0

更新: 要求に応じて、ウィンドウとそのリッチエディット コントロールを作成するために使用しているすべてのコードを追加しました。

別のウィンドウの子として使用される RichEdit コントロールの Windows メッセージを処理しようとしています。

これで、自分の を除いて、RichEdit コントロールが動作するようになりましたWndProc。問題は、 で使用されwc.lpszClassName = MSFTEDIT_CLASS;ているものと一致するように設定すると、RichEdit コントロールのコンテンツ (テキストなど) が描画されないように見えますが、その WndProc 関数はメッセージを処理できるようになります。lpClassNameCreateWindowEx()

ウィンドウの作成:

最初のコンストラクター:

SubWindow::SubWindow(const wchar_t *szAppNameImport)
{
    szAppName = szAppNameImport;

    cfmt = CHARFORMATW();
    hwnd = HWND();
    windowRect = RECT();
    editControlHwnd = HWND();
    wc = WNDCLASSEX();

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_CLASSDC;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = GetModuleHandle(NULL);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = szAppName;
    wc.hIconSm = LoadIcon(wc.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
}

次に、Create()関数:

VOID SubWindow::Create(unsigned int window_startX, unsigned int window_startY, unsigned int windowWidthInput, unsigned int windowHeightInput, HWND parent)
{   
    windowRect.left = window_startX;
    windowRect.top = window_startY;

    windowRect.right = windowWidthInput;
    windowRect.bottom = windowHeightInput;

    if(!RegisterClassEx(&wc))
    {
        throw std::exception();
    }

    if((hwnd = CreateWindowEx
        (
        WS_EX_CLIENTEDGE,
        szAppName,
        TEXT("Our classy sub window!"),
        WS_OVERLAPPEDWINDOW| WS_VISIBLE,

        windowRect.left, windowRect.top,
        windowRect.right, windowRect.bottom,
        parent,
        NULL,       
        wc.hInstance,
        NULL))==NULL)
    {
        throw std::exception();
    }

    SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)this);

    ShowWindow(hwnd, SW_SHOWDEFAULT);
    UpdateWindow(hwnd);
}

WndProc:

LRESULT CALLBACK SubWindow::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    SubWindow *childWindowPointer = (SubWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA);

    if(childWindowPointer != NULL)
    {
        if(childWindowPointer->GetEditControl() == hwnd)
            OutputDebugString(L"I SHOULD NOT BE CALLED");

        return childWindowPointer->MsgProc(hwnd, uMsg, wParam, lParam);
    }
    else
    {
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

メッセージ プロシージャ:

LRESULT SubWindow::MsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{
    PAINTSTRUCT ps;
    HDC hdc;

    switch(uMsg)
    {
    case WM_WINDOWPOSCHANGED:
        {
            GetClientRect(hwnd, &windowRect);
            SetWindowPos(editControlHwnd, NULL, windowRect.left, windowRect.top, windowRect.right, windowRect.bottom, SWP_NOZORDER | SWP_NOACTIVATE);
            return 0;
        }
    case WM_DESTROY:
        {
            OutputDebugString(TEXT("DESTROYING A SUB WINDOW!\n"));
            return 0;
        }

    case WM_PAINT:
        {
            InvalidateRect (hwnd, NULL, FALSE);
            hdc = BeginPaint(hwnd, &ps);
            EndPaint(hwnd, &ps);
            return 0;
        }

    case EM_EXSETSEL:
        {
            if(hwnd == editControlHwnd)
            {
                OutputDebugString(L"Text selection changed");
                return 0;
            }
        }
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
} 

WndProcRichEdit コントロールは、 I've definedを使用しないことを除いて、明らかに問題なく完全に描画および機能します。

ここで何が間違っているのか、またはこれを正しく解決する方法がわかりません。

編集: 回答とコメントに基づいて、次のWindowように作成されたRichEditコントロールを含むクラスのみを使用するようにコードを復元しました:

void SubWindow::CreateEditControl()
{
    std::wstring initialText = TEXT("TestWindow\r\n");

    LoadLibrary(L"Msftedit.dll");

    GetClientRect(hwnd, &windowRect);
    editControlHwnd = CreateWindowEx(0, MSFTEDIT_CLASS, initialText.data(),
        WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_READONLY | WS_VSCROLL | ES_NOHIDESEL,
        windowRect.left, windowRect.top,windowRect.right,windowRect.bottom,
        hwnd,
        NULL, NULL, NULL);

    cfmt.cbSize = sizeof(CHARFORMAT);
    cfmt.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE;
    cfmt.dwEffects = 0;
    cfmt.yHeight = 160;
    cfmt.crTextColor = RGB(0,0,0);
    wcscpy_s(cfmt.szFaceName, TEXT("Tahoma"));

    SendMessage(editControlHwnd, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cfmt);
}

Window の MsgProc でこのコントロールからのメッセージを処理するにはどうすればよいですか?

4

3 に答える 3

1

デフォルトのクラス名 ( ) を使用してリッチ エディット コントロール ウィンドウを作成するとMSFTEDIT_CLASS、すべてのメッセージがその親ウィンドウに送信されます。あなたはその親ウィンドウではないため、これらのメッセージを処理することはできません。

そのため、メッセージを親に渡すのではなく、直接呼び出される独自のウィンドウ プロシージャに置き換えて、コントロールをサブクラス化する必要があります。それは簡単です。通常の編集コントロールについては、この回答で以前に説明しました。変更されたサンプル コードは次のようになります。

// Stores the old original window procedure for the rich edit control.
WNDPROC wpOldRichEditProc;

// The new custom window procedure for the rich edit control.
LRESULT CALLBACK CustomRichEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        ...
    }

    // Pass the messages you don't process on to the original window procedure.
    CallWindowProc(wpOldRichEditProc, hWnd, msg, wParam, lParam);
}

そして、コントロールを作成するとき:

// Create the rich edit control
HWND hWnd = CreateWindowEx(...)

// Subclass it.
wpOldRichEditProc= (WNDPROC)SetWindowLongPtr(hWnd,
                                             GWLP_WNDPROC,
                                             (WNDPROC)CustomRichEditProc);

また、コントロールが破棄されるたびに、そのサブクラスを確実に解除する必要があります。他の例は、親ウィンドウが受信したメッセージに応答してそれを行うことを示していますが、親ウィンドウのメッセージを取得していないため、この場合は機能しません。代わりに、独自のWM_NCDESTROYメッセージに応答してコントロールからサブクラスを削除する必要があります。

SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)wpOldRichEditProc);

または、共通コントロール ライブラリのバージョン 6 では、一連のユーティリティ関数を使用してサブクラス化する、エラーが発生しにくい新しい方法が導入されました。ウィンドウを実際に所有するプロセスを制御できないことを考えると、これは間違いなく推奨されるアプローチです。

MSDNには、両方のアプローチのデモがあります。

もちろん、個々のコントロールだけをサブクラス化する必要はありません。組み込みのリッチ エディット コントロールと同じように動作するカスタム ウィンドウ クラスを登録することもできますが、そのクラスのウィンドウが受信したメッセージを最初に確認することができます。それが必要かどうかは、質問からはわかりません。になるコントロールは 1 つだけのようです。

于 2013-08-24T13:52:00.407 に答える
0

wc構造とウィンドウの作成を含むコードを表示できますか? メイン ウィンドウにリッチ エディット コントロールと同じクラスを持たせたくないという方もいらっしゃると思います。

WNDCLASSEXリッチ エディット コントロールに適用する理由がわかりません。

SetWindowLong()私の提案は、リッチ エディット コントロールが作成された後に、 with を使用しGWL_WNDPROCて、物事を単純化し、「サブクラス化」することEditControl::WndProcです。

于 2013-08-24T13:26:07.040 に答える