質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • C

    3689questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • C++

    3451questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Win32 API

    222questions

    Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

WinAPI子ウィンドウの再描画

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 230

Weapon

score 22

 前提・実現したいこと

C++ととWinAPIで親ウィンドウに2分割で子ウィンドウを2つ配置しました。
しかし
(1)実行時は出ていないのですけどマウスでホバーすると最小化最大化終了ボタンが表示され、
(2)サイズの変更後、左の子ウィンドウの文字をクリックするとサイズ変更前の初期サイズの白い線が発生します。
どこか再描画のタイミングがおかしいのでしょうか
また(3)子ウィンドウのプロシージャのつなぎ方は親ウィンドウ同様WNDCLASSを再び使えばいいのでしょうか

 発生している問題・エラーメッセージ

Broken Window

 該当のソースコード

#define UNICODE
#include <windows.h>
#define ID_CHILD_1 10001
#define ID_CHILD_2 10002

LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWindowProc1(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWindowProc2(HWND, UINT, WPARAM, LPARAM);

HINSTANCE hInst;
RECT rcWindow;
const wchar_t CLASS_NAME[] = L"Main Window";


int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR pCmdLine, int nCmdShow)
{
    WNDCLASSEX wcMain = {};
    wcMain.cbSize = sizeof(WNDCLASSEX);
    wcMain.style = CS_HREDRAW | CS_VREDRAW;
    wcMain.lpfnWndProc = WindowProc;
    wcMain.cbClsExtra = 0;
    wcMain.cbWndExtra = 0;
    wcMain.hInstance = hInstance;
    wcMain.hIcon = NULL;
    wcMain.hIconSm = (HCURSOR)LoadImage(
        NULL,
        MAKEINTRESOURCE(IDC_ARROW),
        IMAGE_CURSOR,
        0, 0,
        LR_DEFAULTSIZE | LR_SHARED
    );
    wcMain.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wcMain.lpszMenuName = NULL;
    wcMain.lpszClassName = CLASS_NAME;
    wcMain.hIconSm = NULL;

    RegisterClassEx(&wcMain);

    HWND hMothWnd = CreateWindowEx
    (
        0,
        CLASS_NAME,
        L"Mother Window",
        WS_OVERLAPPEDWINDOW | WS_EX_TRANSPARENT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    if (hMothWnd == NULL)return 0;

    ShowWindow(hMothWnd, nCmdShow);
    UpdateWindow(hMothWnd);

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


    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static HWND hChildWnd_L, hChildWnd_R;
    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_SIZE:
        if (GetClientRect(hwnd, &rcWindow) == false) {
            MessageBox(hwnd, L"Can't Get the ClientRect", L"Alert", IDOK);
            break;
        }

    case WM_CREATE:
        WNDCLASSEX cwlc;
        cwlc.cbSize = sizeof(WNDCLASSEX);
        cwlc.lpfnWndProc = ChildWindowProc1;
        cwlc.hInstance = hInst;
        cwlc.lpszClassName = L"Child Window 1";
        cwlc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
        cwlc.style = CS_HREDRAW | CS_VREDRAW;

        cwlc.lpszMenuName = NULL;
        RegisterClassEx(&cwlc);

        hChildWnd_L = CreateWindowEx
        (
            0,
            L"EDIT",
            L"Child Window 1",
            WS_CHILD | WS_DLGFRAME | WS_VISIBLE,
            0,
            0,
            (rcWindow.right-rcWindow.left)/2,
            rcWindow.bottom-rcWindow.top,
            hwnd,
            (HMENU)ID_CHILD_1,
            hInst,
            NULL
        );

        WNDCLASSEX cwlc2;
        cwlc2.cbSize = sizeof(WNDCLASSEX);
        cwlc2.lpfnWndProc = ChildWindowProc2;
        cwlc2.hInstance = hInst;
        cwlc2.lpszClassName = L"Child Window 2";
        cwlc2.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        cwlc2.style = CS_HREDRAW | CS_VREDRAW;

        cwlc2.lpszMenuName = NULL;
        RegisterClassEx(&cwlc);
        hChildWnd_R = CreateWindowEx
        (
            0,
            L"EDIT",
            L"Child Window 2",
            WS_CHILD | WS_THICKFRAME | WS_VISIBLE | ES_MULTILINE |
            ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | WS_OVERLAPPEDWINDOW,
            (rcWindow.right - rcWindow.left) / 2,
            rcWindow.top,
            (rcWindow.right - rcWindow.left) / 2,
            rcWindow.bottom - rcWindow.top,
            hwnd,
            (HMENU)ID_CHILD_2,
            hInst,
            NULL
        );
        break;

    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

LRESULT CALLBACK ChildWindowProc1(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {return DefWindowProc(hwnd, uMsg, wParam, lParam);}

LRESULT CALLBACK ChildWindowProc2(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {return DefWindowProc(hwnd, uMsg, wParam, lParam);}


コーディング上のご指摘もありがたいです。

 補足情報

Windows10 Pro
VisualStudio2017Community

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

MotherWindowにはWS_CLIPCHILDREN、子ウィンドウにはそれぞれWS_CLIPCHILDREN | WS_CLIPSIBLINGSを付けてください。
そうしないとそれぞれの描画で重なっている別のウィンドウを塗りつぶしてしまいます。

WM_SIZEのFallThroughはダメです。WM_SIZEはサイズ変更の度に何回も発生します。
WM_CREATEの頭で別個にGetClientRectで取得してください。
閉じるボタンなどが表示されるのは手元では出ませんでしたがWM_SIZEが怪しすぎるのでとりあえずそれを直してからかと。

こう言ったウィンドウ構成ならMDIを使ったほうがいいと思います。

--------- 追記 ---------------------------

    case WM_SIZE:
    {
        if (GetClientRect(hwnd, &rcWindow) == false) {
            MessageBox(hwnd, L"Can't Get the ClientRect", L"Alert", IDOK);
            break;
        }
        int w = rcWindow.right - rcWindow.left;
        int h = rcWindow.bottom - rcWindow.top;
        MoveWindow(hChildWnd_L, 0, 0, w/2, h, TRUE);
        MoveWindow(hChildWnd_R, w/2, 0, w/2, h, TRUE);
        break;
    }

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/21 12:56

    WM_SIZEは消してWM_CREATEにGetClientRectは配置しました。
    子ウィンドウのみでの子ウィンドウの移動やリサイズは想定していません(左右のウィンドウの枠が違うのはWindowstyleの比較用です)。親ウィンドウがリサイズされたとき子ウィンドウがそれぞれ左右中央2分割するようにしたいのです。親のWM_CREATEはCreateWindowが呼ばれたときのみ実行されるため親ウィンドウのリサイズ時に子ウィンドウの再描画が必要であると考えているのですがWM_SIZEでのなんらかの記述は不要でしょうか?
    答えていただいた"WM_CREATEの頭で別個にGetClientRect"とは子ウィンドウのWM_CREATEのことでしょうか?

    MDIについては基本的なウィンドウ管理を覚えたら挑戦させていただきます。ありがとうございます。

    キャンセル

  • 2018/07/21 14:32

    あぁ、そういうことですか。ではMDIは気にしないでください。
    単純に親のWM_SIZEで子を移動させればいいです。
    コード追記したので確認してください。
    MoveWindowの最後の引数がTRUEなら子は再描画されます(SetWindowPosでもいいです)
    WM_CREATEの直後にWM_SIZEも必ず発生するのでWM_CREATEでは子の位置は計算せずに 0, 0, 0, 0とかにしておいてもいいですよ。

    キャンセル

0

ChildWindowProc1(), ChildWindowProc2() の内容を
return DefWindowProc(hwnd, uMsg, wParam, lParam);
にしたら表示が改善されませんか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/20 19:46

    省略してはいけないものまで省略で消してしまっていました。
    実際のコードは書かれています。
    修正しておきますね。ありがとうございます

    キャンセル

  • 2018/07/20 19:59 編集

    WM_SIZEからfall throughしてそのままWM_CREATE時のコードに行ってしまうのがまずいのでは.
    一度,WM_SIZE:の内容を,WM_CREATE:の次に配置し,WM_SIZE:の部分をコメントアウトしてみたらどうでしょうか.
    (「case WM_CREATE:」の行をコメントアウトして,「case WM_SIZE:」を「case WM_CREATE:」に書き換えた感じに)

    キャンセル

  • 2018/07/20 21:00

    それをするとリサイズ時のメッセージが飛ばなくなるのでそのWM_CREATEをWM_PAINTにすればウィンドウの再描画はされます。しかしメッセージがWM_CREATEではなくWM_PAINTで描画していいのかということに違和感を感じているので効果的な解決法を求めています
    そして書き換えても最初の質問の(2)の白い線が残るんですがこれは子ウィンドウの再描画ですかね

    キャンセル

  • 2018/07/20 22:31

    (1)何が問題を引き起こしているのか? を明らかにすべきと思い,最初の回答を行った.一時的にでも試しに子ウィンドウのウィンドウプロシージャをデフォルト動作だけに差し替えたら現象が変化(改善)することは無いのか?という.
    それで問題の現象に変化があるなら,子ウィンドウのプロシージャの実装に問題がある可能性がある(→提示されているコードだけでは解決できない)
    (2)次に,それとは別に,提示されているメインウィンドウのプロシージャにも問題がありそうなのでコメントで追加指摘した.WM_SIZEメッセージ毎にウィンドウ生成処理が走るのは明らかにバグと思われ,それがどんな悪影響を与えるかわからないから,一旦その問題が起こらない状態の動作を確認したい(してほしい)

    上記2点を修正した状態では,少なくともこちらの環境では,提示スクリーンショットのようなおかしな描画は成されない.(そりゃ確かにこの状態はあなたの意図した動作をするコードではないですが,仮に問題現象が起きなくなるなら,そこから必要な処理を再び足していけばよいのではないかと.)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C

    3689questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • C++

    3451questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Win32 API

    222questions

    Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。