私は C++ winapi アプリに取り組んでおり、自分のためSetFocus()
に仕事をするのに苦労しています。でメイン ウィンドウをWS_OVERLAPPEDWINDOW | WS_VISIBLE
作成し、その中にその子 (いくつかのボタンと独自のバージョンのエディット コントロールの始まり) を で作成しWS_CHILD | WS_VISIBLE
ます。フォーカスの問題を除いて、これらはすべて正常に動作しています。
私の検索では、フォーカスをどのように扱うべきかという点で多くを見つけるのに苦労しました. ウィンドウがすべて作成されると、メッセージが個別に受信さWM_SETFOCUS
れ、キャレットを作成して編集コントロールでこのメッセージを処理しますが、子がWM_KILLFOCUS
メッセージを受信しないように見えるため、キャレットが破棄されることはありません。
ここで私の問題が発生します。メインの親ウィンドウに最初にフォーカスがあり、編集コントロールにキャレットがないようにしてから、子の編集コントロールがクリックされてフォーカスがあり、メイン ウィンドウがクリックすると、再びフォーカスが置かれます。
だから私の最初の考えは、メッセージSetFocus()
を処理するときにメインウィンドウにフォーカスを設定するWM_CREATE
ことでしたが、それはうまくいかないようでした.子供はWM_KILLFOCUS
メッセージを受け取りませんでした.
次に考えたのは、親が適切な子への受け渡しを処理する必要があるのではないかと考えたWM_KILLFOCUS
ので、それを行うメソッドを作成しましたが、それでも子は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 があり、メッセージが入ってきたら処理します。
それで、誰か私に何か考えがありますか?
これが完全に間違った方法である場合、またはベスト プラクティスに従っていない場合は、そのように言ってください。
[アップデート]
問題を示すコードは次のとおりです。
メイン.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;
}
BaseWindow.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);
}
MainWnd.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;
}
CustomTextBox.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);
}
}
発見
このコードを書いているときに、問題の原因の 1 つに出会いました。実際のアプリケーションではタイトル バーがないため、送信WM_NCLBUTTONDOWN
していたウィンドウを次のメイン ウィンドウに移動しWM_LBUTTONDOWN
ます。
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, NULL);
その後、SetFocus()
これを行ったところ、これは機能しませんでしたが、それらを切り替えてSetFocus()
最初のものを処理すると、クリックするとフォーカスが変わります。
ただし、最初にフォーカスを設定する際にはまだ問題があります。アプリを起動した時点では、カスタム編集コントロールにはフォーカスがなくてもキャレットが表示され、それをクリックしてフォーカスを与える必要があります。これにより、キーボード入力を受け取ることができます。その後、フォーカスは希望どおりに機能します。メインウィンドウをクリックすると、フォーカスがあります。カスタム編集をクリックすると、フォーカスなどがあります。