Edited at

C++ Builder 10.2 Tokyo > FormShow後に一回だけ実行する > Window Message処理

More than 1 year has passed since last update.


動作環境

RAD Studio 10.2 Tokyo Update 3

秀丸エディタ Version 8.79


関連

FormShow時の処理とFormShow後の処理でWindows 10ではHeightの情報が異なる。

上記においてはFormActivate()を使うことで正しいHeightが得られるようになった。

FormActivate()はフォームのフォーカスが戻ってきたときなどにも実行される。

別の方法としてWindow Messageの方法を実装してみた。


Window Message

上記においてはForm1からForm2へWindow Messageを送信している。

FormShow後の処理では自分自身にWindow Messageを送信する方法が考えられる。


code



  • WM_SHOW_HEIGHTを定義


  • MESSAGE_HANDLER()を定義


  • WMshowHeight()を定義


  • PostMessage(this->Handle, WM_SHOW_HEIGHT, 0, 0);する


Unit1.h

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------

#define WM_SHOW_HEIGHT (WM_APP + 1)

class TForm1 : public TForm
{
__published: // IDE で管理されるコンポーネント
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
void __fastcall FormShow(TObject *Sender);
private: // ユーザー宣言
void __fastcall getVisibleWindowSize(TForm *formPtr, TRect *rectPtr);
public: // ユーザー宣言
__fastcall TForm1(TComponent* Owner);
void __fastcall WMshowHeight(TMessage &msg);

BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_SHOW_HEIGHT, TMessage, WMshowHeight);
END_MESSAGE_MAP(TForm)
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif



Unit1.cpp

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::getVisibleWindowSize(TForm *formPtr, TRect *rectPtr)
{
TRect arect_inv;
RECT arect_nrm;

if (formPtr == NULL || rectPtr == NULL) {
return; // error
}

GetWindowRect(formPtr->Handle, &arect_nrm); // (1)
DwmGetWindowAttribute(formPtr->Handle, DWMWA_EXTENDED_FRAME_BOUNDS, &arect_inv, sizeof(TRect)); // (2)

// for Windows 7
if (arect_inv.left == 0 && arect_inv.top == 0 && arect_inv.Bottom == 0 && arect_inv.right == 0) {
// DwmGetWindowAttribute()が0を返すためGetWindowRect()の結果を使う
rectPtr->left = arect_nrm.left;
rectPtr->top = arect_nrm.top;
rectPtr->right = arect_nrm.right;
rectPtr->bottom = arect_nrm.bottom;
return;
}

// for Windows 8.1, Windows 10
// Windows 8.1では(1)と(2)は同じ定義
// Windows 10ではinvisible borderにより(1)と(2)の結果が異なる
// invisible borderのサイズを含まない(2)の方を返す
//
// !!!ただしWindows 10の場合、FormShow時には正しい値を返さない!!!
// FormShow後に実行すること rectPtr->left = arect_inv.left;
rectPtr->top = arect_inv.top;
rectPtr->right = arect_inv.right;
rectPtr->bottom = arect_inv.bottom;
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TRect arect;

getVisibleWindowSize(this, &arect);

int parhei = arect.Bottom - arect.top;
String msg = IntToStr(parhei) + L" on Button1Click()";
ShowMessage(msg);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
// FormShow()後に処理するため
PostMessage(this->Handle, WM_SHOW_HEIGHT, 0, 0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WMshowHeight(TMessage &msg)
{
// ウィンドウHeightの取得
TRect arect;

getVisibleWindowSize(this, &arect);

int parhei = arect.Bottom - arect.top;
String wrk = IntToStr(parhei) + L" on WMshowHeight()";
ShowMessage(wrk);
}
//---------------------------------------------------------------------------



実行


  • Windows 10


    • 336 on WMshowHeight()

    • 336 on Button1Click()



同じ値になった。


考察


  • FormActivate()


    • 注意: 様々なソフトにてFormShow()だけを多用している場合、コードを読む人がFormActivate()で処理していることを認識しないかもしれない

    • 利点: Window Messageを使う場合よりもシンプルな構造での実装になる

    • 欠点: static変数の使用



  • Window Message


    • 注意: 別のWindow Messageとかぶらないこと

    • 利点: FormShow()からPostMessage()を実行することで、起動時の認識として判別しやすいかも