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

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

Выбор цвета

В этом разделе описывается пример кода, в котором отображается диалоговое окно Цвет , позволяющее пользователю выбрать цвет. Пример кода сначала инициализирует структуру 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 для отображения элементов управления, позволяющих пользователю выбирать параметры зачеркивать, подчеркивание и цвет.

Если функция ChooseFont возвращает значение TRUE, указывающее, что пользователь нажал кнопку ОК , структура CHOOSEFONT содержит сведения, описывающие шрифт и атрибуты шрифта, выбранные пользователем, включая элементы структуры 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 является указателем на буфер, указывающий два фильтра имен файлов, которые пользователь может выбрать для ограничения отображаемых имен файлов. Буфер содержит массив строк с двойным завершением NULL, в котором каждая пара строк задает фильтр. Элемент 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);
}

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

В этом разделе описывается пример кода, отображающий страницу свойств Печать , чтобы пользователь смог выбрать параметры печати документа. Пример кода сначала инициализирует структуру 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);

Когда диалоговое окно открыто, цикл сообщений main должен включать вызов функции 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; 
}