Поделиться через


Использование распространенных диалоговых окон

В этом разделе рассматриваются задачи, которые вызывают общие диалоговые окна:

Выбор цвета

В этом разделе описывается пример кода, отображающий диалоговое окно "Цвет ", чтобы пользователь смог выбрать цвет. Пример кода сначала инициализирует структуру CHOOSECOLOR , а затем вызывает функцию ChooseColor для отображения диалогового окна. Если функция возвращает значение TRUE, указывающее, что пользователь выбрал цвет, пример кода использует выбранный цвет для создания новой сплошной кисти.

В этом примере используется структура CHOOSECOLOR для инициализации диалогового окна следующим образом:

  • Инициализирует элемент lpCustColors указателем на статический массив значений. Цвета в массиве изначально черные, но статический массив сохраняет настраиваемые цвета, созданные пользователем для последующих вызовов ChooseColor .
  • Задает флаг CC_RGBINIT и инициализирует элемент rgbResult , чтобы указать цвет, который изначально выбран при открытии диалогового окна. Если не указано, начальный выбор является черным. В примере используется статическая переменная rgbCurrent для сохранения выбранного значения между вызовами ChooseColor.
  • Задает флаг CC_FULLOPEN , чтобы всегда отображалось расширение настраиваемых цветов диалогового окна.
CHOOSECOLOR cc;                 // common dialog box structure 
static COLORREF acrCustClr[16]; // array of custom colors 
HWND hwnd;                      // owner window
HBRUSH hbrush;                  // brush handle
static DWORD rgbCurrent;        // initial color selection

// Initialize CHOOSECOLOR 
ZeroMemory(&cc, sizeof(cc));
cc.lStructSize = sizeof(cc);
cc.hwndOwner = hwnd;
cc.lpCustColors = (LPDWORD) acrCustClr;
cc.rgbResult = rgbCurrent;
cc.Flags = CC_FULLOPEN | CC_RGBINIT;
 
if (ChooseColor(&cc)==TRUE) 
{
    hbrush = CreateSolidBrush(cc.rgbResult);
    rgbCurrent = cc.rgbResult; 
}

Выбор шрифта

В этом разделе описывается пример кода, отображающего диалоговое окно "Шрифт ", чтобы пользователь смог выбрать атрибуты шрифта. Пример кода сначала инициализирует структуру CHOOSEFONT , а затем вызывает функцию ChooseFont для отображения диалогового окна.

В этом примере устанавливается флаг CF_SCREENFONTS для указания того, что диалоговое окно должно отображать только экранные шрифты. Он задает флаг CF_EFFECTS для отображения элементов управления, позволяющих пользователю выбирать параметры зачеркивания, подчеркивания и цвета.

Если SelectFont возвращает значение TRUE, указывающее, что пользователь нажимал кнопку "ОК ", структура SELECTFONT содержит сведения, описывающие атрибуты шрифта и шрифта, выбранные пользователем, включая элементы структуры LOGFONT , на которые указывает элемент lpLogFont . Элемент rgbColors содержит выбранный цвет текста. В примере кода эти сведения используются для задания цвета шрифта и текста для контекста устройства, связанного с окном владельца.

HWND hwnd;                // owner window
HDC hdc;                  // display device context of owner window

CHOOSEFONT cf;            // common dialog box structure
static LOGFONT lf;        // logical font structure
static DWORD rgbCurrent;  // current text color
HFONT hfont, hfontPrev;
DWORD rgbPrev;

// Initialize CHOOSEFONT
ZeroMemory(&cf, sizeof(cf));
cf.lStructSize = sizeof (cf);
cf.hwndOwner = hwnd;
cf.lpLogFont = &lf;
cf.rgbColors = rgbCurrent;
cf.Flags = CF_SCREENFONTS | CF_EFFECTS;

if (ChooseFont(&cf)==TRUE)
{
    hfont = CreateFontIndirect(cf.lpLogFont);
    hfontPrev = SelectObject(hdc, hfont);
    rgbCurrent= cf.rgbColors;
    rgbPrev = SetTextColor(hdc, rgbCurrent);
 .
 .
 .
}

Открытие файла

Примечание.

Начиная с Windows Vista, диалоговое окно Общий файл было заменено на диалоговое окно Общего элемента для открытия файла. Рекомендуется использовать API общих диалоговых окон вместо API общих диалоговых окон. Дополнительные сведения см. в диалоговом окне общего элемента.

В этом разделе описывается пример кода, отображающий диалоговое окно "Открыть ", чтобы пользователь смог указать диск, каталог и имя открываемого файла. Пример кода сначала инициализирует структуру OPENFILENAME , а затем вызывает функцию GetOpenFileName для отображения диалогового окна.

В этом примере элемент lpstrFilter — это указатель на буфер, указывающий два фильтра имени файла, которые пользователь может выбрать, чтобы ограничить отображаемые имена файлов. Буфер содержит массив строк с двойным нулевым символом, в котором каждая пара строк задает фильтр. Член nFilterIndex указывает, что первый шаблон используется при создании диалогового окна.

В этом примере задаются флаги OFN_PATHMUSTEXIST и OFN_FILEMUSTEXIST в элементе Flags . Эти флаги вызывают проверку диалогового окна перед возвратом пути и имени файла, указанного пользователем.

Функция GetOpenFileName возвращает значение TRUE , если пользователь нажимает кнопку "ОК ", а указанный путь и имя файла существуют. В этом случае буфер, на который указывает элемент lpstrFile , содержит путь и имя файла. Пример кода использует эти сведения в вызове функции для открытия файла.

Хотя этот пример не задает флаг OFN_EXPLORER , он по-прежнему отображает диалоговое окно "Открыть в стиле обозревателя по умолчанию". Однако если вы хотите предоставить процедуру перехватчика или пользовательский шаблон, и вы хотите пользовательский интерфейс Обозревателя, необходимо задать флаг OFN_EXPLORER .

Примечание.

На языке программирования C строка, заключенная в кавычки, завершается значением NULL.

 

OPENFILENAME ofn;       // common dialog box structure
char szFile[260];       // buffer for file name
HWND hwnd;              // owner window
HANDLE hf;              // file handle

// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
// use the contents of szFile to initialize itself.
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = "All\0*.*\0Text\0*.TXT\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

// Display the Open dialog box. 

if (GetOpenFileName(&ofn)==TRUE) 
    hf = CreateFile(ofn.lpstrFile, 
                    GENERIC_READ,
                    0,
                    (LPSECURITY_ATTRIBUTES) NULL,
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL,
                    (HANDLE) NULL);

Отображение диалогового окна "Печать"

В этом разделе описывается пример кода, отображающий диалоговое окно "Печать ", чтобы пользователь смог выбрать параметры печати документа. Пример кода сначала инициализирует структуру PRINTDLG , а затем вызывает функцию PrintDlg для отображения диалогового окна.

В этом примере задается флаг PD_RETURNDC в элементе Flags структуры PRINTDLG . Это приводит к тому, что PrintDlg возвращает дескриптор контекста устройства выбранному принтеру в элементе hDC . Вы можете использовать ручку для вывода данных на принтере.

При входе пример кода задает для элементов hDevMode и hDevNamesзначение NULL. Если функция возвращает TRUE, эти члены возвращают дескрипторы к структурам DEVNAMES, содержащим данные, введенные пользователем, и сведения о принтере. Эти сведения можно использовать для подготовки выходных данных для отправки на выбранный принтер.

PRINTDLG pd;
HWND hwnd;

// Initialize PRINTDLG
ZeroMemory(&pd, sizeof(pd));
pd.lStructSize = sizeof(pd);
pd.hwndOwner   = hwnd;
pd.hDevMode    = NULL;     // Don't forget to free or store hDevMode.
pd.hDevNames   = NULL;     // Don't forget to free or store hDevNames.
pd.Flags       = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC; 
pd.nCopies     = 1;
pd.nFromPage   = 0xFFFF; 
pd.nToPage     = 0xFFFF; 
pd.nMinPage    = 1; 
pd.nMaxPage    = 0xFFFF; 

if (PrintDlg(&pd)==TRUE) 
{
    // GDI calls to render output. 

    // Delete DC when done.
    DeleteDC(pd.hDC);
}

Использование листа свойств печати

В этом разделе описывается пример кода, отображающий лист свойств Print , чтобы пользователь смог выбрать параметры печати документа. Пример кода сначала инициализирует структуру PRINTDLGEX , а затем вызывает функцию PrintDlgEx для отображения листа свойств.

Пример кода задает флаг PD_RETURNDC в элементе Flags структуры PRINTDLG . Это приводит к тому, что функция PrintDlgEx возвращает дескриптор контекста устройства выбранному принтеру в элементе hDC .

При входе пример кода задает для элементов hDevMode и hDevNamesзначение NULL. Если функция возвращает S_OK, эти члены возвращают дескрипторы к структурам DEVNAMES, содержащим входные данные пользователя и информацию о принтере. Эти сведения можно использовать для подготовки выходных данных для отправки на выбранный принтер.

После завершения операции печати пример кода освобождает буферы DEVMODE, DEVNAMES и PRINTPAGERANGE и вызывает функцию DeleteDC для удаления контекста устройства.

// hWnd is the window that owns the property sheet.
HRESULT DisplayPrintPropertySheet(HWND hWnd)
{
    HRESULT hResult;
    PRINTDLGEX pdx = {0};
    LPPRINTPAGERANGE pPageRanges = NULL;

    // Allocate an array of PRINTPAGERANGE structures.
    pPageRanges = (LPPRINTPAGERANGE) GlobalAlloc(GPTR, 10 * sizeof(PRINTPAGERANGE));
    if (!pPageRanges)
        return E_OUTOFMEMORY;

    //  Initialize the PRINTDLGEX structure.
    pdx.lStructSize = sizeof(PRINTDLGEX);
    pdx.hwndOwner = hWnd;
    pdx.hDevMode = NULL;
    pdx.hDevNames = NULL;
    pdx.hDC = NULL;
    pdx.Flags = PD_RETURNDC | PD_COLLATE;
    pdx.Flags2 = 0;
    pdx.ExclusionFlags = 0;
    pdx.nPageRanges = 0;
    pdx.nMaxPageRanges = 10;
    pdx.lpPageRanges = pPageRanges;
    pdx.nMinPage = 1;
    pdx.nMaxPage = 1000;
    pdx.nCopies = 1;
    pdx.hInstance = 0;
    pdx.lpPrintTemplateName = NULL;
    pdx.lpCallback = NULL;
    pdx.nPropertyPages = 0;
    pdx.lphPropertyPages = NULL;
    pdx.nStartPage = START_PAGE_GENERAL;
    pdx.dwResultAction = 0;
    
    //  Invoke the Print property sheet.
    
    hResult = PrintDlgEx(&pdx);

    if ((hResult == S_OK) && pdx.dwResultAction == PD_RESULT_PRINT) 
    {
        // User clicked the Print button, so use the DC and other information returned in the 
        // PRINTDLGEX structure to print the document.
    }

    if (pdx.hDevMode != NULL) 
        GlobalFree(pdx.hDevMode); 
    if (pdx.hDevNames != NULL) 
        GlobalFree(pdx.hDevNames); 
    if (pdx.lpPageRanges != NULL)
        GlobalFree(pPageRanges);

    if (pdx.hDC != NULL) 
        DeleteDC(pdx.hDC);

    return hResult;
}

Настройка печатной страницы

В этом разделе описывается пример кода, отображающий диалоговое окно "Настройка страницы ", чтобы пользователь смог выбрать атрибуты печатной страницы, например тип бумаги, источник бумаги, ориентация страницы и поля страницы. Пример кода сначала инициализирует структуру PAGESETUPDLG , а затем вызывает функцию PageSetupDlg для отображения диалогового окна.

В этом примере устанавливается флаг PSD_MARGINS в элементе Flags и используется элемент rtMargin для указания начальных значений полей. Он задает флаг PSD_INTHOUSANDTHSOFINCHES , чтобы убедиться, что диалоговое окно выражает размеры полей в тысячах дюйма.

При входе пример кода задает для элементов hDevMode и hDevNamesзначение NULL. Если функция возвращает TRUE, она использует эти элементы для возвращения дескрипторов структур DEVNAMES, содержащих входные данные пользователя и сведения о принтере. Эти сведения можно использовать для подготовки выходных данных для отправки на выбранный принтер.

В следующем примере также используется процедура перехватчика PagePaintHook для кастомизации прорисовки содержимого примера страницы.

PAGESETUPDLG psd;    // common dialog box structure
HWND hwnd;           // owner window

// Initialize PAGESETUPDLG
ZeroMemory(&psd, sizeof(psd));
psd.lStructSize = sizeof(psd);
psd.hwndOwner   = hwnd;
psd.hDevMode    = NULL; // Don't forget to free or store hDevMode.
psd.hDevNames   = NULL; // Don't forget to free or store hDevNames.
psd.Flags       = PSD_INTHOUSANDTHSOFINCHES | PSD_MARGINS | 
                  PSD_ENABLEPAGEPAINTHOOK; 
psd.rtMargin.top = 1000;
psd.rtMargin.left = 1250;
psd.rtMargin.right = 1250;
psd.rtMargin.bottom = 1000;
psd.lpfnPagePaintHook = PaintHook;

if (PageSetupDlg(&psd)==TRUE)
{
    // check paper size and margin values here.
}

В следующем примере показан пример процедуры перехватчика PagePaintHook , которая рисует прямоугольник поля в области страницы:

BOOL CALLBACK PaintHook(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    LPRECT lprc; 
    COLORREF crMargRect; 
    HDC hdc, hdcOld; 
 
    switch (uMsg) 
    { 
        // Draw the margin rectangle. 
        case WM_PSD_MARGINRECT: 
            hdc = (HDC) wParam; 
            lprc = (LPRECT) lParam; 
 
            // Get the system highlight color. 
            crMargRect = GetSysColor(COLOR_HIGHLIGHT); 
 
            // Create a dash-dot pen of the system highlight color and 
            // select it into the DC of the sample page. 
            hdcOld = SelectObject(hdc, CreatePen(PS_DASHDOT, .5, crMargRect)); 
 
            // Draw the margin rectangle. 
            Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom); 
 
            // Restore the previous pen to the DC. 
            SelectObject(hdc, hdcOld); 
            return TRUE; 
 
        default: 
            return FALSE; 
    } 
    return TRUE; 
}

Поиск текста

В этом разделе описывается пример кода, который отображает диалоговое окно "Поиск " и управляет ими, чтобы пользователь смог указать параметры операции поиска. Диалоговое окно отправляет сообщения в процедуру окна, чтобы вы могли выполнить операцию поиска.

Код для отображения диалогового окна "Замена " и управления ими аналогичен, за исключением того, что для отображения диалогового окна используется функция ReplaceText . Диалоговое окно "Замена" также отправляет сообщения в ответ на щелчки пользователя по кнопкам "Заменить" и "Заменить все".

Чтобы использовать диалоговое окно "Найти или заменить ", необходимо выполнить три отдельных задачи:

  1. Получите идентификатор сообщения для зарегистрированного сообщения FINDMSGSTRING .
  2. Отображение диалогового окна.
  3. Обработка сообщений FINDMSGSTRING при открытии диалогового окна.

При инициализации приложения вызовите функцию RegisterWindowMessage , чтобы получить идентификатор сообщения для зарегистрированного сообщения FINDMSGSTRING .

UINT uFindReplaceMsg;  // message identifier for FINDMSGSTRING 

uFindReplaceMsg = RegisterWindowMessage(FINDMSGSTRING);

Чтобы отобразить диалоговое окно "Поиск ", сначала инициализируйте структуру FINDREPLACE и вызовите функцию FindText . Обратите внимание, что структура FINDREPLACE и буфер строки поиска должны быть глобальной или статической переменной, чтобы она не выходила из области до закрытия диалогового окна. Необходимо задать элемент hwndOwner , чтобы указать окно, которое получает зарегистрированные сообщения. После того как вы создадите диалоговое окно, вы можете переместить его или управлять им с помощью возвращаемого дескриптора.

FINDREPLACE fr;       // common dialog box structure
HWND hwnd;            // owner window
CHAR szFindWhat[80];  // buffer receiving string
HWND hdlg = NULL;     // handle to Find dialog box

// Initialize FINDREPLACE
ZeroMemory(&fr, sizeof(fr));
fr.lStructSize = sizeof(fr);
fr.hwndOwner = hwnd;
fr.lpstrFindWhat = szFindWhat;
fr.wFindWhatLen = 80;
fr.Flags = 0;

hdlg = FindText(&fr);

При открытии диалогового окна основной цикл сообщений должен включать вызов функции IsDialogMessage . Передайте дескриптор окна диалога в качестве параметра в вызове IsDialogMessage. Это гарантирует, что диалоговое окно правильно обрабатывает сообщения клавиатуры.

Чтобы отслеживать сообщения, отправленные из диалогового окна, процедура окна должна проверить зарегистрированное сообщение FINDMSGSTRING и обработать значения, переданные в структуре FINDREPLACE , как показано в следующем примере.

LPFINDREPLACE lpfr;

if (message == uFindReplaceMsg)
{ 
    // Get pointer to FINDREPLACE structure from lParam.
    lpfr = (LPFINDREPLACE)lParam;

    // If the FR_DIALOGTERM flag is set, 
    // invalidate the handle that identifies the dialog box. 
    if (lpfr->Flags & FR_DIALOGTERM)
    { 
        hdlg = NULL; 
        return 0; 
    } 

    // If the FR_FINDNEXT flag is set, 
    // call the application-defined search routine
    // to search for the requested string. 
    if (lpfr->Flags & FR_FINDNEXT) 
    {
        SearchFile(lpfr->lpstrFindWhat,
                   (BOOL) (lpfr->Flags & FR_DOWN), 
                   (BOOL) (lpfr->Flags & FR_MATCHCASE)); 
    }

    return 0; 
}