我正在尝试找出“正确”的方法来设置作为主窗口子窗口的静态文本框的字体。 经过大量谷歌搜索后,我发现许多结果基本上解释了以下内容:
使用 CreateFont 创建字体对象至少有一篇 MSDN 文章讨论了在处理 WM_INITDIALOG
我所做的是在进入消息循环之前发送 WM_SETFONT
消息。 让我惊讶的是,它有效! 我的惊讶源于我的理解,即在消息被处理之前
SendMessage
不会返回(即“直到窗口过程处理完消息。” - DOCS
)。 那么,代码到底是如何进入消息循环的呢?
这是我的代码:
#include <windows.h>
#include <windowsx.h>
HWND hMainWind;
HWND hStartButton;
HWND hStopButton;
HWND hStaticBox;
static HFONT hFont;
static LRESULT CALLBACK MainWinProc(HWND, UINT, WPARAM, LPARAM);
#define START_BUTTON 1001
#define STOP_BUTTON 1002
int WINAPI WinMain( HINSTANCE hMainInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd )
{
MSG Msg = {0};
WNDCLASSEX MainWinClass;
MainWinClass.cbSize = sizeof(WNDCLASSEX);
MainWinClass.style = CS_VREDRAW|CS_HREDRAW;
MainWinClass.lpfnWndProc = MainWinProc;
MainWinClass.cbClsExtra = 0;
MainWinClass.cbWndExtra = 0;
MainWinClass.hInstance = hMainInstance;
MainWinClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
MainWinClass.hCursor = LoadCursor(NULL, IDC_ARROW);
MainWinClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
MainWinClass.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
MainWinClass.lpszMenuName = NULL; /*No menu*/
MainWinClass.lpszClassName = "TwoButtons"; /* class name to register*/
if( !RegisterClassEx( &MainWinClass ) )
{
MessageBox( NULL, "Window Failed to Register!", "ERROR",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hMainWind = CreateWindowEx
(
WS_EX_LEFT,
MainWinClass.lpszClassName,
"TwoButtons",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, /*Default x pos*/
CW_USEDEFAULT, /*Default y pos*/
640, /*Width*/
480, /*Height*/
HWND_DESKTOP,
NULL,
hMainInstance,
NULL
);
hStartButton = CreateWindow
(
"BUTTON",
"START",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
270, /*x pos*/
200, /*y pos*/
100,
50,
hMainWind,
(HMENU)START_BUTTON,
hMainInstance,
NULL
);
hStopButton = CreateWindow
(
"BUTTON",
"STOP",
WS_TABSTOP | WS_VISIBLE | WS_DISABLED | WS_CHILD | BS_PUSHBUTTON,
270,
300,
100,
50,
hMainWind,
(HMENU)STOP_BUTTON,
hMainInstance,
NULL
);
/*create a static text box*/
hStaticBox = CreateWindow
(
"STATIC", /* lpClassName */
"Box", /* lpWindowName */
WS_BORDER|WS_CHILD|WS_VISIBLE, /* dwStyle */
270, /* x */
100, /* y */
100, /* nWidth */
50, /* nHeight */
hMainWind, /* hWndParent */
NULL, /* hMenu */
hMainInstance, /* hInstance */
(LPVOID)1 /* lpParam */
);
hFont = CreateFont
(
24, /* cHeight */
0, /* cWidth use default*/
0, /* cEscapement */
0, /* cOrientation */
FW_NORMAL, /* cWeight */
FALSE, /* bItalic */
FALSE, /* bUnderline */
FALSE, /* bStrikeOut */
DEFAULT_CHARSET, /* iCharSet */
OUT_DEFAULT_PRECIS, /* iOutPrecision */
CLIP_DEFAULT_PRECIS, /* iClipPrecision */
DEFAULT_QUALITY, /* iQuality */
DEFAULT_PITCH, /* iPitchAndFamily */
"Arial" /* pszFacename */
);
/* Make the main window visible on the screen */
ShowWindow(hMainWind, nShowCmd);
UpdateWindow(hMainWind);
/*Set up the font for the static text box*/
SendMessage ( hStaticBox, WM_SETFONT, (WPARAM) hFont, TRUE );
/* Run the message loop. It will run until GetMessage() returns 0 */
while( GetMessage( &Msg, NULL, 0, 0 ) )
{
/* Translate virtual-key messages into character messages */
TranslateMessage( &Msg );
/* Send message to MainWinProc */
DispatchMessage( &Msg );
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return Msg.wParam;
}
/* This function is called by DispatchMessage() */
static LRESULT CALLBACK MainWinProc( HWND hWind, UINT Message, WPARAM wParam,
LPARAM lParam )
{
switch(Message) /* handle the message */
{
case WM_DESTROY:
DeleteObject(hFont);
PostQuitMessage(0); /* sends a WM_QUIT to the message queue */
break;
case WM_COMMAND:
if( HIWORD( wParam ) == BN_CLICKED ) /*A button was clicked*/
{
switch ( LOWORD(wParam) ) /*Which button?*/
{
case START_BUTTON:
Button_Enable( hStartButton, FALSE );
Button_Enable( hStopButton, TRUE );
SetWindowText( hStaticBox, "START" );
break;
case STOP_BUTTON:
Button_Enable( hStartButton, TRUE );
Button_Enable( hStopButton, FALSE );
SetWindowText( hStaticBox, "STOP" );
break;
}
}
default: /* Pass on messages not handled here */
return DefWindowProc (hWind, Message, wParam, lParam);
}
return 0;
}
在我找到的所有可能的解释中,我缺少的是“何时”发送消息。 我是否在处理其他适当的消息时在 WinProc 中发送它?
static
控件。
至少[一篇 MSDN 文章][1] 讨论了在处理
WM_INITDIALOG
消息时设置字体,但这不是一个对话框。 这只是一个带有静态子文本框的主窗口。
由于您没有创建对话框,因此您可以处理WM_CREATE
。
我所做的是在进入消息循环之前发送
WM_SETFONT
消息。 让我惊讶的是,它有效!
是的,因为您在创建static
控件后发送了它。
我的惊讶来自于我的理解,
SendMessage
在消息被处理之前不会返回(即“直到窗口过程处理了消息。”-[DOCS][2])。 那么,代码到底是如何进入消息循环的呢?
事实并非如此。 根据同一文档:换句话说,
如果指定的窗口是由调用线程创建的,则立即将窗口过程作为子例程调用。
SendMessage()
[在 WM_INITDIALOG 或 WM_CREATE 上] 不起作用。我添加了以下片段:
case WM_INITDIALOG:
case WM_CREATE:
SendMessage ( hStaticBox, WM_SETFONT, (WPARAM) hFont, TRUE );
break;
switch
中的,因为语句,并在消息循环之前注释掉对
WinProc
的调用。这不起作用 - 静态文本框的字体没有更新。SendMessage
那是因为
是在您创建静态控件之前WM_CREATE
发送到您的WndProc
WM_CREATE
是由
CreateWindowEx()
本身发送的。您应该拥有
WndProc
句柄
WM_CREATE
并从那里创建所有子控件,而不是直接在
WinMain()
中。然后您也可以在 WM_SETFONT
内部发送
WM_CREATE
,例如:
...
int WINAPI WinMain( HINSTANCE hMainInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd )
{
...
hMainWind = CreateWindowEx(...);
// get rid of all the subsequent creates here...
ShowWindow(hMainWind, nShowCmd);
UpdateWindow(hMainWind);
...
return Msg.wParam;
}
static LRESULT CALLBACK MainWinProc( HWND hWind, UINT Message, WPARAM wParam,
LPARAM lParam )
{
switch(Message) /* handle the message */
{
case WM_CREATE:
hStartButton = CreateWindow(..., hWind, ...);
hStopButton = CreateWindow(..., hWind, ...);
hStaticBox = CreateWindow(..., hWind, ...);
hFont = CreateFont(...);
SendMessage(hStaticBox, WM_SETFONT, (WPARAM) hFont, TRUE);
break;
case WM_DESTROY:
DeleteObject(hFont);
PostQuitMessage(0); /* sends a WM_QUIT to the message queue */
break;
...
}
...
}