📄 windlg.html.primary
字号:
<html>
<head>
<title>Dialog Box Applet</title>
<meta name="description" content="Reliable software Win32 Tutorial: Dialog Box Applest">
<meta name="keywords" content="windows, cplusplus, source code, example, tutorial, object oriented, CreateDialog, IsDialogMessage, Win32">
</head>
<body background="../images/grid.gif" bgcolor="white" text="black">
<table cellpadding=10 width="100%">
<tr>
<td width=100 align=center valign=middle>
<a href="../index.htm">
<img src="../images/rsbullet.gif" alt="RS" border=0 width=39 height=39>
<br>Home</a>
<td><font face="arial" color="#009966">
<h1 align=center>Program with a Dialog Box as the Main Window</h1>
</font>
</table>
<p>
<table width="100%">
<tr>
<td width=104> <!-- Left margin -->
<td> <!-- Middle column, there is also the right margin at the end -->
<table cellpadding=10 cellspacing=0 width="100%">
<tr>
<td bgcolor="#ffffff">
<hr>
<font size="+1"><b>The main window</b></font> of a program doesn't have to be a resizable general purpose window. Many small applications work better in a dialog box format. The obvious advantage of such an approach is that you can use a resource editor to arrange all your controls on the surface of the box. This is in fact how the UI of the <a href="../freq.html">Frequency Analyzer</a> was implemented. Since this is a useful technique, I will describe it in some detail. You can also <a href="source/DlgApp.zip">download the source code</a> for a simple application that demonstrates the techniques described here (courtesy Laszlo Radanyi).
<p>First of all, we have to design the dialog box using the resource editor. We assign identifiers to all the controls and to the dialog itself. Here, the dialog resource has the identifier DLG_MAIN. In the <i>WinMain</i> procedure we don't have to register any window class, because Windows has a pre-defined class for dialog boxes. Instead of creating a window, we call <i>CreateDialog</i>, passing it a pointer to our own dialog procedure (explained later).
<p>The message loop is non-standard in that it calls <i>IsDialogMessage</i> for every message. This API not only checks whether a given message is directed at the dialog box, but more importantly, it dispatches it to the dialog procedure. If the message was not for the dialog, we do the standard translation and dispatching.
<p>For convenience, we keep the value of HINSTANCE in a global variable. This is actually a precursor of a more general object--the Application. Here, however, we decided it was too trivial to deserve a class of its own.
<hr>
<pre><font face="courier">
<font color="#009966">HINSTANCE</font> TheInstance = 0;
int <font color="#009966">WINAPI</font> <font color="#cc0066"><b>WinMain</b></font>
(<font color="#009966">HINSTANCE</font> hInst, <font color="#009966">HINSTANCE</font> hPrevInst, char * cmdParam, int cmdShow)
{
TheInstance = hInst;
_set_new_handler (& NewHandler);
<font color="#009966">HWND</font> hDialog = 0;
hDialog = <font color="#000099"><b>CreateDialog</b></font> (hInst, <font color="#000099"><b>MAKEINTRESOURCE</b></font> (DLG_MAIN), 0, DialogProc);
if (!hDialog)
{
char buf [100];
wsprintf (buf, "Error x%x", GetLastError ());
<font color="#000099"><b>MessageBox</b></font> (0, buf, "CreateDialog", <font color="#009966">MB_ICONEXCLAMATION</font> | <font color="#009966">MB_OK</font>);
return 1;
}
MSG msg;
int status;
while ((status = <font color="#000099"><b>GetMessage</b></font> (& msg, 0, 0, 0)) != 0)
{
if (status == -1)
return -1;
if (!<font color="#000099"><b>IsDialogMessage</b></font> (hDialog, & msg))
{
<font color="#000099"><b>TranslateMessage</b></font> ( & msg );
<font color="#000099"><b>DispatchMessage</b></font> ( & msg );
}
}
return msg.wParam;
}
</font></pre>
<hr>
The dialog procedure is just like Windows procedure, except that it returns TRUE when it processes a message and FALSE when it doesn't. There is no need to call the default procedure, because Windows does it for us whenever the dialog procedure returns FALSE (makes you thing why wasn't the same design used in Windows procedure...). The first message the dialog gets is WM_INITDIALOG and the last one is WM_CLOSE. During the processing of these messages we create and destroy the Controller. Other than that, the dialog expects messages from its controls--these are passed as WM_COMMAND. One control that requires special processing is a (horizontal) scrollbar--it sends the WM_HSCROLL message. There are scrollbar controls in the Frequency Analyzer and that's how they are dealt with.
<hr>
<pre><font face="courier">
BOOL CALLBACK <font color="#cc0066"><b>DialogProc</b></font> (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static Controller* control = 0;
switch (message)
{
case <font color="#009966">WM_INITDIALOG</font>:
try
{
control = new Controller (hwnd);
}
catch (WinException e)
{
<font color="#000099"><b>MessageBox</b></font> (0, e.GetMessage (), "Exception", <font color="#009966">MB_ICONEXCLAMATION</font> | <font color="#009966">MB_OK</font>);
}
catch (...)
{
<font color="#000099"><b>MessageBox</b></font> (0, "Unknown", "Exception", <font color="#009966">MB_ICONEXCLAMATION</font> | <font color="#009966">MB_OK</font>);
return -1;
}
return TRUE;
case <font color="#009966">WM_COMMAND</font>:
control->Command(hwnd, LOWORD (wParam), HIWORD (wParam));
return TRUE;
case <font color="#009966">WM_HSCROLL</font>:
control->Scroll (hwnd, LOWORD (wParam), HIWORD (wParam));
return 0;
case <font color="#009966">WM_CLOSE</font>:
delete control;
<font color="#000099"><b>DestroyWindow</b></font> (hwnd);
return TRUE;
}
return FALSE;
}
</font></pre>
<hr>
Let's have a look at the Controller. Notice how every control on the face of the dialog box has a corresponding (embedded) <a href="controls.html">control object</a> inside the Controller. There are edits, combos, radio buttons and scrollbars. There is a special metafile control that draws the frequency scale and two view objects corresponding to two static panes upon which we draw the graphs. Finally we have the <a href="../recorder.html">Painter</a> object that is responsible for the asynchronous repainting of the two panes.
<hr>
<pre><font face="courier">
class <font color="#cc0066"><b>Controller</b></font>
{
public:
Controller(HWND hwnd);
~Controller ();
void Command (HWND hwnd, int id, int code);
void Scroll (HWND hwnd, int cmd, int pos);
void Paint (HWND hwnd);
void ReInit (HWND hwnd);
void Stop (HWND hwnd);
private:
void InitScrollPositions ();
void PaintScale ();
BOOL _isStopped;
int _bitsPerSample;
int _samplesPerSecond;
int _fftPoints;
int _samplesPerBuf;
EditReadOnly _edit;
Combo _comboFreq;
Combo _comboPoints;
RadioButton _radio8;
RadioButton _radio16;
ScrollBarMap _scroll;
StaticEnhMetafileControl _scaleFreq;
ViewWave _viewWave;
ViewFreq _viewFreq;
Painter _display;
};
</font></pre>
<hr>
The constructor of the Controller takes care of the initialization of all the controls by passing them the handle to the dialog box window and the appropriate identifiers. As a matter of cosmethics, we attach our own icon to the dialog--otherwise the system would use the standard Windows icon.
<hr>
<pre><font face="courier">
<font color="#cc0066"><b>Controller::Controller</b></font> (HWND hwnd)
:_isStopped (TRUE),
_bitsPerSample (16),
_samplesPerSecond (SAMPLES_SEC),
_fftPoints (FFT_POINTS * 4),
_samplesPerBuf (FFT_POINTS * 2),
_radio8 (hwnd, IDC_8_BITS),
_radio16 (hwnd, IDC_16_BITS),
_scroll (hwnd, IDC_SCROLLBAR),
_edit (hwnd, IDC_EDIT),
_comboFreq (hwnd, IDC_SAMPLING),
_comboPoints (hwnd, IDC_POINTS),
_viewWave (hwnd, IDS_WAVE_PANE, FFT_POINTS * 8),
_viewFreq (hwnd, IDS_FREQ_PANE),
_scaleFreq (hwnd, IDC_FREQ_SCALE),
_display (hwnd,
_viewWave,
_viewFreq,
_samplesPerBuf,
_samplesPerSecond,
_fftPoints)
{
// Attach icon to main dialog
HICON hIcon = <font color="#000099"><b>LoadIcon</b></font> (TheInstance, <font color="#000099"><b>MAKEINTRESOURCE</b></font> (ICO_FFT));
<font color="#000099"><b>SendMessage</b></font> (hwnd, <font color="#009966">WM_SETICON</font>, WPARAM (<font color="#009966">ICON_SMALL</font>), LPARAM (hIcon));
// Other initializations...
}
</font></pre>
<hr>
Using a dialog box as the main window is a very handy and simple technique, especially for applications that display a panel-like interface. By the way, the Battleship app (see the <a href="../index.htm">home page</a>) uses the same trick. You may now continue to the next tutorial on the use of <a href="dialog.html">dialog boxes</a> in Windows applications.
<hr>
</table>
</table>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -