wxWidgetsのチュートリアル的なもの

https://qiita.com/kmatsumoto630823/items/12dcb03654bc5bcadb87

上記記事の手順で作成した環境を前提とし、以下も実施済みとする
異なる環境の場合は、適宜読み替えること
 - 以下のビルドコマンドで静的ライブラリのビルド
    ```
    cd C:\wxWidgets\wxWidgets-3.2.2.1\build\msw
    mingw32-make SHELL=CMD.exe -f makefile.gcc BUILD=release UNICODE=1 SHARED=0 MONOLITHIC=1
    ```
 - リソースファイルの準備
    ```
    windres -i.\resource.rc -o.\resource.o --include-dir C:\wxWidgets\wxWidgets-3.2.2.1\include --define wxUSE_DPI_AWARE_MANIFEST=2
    ```
    
# 0. はじめに

wxWidgetsを使ったGUIアプリ作成のおおまかな流れを掴んでもらうのが目的
過剰に書きすぎないようにするが、大事だと思ったところは深堀していく

※単に関数と書いた場合はクラスのメンバ関数と読み替えること
※通常の関数はフリー関数と表記する

# 1. wxApp

wxWidgetsではmain関数を定義せず、マクロ内で生成する
したがって、「wxApp」クラスの「OnInit」関数が実質的なコードの起点となる

## ソースコード

```App.h
#include <wx/wx.h>

//wxAppの派生クラスを定義してOnInit()をオーバーライド
class myApp : public wxApp
{
public:
    virtual bool OnInit() override;
};
```

```App.cpp
#include "App.h"
#include <iostream>

//真のmain関数（エントリポイント）を生成するマクロ
wxIMPLEMENT_APP(myApp);

//事実上のmain関数
bool myApp::OnInit()
{
    //標準出力に文字列を出力
    std::cout << "Hallo World!\n";

    //trueでwxWidgetsのメインループへ、falseでプログラム即終了
    return true;
}
```

## コンパイル

※今回に限っては「-mwindows」は抜いてコンソールアプリケーションとしてビルド

```
g++ -O2 -finput-charset=CP932 -fexec-charset=CP932 -static-libgcc -static-libstdc++ -mthreads  App.cpp -o App.exe -I C:\wxWidgets\wxWidgets-3.2.2.1\include -I C:\wxWidgets\wxWidgets-3.2.2.1\lib\gcc_lib\mswu -L C:\wxWidgets\wxWidgets-3.2.2.1\lib\gcc_lib -lwxmsw32u -lwxmsw32u_gl -lwxscintilla -lwxtiff -lwxjpeg -lwxpng -lwxzlib -lwxregexu -lwxexpat -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lwinspool -lwinmm -lshell32 -lshlwapi -lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lversion -lws2_32 -lwininet -loleacc -luxtheme
```
## 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/ce9aa071-81f0-6ad9-6d0b-18f94fda8c56.png)

## 真のエントリポイントはどこか？

wxWidgetsで最初にやることをまとめると次の通り
- 「wxApp」クラスの派生クラスをつくる
- 「OnInit」関数をオーバーライドしてやりたい処理を書く
- 定義した派生クラスを「wxIMPLEMENT_APP」マクロに渡す

あとはwxWidgets側で「OnInit」関数を実行してくれる

真のエントリポイントは「wxIMPLEMENT_APP」マクロによって定義をされる
※参考までに自分の環境で「wxIMPLEMENT_APP」マクロをVSCodeに展開してもらった結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/8b300ca5-0372-3779-ae56-c5ccf4b885b8.png)

# 2. wxFrame

ここではウィンドウを取り扱う
wxWidgetsでは「wxFrame」クラスが最も基本的なウィンドウとなる

また、widgetsクラスのコンストラクタで（おおむね）共通である第一引数・第二引数にも触れる
ついでにWindowIDの取り扱いも解説しておく

## ソースコード

```App.h
#include <wx/wx.h>

//wxAppの派生クラスを定義してOnInit()をオーバーライド
class myApp : public wxApp
{
public:
    virtual bool OnInit() override;
};
```

```App.cpp
#include "App.h"

//真のmain関数（エントリポイント）を生成するマクロ
wxIMPLEMENT_APP(myApp);

//事実上のmain関数
bool myApp::OnInit()
{
    //ウィンドウを生成
    auto frame = new wxFrame(nullptr, wxID_ANY, "ウィンドウのタイトル");

    //ウィンドウを表示
    frame->Show();
    
    //trueでwxWidgetsのメインループへ、falseでプログラム即終了
    return true;
}
```

## コンパイル

```
g++ -O2 -finput-charset=CP932 -fexec-charset=CP932 -static-libgcc -static-libstdc++ -mthreads -mwindows App.cpp resource.o -o App.exe -I C:\wxWidgets\wxWidgets-3.2.2.1\include -I C:\wxWidgets\wxWidgets-3.2.2.1\lib\gcc_lib\mswu -L C:\wxWidgets\wxWidgets-3.2.2.1\lib\gcc_lib -lwxmsw32u -lwxmsw32u_gl -lwxscintilla -lwxtiff -lwxjpeg -lwxpng -lwxzlib -lwxregexu -lwxexpat -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lwinspool -lwinmm -lshell32 -lshlwapi -lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lversion -lws2_32 -lwininet -loleacc -luxtheme
```

## 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/aceea615-a2fa-b81c-a288-48d2f963ac9b.png)


## widgetクラスのコンストラクタ

下記は「wxFrame」クラスのコンストラクタを呼び出している

```c++
auto frame = new wxFrame(nullptr, wxID_ANY, "ウィンドウのタイトル");
```

「wxFrame」クラスに限らず、widgetクラスのコンストラクタで要求される第一・ 第二引数は（おおむね）共通となっている

- 第一引数：親widgetのポインタ
※「wxFrame」は最上位のwidgetのため今回はnullptr

- 第二引数：WindowID（すべてのwidget間でユニークとなることが要求される値）
※WindowIDを使った処理をしないなら「wxID_ANY」を指定して自動割振するとよい

WindowIDについてはwxWidget側で管理されている範囲がある

- 自動割り当て範囲：「wxID_AUTO_LOWEST」～「wxID_AUTO_HIGHEST」
- 予約済みIDの範囲：「wxID_LOWEST」～「wxID_HIGHEST」

手動でIDを管理する場合はこれらの範囲を避けること
https://docs.wxwidgets.org/3.2/overview_windowids.html

覚えなくていいが「wxFrame」のコンストラクタの完全な定義は次の通り
https://docs.wxwidgets.org/3.2/classwx_frame.html#a01b53ac2d4a5e6b0773ecbcf7b5f6af8

```c++
wxFrame (wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE, const wxString &name=wxFrameNameStr)
```

デフォルト値で引数が隠れているものが多いが、あとから設定できるものはひとまずデフォルト値に任せてしまうのもよいだろう

# 3. wxFrameをカスタマイズする（準備）

まずは準備として、動作を変えない範囲で「wxFrame」クラスを継承した派生クラスを定義する
この派生クラスの定義がオリジナルプログラムの第一歩となる

## ソースコード

```frame.h
#include <wx/wx.h>

class myFrame : public wxFrame
{
public:
    //基底クラスと同じ引数を持つコンストラクタ（宣言）
    myFrame
    (
        wxWindow* parent,
        wxWindowID id,
        const wxString& title,
        const wxPoint& pos = wxDefaultPosition,
        const wxSize& size = wxDefaultSize,
        long style = wxDEFAULT_FRAME_STYLE,
        const wxString& name = wxFrameNameStr
    );

private:
    //今後のカスタマイズで必要があればここにメンバの追加
};
```

```frame.cpp
#include "Frame.h"

 //基底クラスと同じ引数を持つコンストラクタ（定義）
myFrame::myFrame
(
    wxWindow* parent,
    wxWindowID id,
    const wxString& title,
    const wxPoint& pos,
    const wxSize& size,
    long style,
    const wxString& name

) : wxFrame(parent, id, title, pos, size, style, name)//基底クラスへの委譲コンストラクタ
{
    //今後ここにカスタマイズの処理を入れる予定
}
```

```app.h
#include <wx/wx.h>

//wxAppの派生クラスを定義してOnInit()をオーバーライド
class myApp : public wxApp
{
public:
    virtual bool OnInit() override;
};
```

```app.cpp
#include "App.h"
#include "Frame.h"

//真のmain関数（エントリポイント）を生成するマクロ
wxIMPLEMENT_APP(myApp);

//事実上のmain関数
bool myApp::OnInit()
{
    //「カスタマイズされた」ウィンドウを生成
    auto frame = new myFrame(nullptr, wxID_ANY, "ウィンドウのタイトル");

    //ウィンドウを表示
    frame->Show();
    
    //trueでwxWidgetsのメインループへ、falseでプログラム即終了
    return true;
}
```

## コンパイル

```
 g++ -O2 -finput-charset=CP932 -fexec-charset=CP932 -static-libgcc -static-libstdc++ -mthreads -mwindows App.cpp resource.o Frame.cpp -o App.exe -I C:\wxWidgets\wxWidgets-3.2.2.1\include -I C:\wxWidgets\wxWidgets-3.2.2.1\lib\gcc_lib\mswu -L C:\wxWidgets\wxWidgets-3.2.2.1\lib\gcc_lib -lwxmsw32u -lwxmsw32u_gl -lwxscintilla -lwxtiff -lwxjpeg -lwxpng -lwxzlib -lwxregexu -lwxexpat -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lwinspool -lwinmm -lshell32 -lshlwapi -lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lversion -lws2_32 -lwininet -loleacc -luxtheme
```

## 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/e55fd9e8-e9f6-22c0-8dc2-ac1dceed5765.png)


## 派生・継承によるwidgetクラスのカスタマイズ

「wxFrame」クラスを継承した「myFrame」派生クラスは基底クラスと同じ動作をするだけだが、以降の解説ではこのコードをひな形としてコードを追加していく

「wxFrame」クラスに限らずwidgetクラスのカスタマイズは継承によるポリモーフィズムによって実現できる
また、内部的に使われる関数であっても「オーバーライド可能な仮想関数」であればデフォルトの挙動を変えられる

# 4. メニューバーとステータスバー

「wxFrame」クラスにはメニューバーとステータスバーを追加することができる
※一応ツールバーもあるが割愛
メニューバーのアイテムには構築の都合上「wxID_ANY」ではなく明示的にWindowIDを割り当てる
また、イベントハンドルについても後ほど解説する

## ソースコード

```frame.h
#include <wx/wx.h>

class myFrame : public wxFrame
{
public:
    //基底クラスと同じ引数を持つコンストラクタ（宣言）
    myFrame
    (
        wxWindow* parent,
        wxWindowID id,
        const wxString& title,
        const wxPoint& pos = wxDefaultPosition,
        const wxSize& size = wxDefaultSize,
        long style = wxDEFAULT_FRAME_STYLE,
        const wxString& name = wxFrameNameStr
    );

private:
    wxMenuBar* menu_bar;
    wxMenu* menu_file;
};
```

```frame.cpp
#include "Frame.h"

 //基底クラスと同じ引数を持つコンストラクタ（定義）
myFrame::myFrame
(
    wxWindow* parent,
    wxWindowID id,
    const wxString& title,
    const wxPoint& pos,
    const wxSize& size,
    long style,
    const wxString& name

) : wxFrame(parent, id, title, pos, size, style, name)
{
    //メニューアイテムに割り当てるIDを列挙型を宣言しておく
    enum ID_MENU
    {
        ID_MENU_EXIT,
    };

    //メニューの構築
    menu_file = new wxMenu;
    menu_file->Append(ID_MENU_EXIT, "終了\tCtrl+Q");

    //メニューバーの構築とメニューバーにメニューをセット
    menu_bar = new wxMenuBar;
    menu_bar->Append(menu_file, "ファイル(&F)");

    //このWindowにメニューバーをセット
    SetMenuBar(menu_bar);

    //メニューの終了を押したらプログラム終了
    Bind(wxEVT_MENU, [=](wxCommandEvent& event)
    {
        Destroy();
    }, ID_MENU_EXIT);

    //ステータスバー
    CreateStatusBar();
    SetStatusText("ステータスバーはここ");

}
```

```app.h
#include <wx/wx.h>

//wxAppの派生クラスを定義してOnInit()をオーバーライド
class myApp : public wxApp
{
public:
    virtual bool OnInit() override;
};
```
```app.cpp
#include "App.h"
#include "Frame.h"

//真のmain関数（エントリポイント）を生成するマクロ
wxIMPLEMENT_APP(myApp);

//事実上のmain関数
bool myApp::OnInit()
{
    //「カスタマイズされた」ウィンドウを生成
    auto frame = new myFrame(nullptr, wxID_ANY, "ウィンドウのタイトル");

    //ウィンドウを表示
    frame->Show();
    
    //trueでwxWidgetsのメインループへ、falseでプログラム即終了
    return true;
}
```

## コンパイル

```
 g++ -O2 -finput-charset=CP932 -fexec-charset=CP932 -static-libgcc -static-libstdc++ -mthreads -mwindows App.cpp Frame.cpp resource.o -o App.exe -I C:\wxWidgets\wxWidgets-3.2.2.1\include -I C:\wxWidgets\wxWidgets-3.2.2.1\lib\gcc_lib\mswu -L C:\wxWidgets\wxWidgets-3.2.2.1\lib\gcc_lib -lwxmsw32u -lwxmsw32u_gl -lwxscintilla -lwxtiff -lwxjpeg -lwxpng -lwxzlib -lwxregexu -lwxexpat -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lwinspool -lwinmm -lshell32 -lshlwapi -lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lversion -lws2_32 -lwininet -loleacc -luxtheme
```

## 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/4aa8fc58-d553-37e2-f7af-eb926e3cfe77.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/10e4cdf6-5b25-7e03-746f-12552bfaf620.png)


## メニューの構成要素

メニュバーを構成する要素は次の通り
- メニューバー（wxMenuBar）
- メニュー（wxMenu）
- メニューアイテム（wxMenuItem）

メニューアイテムに関しては「Append」関数で間接的に構築している
※リファレンスでも「wxMenu」の関数で生成するのが普通と記載があったのでそれに倣う

```c++
menu_file->Append(ID_MENU_EXIT, "終了\tCtrl+Q");
```

「wxID_ANY」ではなく、独自定義の「ID_MENU_EXIT」なのはイベントハンドルで必要になるから

## イベントハンドリング（その１）

GUIのプログラムは基本的にイベント駆動型となる
ユーザーの操作に対してイベントが発生、何らかの処理が実行することになる
したがって、イベントと処理を紐づけ（Bind）する必要がある

具体的には以下の部分のこと

```c++
    //メニューの終了を押したらプログラム終了
    Bind(wxEVT_MENU, [=](wxCommandEvent& event)
    {
        Destroy();
    }, ID_MENU_EXIT);
```

「Bind」関数で「メニューアイテム押下」のイベントと「関数オブジェクト」を紐づけている
「ID_MENU_EXIT」を指定しているのは、どのメニューアイテムかの判別のため

関数オブジェクトの「operator()」は適切なイベント型の引数を一つ持つ必要がある
この引数にはイベント発生時の様々な情報が含まれる

※関数オブジェクトを引数で受けるので「Bind」関数はテンプレートで定義されている

## 少し複雑なメニューバー

コードは示さないが複雑なメニューも表現できる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/f8bc0b4e-8240-b5f2-1cac-a6b306957715.png)

## ステータスバー

特に難しいところはない
表示する内容を変えたい場合は適宜「SetStatusText」関数を呼び出せばいい

# 5. widgetをウィンドウ上に配置する

ちょっと長いが最後だ、頑張ろう

## ソースコード

```frame.h
#include <wx/wx.h>

class myFrame : public wxFrame
{
public:
    //基底クラスと同じ引数を持つコンストラクタ（宣言）
    myFrame
    (
        wxWindow* parent,
        wxWindowID id,
        const wxString& title,
        const wxPoint& pos = wxDefaultPosition,
        const wxSize& size = wxDefaultSize,
        long style = wxDEFAULT_FRAME_STYLE,
        const wxString& name = wxFrameNameStr
    );

private:
    wxMenuBar* menu_bar;
    wxMenu* menu_file;

    wxPanel* panel;
    wxTextCtrl* textCtrl;
    wxButton* button_uc;
    wxButton* button_lc;
};
```

```frame.cpp
#include "Frame.h"

 //基底クラスと同じ引数を持つコンストラクタ（定義）
myFrame::myFrame
(
    wxWindow* parent,
    wxWindowID id,
    const wxString& title,
    const wxPoint& pos,
    const wxSize& size,
    long style,
    const wxString& name

) : wxFrame(parent, id, title, pos, size, style, name)//基底クラスへの委譲コンストラクタ
{
    //メニューアイテムに割り当てるIDを列挙型を宣言しておく
    enum ID_MENU
    {
        ID_MENU_EXIT,
    };

    //メニューの構築
    menu_file = new wxMenu;
    menu_file->Append(ID_MENU_EXIT, "終了\tCtrl+Q");

    //メニューバーの構築とメニューバーにメニューをセット
    menu_bar = new wxMenuBar;
    menu_bar->Append(menu_file, "ファイル(&F)");

    //このWindowにメニューバーをセット
    SetMenuBar(menu_bar);

    //メニューの終了を押したらプログラム終了
    Bind(wxEVT_MENU, [=](wxCommandEvent& event)
    {
        Destroy();
    }, ID_MENU_EXIT);

    //ステータスバー
    CreateStatusBar();
    SetStatusText("ステータスバーはここ");

    //パネル（親widgetはこのthisつまりmyFrame）
    panel = new wxPanel(this, wxID_ANY);

    //テキストコントロール（親widgetはpanel）
    textCtrl = new wxTextCtrl(panel, wxID_ANY);

    //ボタン（親widgetはpanel）
    button_uc = new wxButton(panel, wxID_ANY, "UpperCase");
    button_lc = new wxButton(panel, wxID_ANY, "LowerCase");

    //サイザー（垂直方向に詰める）
    auto vsizer = new wxBoxSizer(wxVERTICAL);

    //サイザー（水平方向に詰める）
    auto hsizer = new wxBoxSizer(wxHORIZONTAL);

    //レイアウトを整える
    panel->SetSizer(vsizer);

    vsizer->Add(textCtrl, 0, wxALIGN_CENTER);
    vsizer->Add(hsizer, 0, wxALIGN_CENTER);
        hsizer->Add(button_uc, 0, wxALIGN_CENTER);
        hsizer->Add(button_lc, 0, wxALIGN_CENTER);

    //UpperCaseボタンを押したら、TextCtrlの文字列をUpperCaseする
    button_uc->Bind(wxEVT_BUTTON, [=, this](wxCommandEvent& event)
    {
        //ダイアログ（親widgetはこのthisつまりmyFrame）
        auto dialog = wxMessageDialog(this, "テキストをUpperCaseしますか？", "タイトル", wxCANCEL);

        //ダイアログを表示して、OKボタンを押したらテキストの変換を実施する
        if(dialog.ShowModal() == wxID_OK)
        {
            auto text = textCtrl->GetValue();
            text.UpperCase();
            textCtrl->SetValue(text);
        }
    });

    //LowerCaseボタンを押したら、TextCtrlの文字列をLowerCaseする
    button_lc->Bind(wxEVT_BUTTON, [=, this](wxCommandEvent& event)
    {
        //ダイアログ（親widgetはこのthisつまりmyFrame）
        auto dialog = wxMessageDialog(this, "テキストをlowerCaseしますか？", "タイトル", wxCANCEL);

        //ダイアログを表示して、OKボタンを押したらテキストの変換を実施する    
        if(dialog.ShowModal() == wxID_OK)
        {
            auto text = textCtrl->GetValue();
            text.LowerCase();
            textCtrl->SetValue(text);
        }
    });
}
```

```app.h
#include <wx/wx.h>

//wxAppの派生クラスを定義してOnInit()をオーバーライド
class myApp : public wxApp
{
public:
    virtual bool OnInit() override;
};
```
```app.cpp
#include "App.h"
#include "Frame.h"

//真のmain関数（エントリポイント）を生成するマクロ
wxIMPLEMENT_APP(myApp);

//事実上のmain関数
bool myApp::OnInit()
{
    //「カスタマイズされた」ウィンドウを生成
    auto frame = new myFrame(nullptr, wxID_ANY, "ウィンドウのタイトル");

    //ウィンドウを表示
    frame->Show();
    
    //trueでwxWidgetsのメインループへ、falseでプログラム即終了
    return true;
}
```

## コンパイル

```
 g++ -O2 -finput-charset=CP932 -fexec-charset=CP932 -static-libgcc -static-libstdc++ -mthreads -mwindows App.cpp Frame.cpp resource.o -o App.exe -I C:\wxWidgets\wxWidgets-3.2.2.1\include -I C:\wxWidgets\wxWidgets-3.2.2.1\lib\gcc_lib\mswu -L C:\wxWidgets\wxWidgets-3.2.2.1\lib\gcc_lib -lwxmsw32u -lwxmsw32u_gl -lwxscintilla -lwxtiff -lwxjpeg -lwxpng -lwxzlib -lwxregexu -lwxexpat -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lwinspool -lwinmm -lshell32 -lshlwapi -lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lversion -lws2_32 -lwininet -loleacc -luxtheme
```

## 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/e6bc532c-a555-362c-6a3e-98804963b065.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/92aea750-f07a-9cf3-8f23-f0c5756dc1e5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/3243e898-2215-fc7e-76ec-b3a39c0f518c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/5f45c047-14c6-24bc-757e-45741c527e36.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124801/b80ade88-4ead-159f-7587-97142b6f94a1.png)

## サイザー

配置された各widgetのレイアウトにはサイザーを使う
ウィンドウのサイズを変更したときなど、サイザーが追従してwidgetのレイアウトをコントロールしてくれる

```c++
    //サイザー（垂直方向に詰める）
    auto vsizer = new wxBoxSizer(wxVERTICAL);

    //サイザー（水平方向に詰める）
    auto hsizer = new wxBoxSizer(wxHORIZONTAL);

    //レイアウトを整える
    panel->SetSizer(vsizer);

    vsizer->Add(textCtrl, 0, wxALIGN_CENTER);
    vsizer->Add(hsizer, 0, wxALIGN_CENTER);
        hsizer->Add(button_uc, 0, wxALIGN_CENTER);
        hsizer->Add(button_lc, 0, wxALIGN_CENTER);
```

「wxBoxSizer」クラスは最もよく使うサイザーである
コンストラクタに「wxVERTICAL」か「wxHORIZONTAL」を渡して、widgetを詰める方向を決める

サイザーにwidgetを追加するときは「Add」関数を使う
widgetだけでなくサイザーも受け取れるので構造を入れ子にすることもできる
ここでは詳細は割愛するが第二引数以降はレイアウトに関するパラメーターで、
 - 詰める方向に対してどの割合でサイズを要求するか
 - 詰める方向の直角方向にはどちらに寄せるのか、あるいは伸長（expand）するのか
 - widgetの周りに余白はどの程度必要か
等を設定していく。

※サイザーの詳細
https://docs.wxwidgets.org/3.2/overview_sizer.html

## イベントハンドリング（その２）

ここではどのオブジェクトの「Bind」関数を呼び出しているか意識してほしい

```c++
    //LowerCaseボタンを押したら、TextCtrlの文字列をLowerCaseする
    button_lc->Bind(wxEVT_BUTTON, [=, this](wxCommandEvent& event)
    {
        //処理は省略
    });

```

親widgetの「Bind」関数ではなく、子widgetの「button_lc->Bind」関数を呼び出している
子widgetに直接紐づけているので、windowIDを指定はしていない

そもそもすべてのイベントが親widgetに伝搬するわけではない
「wxCommandEvent」は汎用的なイベントで伝搬するよう設計されているので、メニューの押下イベントを親widgetで処理することができたのである

※例えば「wxGrid」クラスはより特化した「wxGridEvent」を発生させるが、親widgetには伝搬しない

小難しいことを考えたくなければ、子widgetの「Bind」関数でイベント処理するのがいいだろう

※イベントとイベントハンドリングの詳細
https://docs.wxwidgets.org/3.2/overview_events.html

## ダイアログ

ダイアログにも触れておく

```c++
        //ダイアログ（親widgetはこのthisつまりmyFrame）
        auto dialog = wxMessageDialog(this, "テキストをlowerCaseしますか？", "タイトル", wxCANCEL);

        //ダイアログを表示して、OKボタンを押したらテキストの変換を実施する    
        if(dialog.ShowModal() == wxID_OK)
        {
            auto text = textCtrl->GetValue();
            text.LowerCase();
            textCtrl->SetValue(text);
        }
```

ここで使われている「wxMessageDialog」クラスは「wxDialog」クラスの派生クラスとなる

「ShowModal」関数でダイアログを表示する
ダイアログが閉じられるまでは親のウィンドウは操作不能になる
※「Modal」なウインドウと呼ばれる

「ShowModal」関数の戻り値はOKボタンを押したかキャンセルボタンを押したかの判定に使える
またカスタマイズしてメンバ変数を追加してそれを取得しても良い

「wxDialog」クラスから派生クラスを自分で定義してもいいが、下記のような便利なダイアログが用意されている
あるものは便利に使わせてもらおう

- wxColourDialog
- wxDirDialog
- wxFileDialog
- wxFindReplaceDialog
- wxFontDialog
- wxGenericProgressDialog
- wxProgressDialog
- wxHtmlHelpDialog
- wxMessageDialog
- wxMultiChoiceDialog
- wxNumberEntryDialog
- wxPGArrayEditorDialog
- wxPGArrayStringEditorDialog
- wxPrintAbortDialog 
- wxPropertySheetDialog
- wxRichTextFormattingDialog
- wxRearrangeDialog
- wxRichTextStyleOrganiserDialog
- wxSingleChoiceDialog
- wxSymbolPickerDialog
- wxTextEntryDialog
- wxPasswordEntryDialog
- wxWizard

※メモリとダイアログの話（ダイアログは「new」でインスタンス化してないことに気づいただろうか？）
https://docs.wxwidgets.org/3.2/page_multiplatform.html#page_multiplatform_allocatingobjects
https://wiki.wxwidgets.org/Avoiding_Memory_Leaks

# その他
- サンプルをコンパイルする
つかえそうなwidgetを探すとっかかりになる

https://qiita.com/kmatsumoto630823/items/50963ef56aac1e4c81e8

- クラスのリファレンスを読む
widgetのクラスごとにページが割かれているので必要になったら参照する
  - そのクラスの概要
  - スタイル
  - 関連するほかのクラス
  - 発生させるイベントの種類
  - publicなメンバ関数（つまり何ができるか）

※例としてwxTextCtrlのリンクを貼っておく

https://docs.wxwidgets.org/stable/classwx_text_ctrl.html

- デフォルト挙動のカスタマイズ
widgetクラスには「virtualでpublic(またはprotected)」宣言された関数がある
派生クラスでもアクセス可能なので、オーバーライドで挙動の変更ができる

- wxWidgetsの改造
↑でどうしようもなくなったら、ライブラリのコードに手を入れるしかないが・・・
ライセンス的に改造部分のソースコードを求められたら開示する義務が発生するかも？

# 参考
Programming Guides（公式ドキュメント）
https://docs.wxwidgets.org/3.2/page_topics.html

wxWidgets の最小サンプル（qiitaの記事から、非常に参考になった）
https://qiita.com/mod_poppo/items/8e6baa50765e8573f883

wxWidgets tutorial（私が最初にやったやつ、良いチュートリアルだと思う）
https://zetcode.com/gui/wxwidgets/
※ただし、イベントハンドラへの登録にBindではなく今は非推奨なConnect使ってるので注意