将 hFont (CreateFontA) 传递给 CreateWindowEx
Passing hFont (CreateFontA) to CreateWindowEx
已解决!!!
我最初的问题是 CreateFont 函数是否可以与 CreateWindow 函数一起使用。我在文档中找到的所有内容都让我相信它只适用于文本函数。
由于我无法实施所提供的建议并且在我的问题上没有取得任何进展,我采用了一种新方法。我创建了我的测试代码,这样我就可以轻松地在 WM_CREATE: 和 WM_PAINT: 中所做的更改之间切换。现在可以更轻松地破解我在文档、搜索和脑海中突然出现的内容。
以下是我的测试代码。添加和删除 styleSelection 的评论让我 select 我正在做的事情。
全局:HFONT hFont;
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
HDC hdc;
string styleSelection = "WM_CREATE";
//styleSelection = "WM_PAINT";
switch(uMsg) {
case WM_CLOSE: {
DeleteObject(hFont);
DestroyWindow(hWnd);
break;
}
case WM_COMMAND: {
DeleteObject(hFont);
PostQuitMessage(0);
break;
}
case WM_CREATE: {
HINSTANCE hIns = ((LPCREATESTRUCT)lParam)->hInstance;
if((styleSelection == "WM_CREATE") && (hFont = CreateFontA(18, 0, 0, 0, FW_DONTCARE, 1, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, TEXT("DONTCARE")))) {
int textHStart = 20; int textLineSpace = 16;
vector < int > textVStart = { 20,60,100,120,160 };
vector < string > newStrings;
newStrings = getDynamicData(); // Get the strings for output
for(int i = 0; i < newStrings.size(); i++) {
CreateWindowEx(NULL, TEXT("Static"), newStrings[i].c_str(), WS_CHILD | WS_VISIBLE, textHStart, textVStart[i], newStrings[i].length() * 10, textLineSpace, hWnd, (HMENU)IDC_USER_LABEL, hIns, NULL);
}
}
HWND hButton = CreateWindowA(_T("button"), _T("Exit"), WS_CHILD | WS_VISIBLE, 385, 250, 60, 25, hWnd, (HMENU)IDC_BUTTON, hIns, 0);
return 0;
}
case WM_DESTROY: {
DeleteObject(hFont);
PostQuitMessage(0);
break;
}
case WM_CTLCOLORSTATIC: {
HDC hEdit = (HDC)wParam;
SetTextColor(hEdit, RGB(0, 0, 0));
//SetBkColor(hEdit, RGB(0xFF, 0x00, 0x00));
SetBkMode(hEdit, TRANSPARENT);
return (INT_PTR)GetStockObject(HOLLOW_BRUSH);
}
case WM_PAINT: {
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
if((styleSelection == "WM_PAINT") && (hFont = CreateFontA(18, 0, 0, 0, FW_DONTCARE, 1, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, TEXT("DONTCARE")))) {
HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
HDC hEdit = (HDC)wParam;
SetTextColor(hdc, RGB(0, 0, 0));
//SetBkColor(hdc, RGB(0xFF, 0x00, 0x00));
SetBkMode(hdc, TRANSPARENT);
int index = 7; // Vertical spaces and number of lines for the array
const char* cpaText[7] = { "Hello,","", "What I want to do", "is to format this text." };
for(int iLoopCounter = 0; cpaText[iLoopCounter] != 0; iLoopCounter++, index += 20) {
TextOutA(hdc, 5, index, cpaText[iLoopCounter], strlen(cpaText[iLoopCounter]));
}
SelectObject(hdc, hOldFont);
}
EndPaint(hWnd, &ps);
break;
}
default: {
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
break;
}
}
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
}
////---- this is the data to be printed.
vector < string > getDynamicData() {
vector < string > retvec;
retvec.push_back("This is a test.");
retvec.push_back("I am trying to change the text");
return retvec;
}
我最终想出的解决方案在答案部分。
您不应在 WM_PAINT
处理程序期间调用 CreateWindow
。
相反,您需要做的是将您创建的字体保存在 WM_CREATE
处理程序中,然后在您获得 WM_PAINT
时使用该字体。 GetWindowLongPtr
/SetWindowLongPtr
和 GWLP_USERDATA
是执行此类数据保存的规范方法。
例如:
LRESULT WINAPI MyWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
{
if(-1 == DefWindowProc(hWnd, WM_CREATE, wParam, lParam))
return -1;
HFONT hFont = CreateFont(...);
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)hFont);
}
break;
case WM_DESTROY:
DestroyObject((HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA));
return DefWindowProc(hWnd, WM_DESTROY, wParam, lParam);
case WM_PAINT:
{
DefWindowProc(hWnd, WM_PAINT, wParam, lParam);
HFONT hFont = (HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA);
...
}
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
也可以在实际创建 window 的任何代码中创建 HFONT
,并将 HFONT
作为 lParam
参数传递给 CreateWindow
然后在处理 WM_CREATE
时按照描述保存它(而不是在处理 WM_CREATE
时实际创建 HFONT
)。
对于文本框,它已完成
HFONT newFont = CreateFont(22, 0, 0, 0,0 , FALSE, FALSE, FALSE, DEFAULT_CHARSET,
OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY,
DEFAULT_PITCH | FF_DECORATIVE, L"Lucida Console");
::PostMessage(hc,WM_SETFONT,(WPARAM)newFont,(LPARAM)0);
你应该在别处创建所有这些
并使用WS_EX_COMPOSITED
将此 ::PostMessage(hc,WM_SETFONT,(WPARAM)newFont,(LPARAM)0);
添加到您的 for
循环中,直到结束。但不是 hc
ofc
我的工作解决方案:
我的一个问题是 WM_PAINT 中的 TextOut 没有使用动态文本。回顾之前使用 Jonathan Potter 在 Add dynamic text to WM_CREATE in C++ using variables 中的建议解决的问题,我终于意识到同样适用于 TextOut。
在我使用 TextOut 处理动态文本后,下一个选择是保留 WM_CREATE 用于标准字体样式,或者将所有内容迁移到 WM_PAINT。我决定迁移到 WM_PAINT 将是更清洁的解决方案。以下是我最终得到的结果:
全局:HFONT hFont;
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
HDC hdc;
string styleSelection = "standardFont";
styleSelection = "specialFont";
switch(uMsg) {
case WM_CREATE: {
if(-1 == DefWindowProc(hWnd, WM_CREATE, wParam, lParam))
return -1;
hFont = CreateFontA(18, 0, 0, 0, FW_DONTCARE, 1, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, TEXT("DONTCARE"));
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)hFont);
}
break;case WM_CLOSE: {
DeleteObject(hFont);
DestroyWindow(hWnd);
break;
}
case WM_COMMAND: {
DeleteObject(hFont);
PostQuitMessage(0);
break;
}
case WM_DESTROY: {
//DestroyObject((HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA));
DeleteObject((HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA));
return DefWindowProc(hWnd, WM_DESTROY, wParam, lParam);
}
case WM_PAINT: {
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
HDC hEdit = (HDC)wParam;
SetBkMode(hdc, TRANSPARENT);
if(styleSelection == "standardFont") {
SetTextColor(hdc, RGB(0, 0, 0));
int textHStart = 20; int textLineSpace = 16;
vector < int > textVStart = { 20,60,100,120,160 };
vector < string > newStrings;
newStrings = getDynamicData(); // Get the strings for output
for(int i = 0; i < newStrings.size(); i++) {
TextOutA(hdc, textHStart, textVStart[i], newStrings[i].c_str(), newStrings[i].size());
}
}
else {
DefWindowProc(hWnd, WM_PAINT, wParam, lParam);
hFont = (HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA);
HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
SetTextColor(hdc, RGB(0xFF, 0x00, 0x00));
int textHStart = 20; int textLineSpace = 16;
vector < int > textVStart = { 20,60,100,120,160 };
vector < string > newStrings;
newStrings = getDynamicData(); // Get the strings for output
for(int i = 0; i < newStrings.size(); i++) {
TextOutA(hdc, textHStart, textVStart[i], newStrings[i].c_str(), newStrings[i].size());
}
SelectObject(hdc, hOldFont);
DeleteObject(hFont);
}
EndPaint(hWnd, &ps);
break;
}
default: {
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
break;
}
以上代码也实现了 SoronelHaetir 的一些建议。我会仔细研究一下 SoronelHaetir 的其他建议
我仍然需要处理可能的内存泄漏问题和其他一些平滑项目,但这适用于我想做的事情。所需要的只是阅读、耐心和足够的坚持,直到我弄明白为止。
已解决!!!
我最初的问题是 CreateFont 函数是否可以与 CreateWindow 函数一起使用。我在文档中找到的所有内容都让我相信它只适用于文本函数。
由于我无法实施所提供的建议并且在我的问题上没有取得任何进展,我采用了一种新方法。我创建了我的测试代码,这样我就可以轻松地在 WM_CREATE: 和 WM_PAINT: 中所做的更改之间切换。现在可以更轻松地破解我在文档、搜索和脑海中突然出现的内容。
以下是我的测试代码。添加和删除 styleSelection 的评论让我 select 我正在做的事情。
全局:HFONT hFont;
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
HDC hdc;
string styleSelection = "WM_CREATE";
//styleSelection = "WM_PAINT";
switch(uMsg) {
case WM_CLOSE: {
DeleteObject(hFont);
DestroyWindow(hWnd);
break;
}
case WM_COMMAND: {
DeleteObject(hFont);
PostQuitMessage(0);
break;
}
case WM_CREATE: {
HINSTANCE hIns = ((LPCREATESTRUCT)lParam)->hInstance;
if((styleSelection == "WM_CREATE") && (hFont = CreateFontA(18, 0, 0, 0, FW_DONTCARE, 1, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, TEXT("DONTCARE")))) {
int textHStart = 20; int textLineSpace = 16;
vector < int > textVStart = { 20,60,100,120,160 };
vector < string > newStrings;
newStrings = getDynamicData(); // Get the strings for output
for(int i = 0; i < newStrings.size(); i++) {
CreateWindowEx(NULL, TEXT("Static"), newStrings[i].c_str(), WS_CHILD | WS_VISIBLE, textHStart, textVStart[i], newStrings[i].length() * 10, textLineSpace, hWnd, (HMENU)IDC_USER_LABEL, hIns, NULL);
}
}
HWND hButton = CreateWindowA(_T("button"), _T("Exit"), WS_CHILD | WS_VISIBLE, 385, 250, 60, 25, hWnd, (HMENU)IDC_BUTTON, hIns, 0);
return 0;
}
case WM_DESTROY: {
DeleteObject(hFont);
PostQuitMessage(0);
break;
}
case WM_CTLCOLORSTATIC: {
HDC hEdit = (HDC)wParam;
SetTextColor(hEdit, RGB(0, 0, 0));
//SetBkColor(hEdit, RGB(0xFF, 0x00, 0x00));
SetBkMode(hEdit, TRANSPARENT);
return (INT_PTR)GetStockObject(HOLLOW_BRUSH);
}
case WM_PAINT: {
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
if((styleSelection == "WM_PAINT") && (hFont = CreateFontA(18, 0, 0, 0, FW_DONTCARE, 1, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, TEXT("DONTCARE")))) {
HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
HDC hEdit = (HDC)wParam;
SetTextColor(hdc, RGB(0, 0, 0));
//SetBkColor(hdc, RGB(0xFF, 0x00, 0x00));
SetBkMode(hdc, TRANSPARENT);
int index = 7; // Vertical spaces and number of lines for the array
const char* cpaText[7] = { "Hello,","", "What I want to do", "is to format this text." };
for(int iLoopCounter = 0; cpaText[iLoopCounter] != 0; iLoopCounter++, index += 20) {
TextOutA(hdc, 5, index, cpaText[iLoopCounter], strlen(cpaText[iLoopCounter]));
}
SelectObject(hdc, hOldFont);
}
EndPaint(hWnd, &ps);
break;
}
default: {
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
break;
}
}
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
}
////---- this is the data to be printed.
vector < string > getDynamicData() {
vector < string > retvec;
retvec.push_back("This is a test.");
retvec.push_back("I am trying to change the text");
return retvec;
}
我最终想出的解决方案在答案部分。
您不应在 WM_PAINT
处理程序期间调用 CreateWindow
。
相反,您需要做的是将您创建的字体保存在 WM_CREATE
处理程序中,然后在您获得 WM_PAINT
时使用该字体。 GetWindowLongPtr
/SetWindowLongPtr
和 GWLP_USERDATA
是执行此类数据保存的规范方法。
例如:
LRESULT WINAPI MyWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
{
if(-1 == DefWindowProc(hWnd, WM_CREATE, wParam, lParam))
return -1;
HFONT hFont = CreateFont(...);
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)hFont);
}
break;
case WM_DESTROY:
DestroyObject((HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA));
return DefWindowProc(hWnd, WM_DESTROY, wParam, lParam);
case WM_PAINT:
{
DefWindowProc(hWnd, WM_PAINT, wParam, lParam);
HFONT hFont = (HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA);
...
}
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
也可以在实际创建 window 的任何代码中创建 HFONT
,并将 HFONT
作为 lParam
参数传递给 CreateWindow
然后在处理 WM_CREATE
时按照描述保存它(而不是在处理 WM_CREATE
时实际创建 HFONT
)。
对于文本框,它已完成
HFONT newFont = CreateFont(22, 0, 0, 0,0 , FALSE, FALSE, FALSE, DEFAULT_CHARSET,
OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY,
DEFAULT_PITCH | FF_DECORATIVE, L"Lucida Console");
::PostMessage(hc,WM_SETFONT,(WPARAM)newFont,(LPARAM)0);
你应该在别处创建所有这些
并使用WS_EX_COMPOSITED
将此 ::PostMessage(hc,WM_SETFONT,(WPARAM)newFont,(LPARAM)0);
添加到您的 for
循环中,直到结束。但不是 hc
ofc
我的工作解决方案:
我的一个问题是 WM_PAINT 中的 TextOut 没有使用动态文本。回顾之前使用 Jonathan Potter 在 Add dynamic text to WM_CREATE in C++ using variables 中的建议解决的问题,我终于意识到同样适用于 TextOut。
在我使用 TextOut 处理动态文本后,下一个选择是保留 WM_CREATE 用于标准字体样式,或者将所有内容迁移到 WM_PAINT。我决定迁移到 WM_PAINT 将是更清洁的解决方案。以下是我最终得到的结果:
全局:HFONT hFont;
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
HDC hdc;
string styleSelection = "standardFont";
styleSelection = "specialFont";
switch(uMsg) {
case WM_CREATE: {
if(-1 == DefWindowProc(hWnd, WM_CREATE, wParam, lParam))
return -1;
hFont = CreateFontA(18, 0, 0, 0, FW_DONTCARE, 1, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, TEXT("DONTCARE"));
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)hFont);
}
break;case WM_CLOSE: {
DeleteObject(hFont);
DestroyWindow(hWnd);
break;
}
case WM_COMMAND: {
DeleteObject(hFont);
PostQuitMessage(0);
break;
}
case WM_DESTROY: {
//DestroyObject((HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA));
DeleteObject((HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA));
return DefWindowProc(hWnd, WM_DESTROY, wParam, lParam);
}
case WM_PAINT: {
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
HDC hEdit = (HDC)wParam;
SetBkMode(hdc, TRANSPARENT);
if(styleSelection == "standardFont") {
SetTextColor(hdc, RGB(0, 0, 0));
int textHStart = 20; int textLineSpace = 16;
vector < int > textVStart = { 20,60,100,120,160 };
vector < string > newStrings;
newStrings = getDynamicData(); // Get the strings for output
for(int i = 0; i < newStrings.size(); i++) {
TextOutA(hdc, textHStart, textVStart[i], newStrings[i].c_str(), newStrings[i].size());
}
}
else {
DefWindowProc(hWnd, WM_PAINT, wParam, lParam);
hFont = (HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA);
HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
SetTextColor(hdc, RGB(0xFF, 0x00, 0x00));
int textHStart = 20; int textLineSpace = 16;
vector < int > textVStart = { 20,60,100,120,160 };
vector < string > newStrings;
newStrings = getDynamicData(); // Get the strings for output
for(int i = 0; i < newStrings.size(); i++) {
TextOutA(hdc, textHStart, textVStart[i], newStrings[i].c_str(), newStrings[i].size());
}
SelectObject(hdc, hOldFont);
DeleteObject(hFont);
}
EndPaint(hWnd, &ps);
break;
}
default: {
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
break;
}
以上代码也实现了 SoronelHaetir 的一些建议。我会仔细研究一下 SoronelHaetir 的其他建议 我仍然需要处理可能的内存泄漏问题和其他一些平滑项目,但这适用于我想做的事情。所需要的只是阅读、耐心和足够的坚持,直到我弄明白为止。