gpt4 book ai didi

c++ - winapi C++ 处理焦点

转载 作者:太空狗 更新时间:2023-10-29 23:07:13 25 4
gpt4 key购买 nike

我正在开发一个 C++ winapi 应用程序,我正在努力让 SetFocus() 为我工作。我使用 WS_OVERLAPPEDWINDOW | 创建主窗口WS_VISIBLE 然后在其中我使用 WS_CHILD | 创建它的子项(几个按钮和我自己版本的编辑控件的开头) WS_VISIBLE,除了焦点问题外都工作正常。

在我的搜索中,我一直在努力寻找关于应该如何处理 Focus 的很多信息。当所有窗口都创建后,它们分别收到 WM_SETFOCUS 消息,我通过创建插入符号在我的编辑控件中处理此消息,但是 children 似乎从未收到 WM_KILLFOCUS 消息所以插入符永远不会被破坏。

这就是我的问题所在:我希望主父窗口最初有焦点,并且在我的编辑控件中没有插入符,然后当子编辑控件被单击时它有焦点,然后当单击主窗口,然后应该再次获得焦点,依此类推。

所以我最初的想法是在处理 WM_CREATE 消息时使用 SetFocus() 将焦点设置到主窗口,但这似乎不起作用: child 不' 收到 WM_KILLFOCUS 消息。

我的下一个想法是,也许 parent 必须处理将 WM_KILLFOCUS 传递给适当的 child ,所以我写了一个方法来为我做这件事,但 children 仍然没有收到 WM_KILLFOCUS 消息。

所以我最好的猜测是我没有在我的 WndProc 中正确处理消息。

我已经创建了自己的 Window 类并通过以下 WndProc 将消息分发到适当的类:

LRESULT CALLBACK CBaseWindow::stWinMsgHandler(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
CBaseWindow* pWnd;

if (uMsg == WM_NCCREATE)
{
SetWindowLong(hwnd, GWL_USERDATA, (long)((LPCREATESTRUCT(lParam))->lpCreateParams));
}

pWnd = GetObjectFromWindow(hwnd);

if (pWnd)
return pWnd->WinMsgHandler(hwnd, uMsg, wParam, lParam);
else
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

然后每个类都有自己的 WndProc,我在其中处理传入的消息。

那么有人对我有什么想法吗?

如果我这样做是完全错误的方式,或者如果我没有遵循最佳实践,请这样说,我这样做是为了学习,所以赶快离开吧。

[更新]

好的,这里是一些代码来演示问题:

main.cpp

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "MainWnd.h"

int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MainWnd wnd(hInstance);

MSG msg;
while(GetMessage(&msg, NULL, 0, 0 ) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

基本窗口.cpp

 #include "BaseWindow.h"

//...

LRESULT CALLBACK CBaseWindow::stWinMsgHandler(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
CBaseWindow* pWnd;

if (uMsg == WM_NCCREATE)
{
SetWindowLong(hwnd,
GWL_USERDATA,
(long)((LPCREATESTRUCT(lParam))->lpCreateParams));
}

pWnd = GetObjectFromWindow(hwnd);

if (pWnd)
return pWnd->WinMsgHandler(hwnd, uMsg, wParam, lParam);
else
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

BOOL CBaseWindow::Create(DWORD dwStyles, RECT* rect)
{
m_hwnd = CreateWindow(
szClassName,
szWindowTitle,
dwStyles,
rect->left,
rect->top,
rect->right - rect->left,
rect->bottom - rect->top,
NULL,
NULL,
hInstance,
(void *)this);

return (m_hwnd != NULL);
}

主窗口.cpp

#include "MainWnd.h"
#define WIDTH 400
#define HEIGHT 400

MainWnd::MainWnd(HINSTANCE hInst): CBaseWindow(hInst), hInstance(hInst)
{
SetWindowTitle(_T("Main Window"));

WNDCLASSEX wcx;
FillWindowClass(&wcx);

if(RegisterWindow(&wcx))
{
RECT rc;
BuildRect(&rc);

if(Create(WS_OVERLAPPEDWINDOW | WS_VISIBLE, &rc))
{
customTextBox = new CustomTextBox(hInst, m_hwnd);
}
}
}

void MainWnd::FillWindowClass(WNDCLASSEX *wcx)
{
wcx->cbSize = sizeof(WNDCLASSEX);
wcx->style = CS_HREDRAW | CS_VREDRAW | CS_DROPSHADOW;
wcx->lpfnWndProc = CBaseWindow::stWinMsgHandler;
wcx->cbClsExtra = 0;
wcx->cbWndExtra = 0;
wcx->hInstance = hInstance;
wcx->hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx->hCursor = LoadCursor(NULL, IDC_ARROW);
wcx->hbrBackground = CreateSolidBrush(RGB(255,255,255));
wcx->lpszMenuName = NULL;
wcx->lpszClassName = _T("MainWindow");
wcx->hIconSm = LoadIcon(NULL, IDI_APPLICATION);
}

LRESULT CALLBACK MainWnd::WinMsgHandler(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
delete customTextBox;
PostQuitMessage(0);
break;
case WM_LBUTTONUP:
SetFocus(hwnd);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}

自定义文本框.cpp

 #include "CustomTextBox.h"

CustomTextBox::CustomTextBox(
HINSTANCE hInst,
HWND hParent): CBaseWindow(hInst),
hParent(hParent),
{
WNDCLASSEX wcx;
CreateWndClassEX(wcx);
if(RegisterWindow(&wcx))
{
RECT clientRect;
CreateClientRect(clientRect);
CreateChild(WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP, &clientRect, hParent);
}
}

void CustomTextBox::CreateWndClassEX(WNDCLASSEX& wcx)
{
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = CBaseWindow::stWinMsgHandler;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = hInstance;
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = CreateSolidBrush(RGB(255,255,255));
wcx.lpszMenuName = NULL;
wcx.lpszClassName = _T("Edit Control");
wcx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
}

LRESULT CALLBACK CustomTextBox::WinMsgHandler(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
/* Handling the caret */
case WM_SETFOCUS:
CreateCaret(hwnd, NULL, 0, nWindowY);
SetCaretPos(GetEndOfLinePoint(), nCaretPosY * nCharY);
ShowCaret(hwnd);
return 0;
case WM_MOUSEACTIVATE:
SetFocus(hwnd);
return MA_ACTIVATE;
case WM_KILLFOCUS:
DestroyCaret();
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}

发现

在编写这段代码时,我遇到了导致问题的原因之一:在我的实际应用程序中,我没有标题栏,因此要移动我正在发送 WM_NCLBUTTONDOWN 的窗口到我的WM_LBUTTONDOWN 上的主窗口:

SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, NULL);

然后我在这之后有我的 SetFocus() 并且这不起作用但是如果我切换它们并首先处理 SetFocus() 然后点击确实改变专注。

虽然初始设置焦点仍然存在问题。在启动应用程序后的那一刻,自定义编辑控件仍然显示插入符号,即使它没有焦点,您需要单击它以赋予它焦点,从而它将接收键盘输入。之后焦点按预期工作:如果我单击主窗口,它就会有焦点;如果我点击自定义编辑,它有焦点等。

最佳答案

好吧,事实证明我的整个问题在于那行 SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, NULL); 一旦我切换了这个:

case WM_LBUTTONDOWN:                        
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, NULL);
SetFocus(hwnd);
break;

到:

case WM_LBUTTONDOWN:                        
SetFocus(hwnd);
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, NULL);
break;

一切都在一起了。

关于c++ - winapi C++ 处理焦点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13381836/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com