C++ Builder 10.2 Tokyo > Forms > 폼을 정렬할 때 공백이 없도록 배치(Windows 7, 8.1, 10) > FormShow 후 실행

구현 환경
RAD Studio 10.2 Tokyo Update 3

관련


  • C++ Builder 10.2 Tokyo > Forms > Bug > 8개의 자식 폼을 부모 폼 아래에 4행 x 2열로 배치 > 공백이 뚫린다 > 10.2 Tokyo의 문제가 아닐 것
  • C++ Builder XE4 > Windows 7, 8.1, 10의 윈도우 크기 정보 보기

  • 처리 개요


  • Windows 7, 8.1, 10 모두에서 폼을 늘어 놓을 때 빈 공간이 생기지 않도록한다

  • code



    Unit1.h
    //---------------------------------------------------------------------------
    
    #ifndef Unit1H
    #define Unit1H
    //---------------------------------------------------------------------------
    #include <System.Classes.hpp>
    #include <Vcl.Controls.hpp>
    #include <Vcl.StdCtrls.hpp>
    #include <Vcl.Forms.hpp>
    #include <Vcl.ExtCtrls.hpp>
    #include <Vcl.ComCtrls.hpp>
    #include <VCLTee.Chart.hpp>
    #include <VCLTee.Series.hpp>
    #include <VclTee.TeeGDIPlus.hpp>
    #include <VCLTee.TeEngine.hpp>
    #include <VCLTee.TeeProcs.hpp>
    
    #include "Unit2.h"
    //---------------------------------------------------------------------------
    
    // hogehoge
    
    class TForm1 : public TForm
    {
    __published:    // IDE で管理されるコンポーネント
        TButton *B_matrix;
        void __fastcall B_createChildClick(TObject *Sender);
        void __fastcall B_matrixClick(TObject *Sender);
    private:    // ユーザー宣言
        static const int kNumChild = 8;
        TForm2 *m_childForms[kNumChild];
        void __fastcall putChildrenInMatrix();
        void __fastcall GetVisibleWindowSize(TForm *formPtr, TRect *rectPtr);
    public:     // ユーザー宣言
        __fastcall TForm1(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
    

    Unit1.cpp
    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit1.h"
    #include <DateUtils.hpp>
    
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
    }
    
    //---------------------------------------------------------------------------
    void __fastcall TForm1::B_createChildClick(TObject *Sender)
    {
        for(int idx=0; idx < kNumChild; idx++) {
            m_childForms[idx] = new TForm2(this);
            m_childForms[idx]->Show();
        }
    }
    //---------------------------------------------------------------------------
    
    static void calcLeftTopOfChildren(int parentTop, int parentHeight, int childIdx, int childWidth, int childHeight, int *dstTop, int *dstLeft)
    {
        int topSize, leftSize;
    
        if (childIdx < 4) {
            topSize = childIdx * childHeight;
            leftSize = 0;
        } else {
            topSize = (childIdx - 4) * childHeight;
            leftSize = childWidth;
        }
    
        int marginTop = parentTop + parentHeight;
    
        *dstTop = marginTop + topSize;
        *dstLeft = leftSize;
    }
    
    void __fastcall TForm1::putChildrenInMatrix()
    {
        TForm2 *formPtr;
        int topPos, leftPos;
    
        TRect parGeo; // parent
        TRect chlGeo; // child
    
        for(int chlIdx=0; chlIdx < kNumChild; chlIdx++) {
            formPtr = m_childForms[chlIdx];
    
            // parent
            GetVisibleWindowSize(this, &parGeo);
            int parhei = parGeo.Bottom - parGeo.top;
            // child
            GetVisibleWindowSize(formPtr, &chlGeo);
            int chlwid = chlGeo.Right - chlGeo.Left;
            int chlhei = chlGeo.Bottom - chlGeo.top;
    
            // calcLeftTopOfChildren(this->Top, this->Height, chlIdx, formPtr->Width, formPtr->Height, &topPos, &leftPos);
            calcLeftTopOfChildren(parGeo.top, parhei, chlIdx, chlwid, chlhei, &topPos, &leftPos);
            formPtr->Top = topPos;
            formPtr->Left = leftPos;
        }
    }
    void __fastcall TForm1::B_matrixClick(TObject *Sender)
    {
        putChildrenInMatrix();
    }
    
    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;
    }
    

    실행 결과



    Windows 7





    Windows 8.1





    Windows 10





    FormShow 후 실행



    (추기 2018/05/07)

    C++ Builder 10.2 Tokyo > Forms > Height > Windows 10: 실행 타이밍에 따라 다름 | Windows 7, 8.1: 실행 타이밍에 관계없이 동일
    에 기재된 대로,

    상기의 구현은 FormShow시에 실행하면 희망의 동작은 되지 않는다.

    FormShow의 처리 후에만 유효한 것 같다.

    좋은 웹페이지 즐겨찾기