使用一般對話方塊
本節涵蓋叫用常見對話方塊的工作:
選擇色彩
本主題描述顯示 [色彩 ] 對話方塊的範例程式碼,讓使用者可以選取色彩。 範例程式碼會先初始化 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結構會包含描述使用者所選取字型和字型屬性的資訊,包括lpLogFont成員所指向的LOGFONT結構成員。 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成員會指定建立對話方塊時會使用第一個模式。
本範例會設定Flags成員中的OFN_PATHMUSTEXIST和OFN_FILEMUSTEXIST旗標。 這些旗標會導致對話方塊在傳回之前驗證使用者實際存在的路徑和檔案名。
如果使用者按一下 [確定] 按鈕,且指定的路徑和檔案名存在,GetOpenFileName函式會傳回TRUE。 在此情況下, lpstrFile 成員所指向的緩衝區包含路徑和檔案名。 範例程式碼會在對 函式的呼叫中使用這項資訊來開啟檔案。
雖然此範例未設定 OFN_EXPLORER 旗標,但仍會顯示預設的 [總管] 樣式 [ 開啟 ] 對話方塊。 不過,如果您想要提供勾點程式或自訂範本,而且您想要 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 函式來顯示對話方塊。
本範例會在PRINTDLG結構的Flags成員中設定PD_RETURNDC旗標。 這會導致 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 屬性工作表
本主題描述顯示 Print 屬性工作表的範例程式碼,讓使用者可以選取列印檔案的選項。 範例程式碼會先初始化 PRINTDLGEX 結構,然後呼叫 PrintDlgEx 函式來顯示內容表。
範例程式碼會在PRINTDLG結構的Flags成員中設定PD_RETURNDC旗標。 這會導致 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 函式以顯示對話方塊。
本範例會在Flags成員中設定PSD_MARGINS旗標,並使用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;
}
尋找文字
本主題描述顯示和管理 [尋找 ] 對話方塊的範例程式碼,讓使用者可以指定搜尋作業的參數。 對話方塊會將訊息傳送至視窗程式,讓您可以執行搜尋作業。
顯示和管理 Replace 對話方塊的程式碼很類似,不同之處在于它會使用 ReplaceText 函式來顯示對話方塊。 [ 取代] 對話方塊也會傳送訊息,以回應使用者按一下 [ 取代 ] 和 [ 全部取代] 按鈕。
若要使用 [ 尋找 或 取代] 對話方塊,您必須執行三個不同的工作:
- 取得 FINDMSGSTRING 已註冊訊息的訊息識別碼。
- 顯示對話方塊。
- 開啟對話方塊時,處理 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;
}