上記の手順で作成した環境を前提とし、以下も実施済みとする
- 以下のビルドコマンドで静的ライブラリのビルド
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」関数が実質的なコードの起点となる
ソースコード
#include <wx/wx.h>
//wxAppの派生クラスを定義してOnInit()をオーバーライド
class myApp : public wxApp
{
public:
virtual bool OnInit() override;
};
#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
実行結果
真のエントリポイントはどこか?
wxWidgetsで最初にやることをまとめると次の通り
- 「wxApp」クラスの派生クラスをつくる
- 「OnInit」関数をオーバーライドしてやりたい処理を書く
- 定義した派生クラスを「wxIMPLEMENT_APP」マクロに渡す
あとはwxWidgets側で「OnInit」関数を最初に実行してくれる
真のエントリポイントは「wxIMPLEMENT_APP」マクロによって定義をされる
※参考までに自分の環境で「wxIMPLEMENT_APP」マクロをVSCodeに展開してもらった結果
2. wxFrame
ここではウィンドウを取り扱う
wxWidgetsでは「wxFrame」クラスが最も基本的なウィンドウとなる
また、widgetsクラスのコンストラクタで(おおむね)共通である第一引数・第二引数にも触れる
ついでにWindowIDの取り扱いも解説しておく
ソースコード
#include <wx/wx.h>
//wxAppの派生クラスを定義してOnInit()をオーバーライド
class myApp : public wxApp
{
public:
virtual bool OnInit() override;
};
#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
実行結果
widgetクラスのコンストラクタ
下記は「wxFrame」クラスのコンストラクタである
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
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」クラスを継承した派生クラスを定義する
この派生クラスの定義がオリジナルプログラムの第一歩となる
ソースコード
#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:
//今後のカスタマイズで必要があればここにメンバの追加
};
#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)//基底クラスへの委譲コンストラクタ
{
//今後ここにカスタマイズの処理を入れる予定
}
#include <wx/wx.h>
//wxAppの派生クラスを定義してOnInit()をオーバーライド
class myApp : public wxApp
{
public:
virtual bool OnInit() override;
};
#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
実行結果
派生・継承によるwidgetクラスのカスタマイズ
「wxFrame」クラスを継承した「myFrame」派生クラスは基底クラスと同じ動作をするだけだが、以降の解説ではこのコードをひな形としてカスタマイズを入れていく
「wxFrame」クラスに限らずwidgetクラスのカスタマイズは継承によるポリモーフィズムによって実現できる
内部的に使われる関数であっても「オーバーライド可能な仮想関数」であればデフォルトの挙動を変えられる
4. メニューバーとステータスバー
「wxFrame」クラスにはメニューバーとステータスバーを追加することができる
※一応ツールバーもあるが割愛
メニューバーのアイテムには構築の都合上「wxID_ANY」ではなく明示的にWindowIDを割り当てる
また、イベントハンドルについても解説する
ソースコード
#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;
};
#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("ステータスバーはここ");
}
#include <wx/wx.h>
//wxAppの派生クラスを定義してOnInit()をオーバーライド
class myApp : public wxApp
{
public:
virtual bool OnInit() override;
};
#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
実行結果
メニューの構成要素
メニュバーを構成する要素は次の通り
- メニューバー(wxMenuBar)
- メニュー(wxMenu)
- メニューアイテム(wxMenuItem)
メニューアイテムに関しては「Append」関数で間接的に構築している
※リファレンスでも「wxMenu」の関数で生成するのが普通と記載があったのでそれに倣う
menu_file->Append(ID_MENU_EXIT, "終了\tCtrl+Q");
「wxID_ANY」ではなく、独自定義の「ID_MENU_EXIT」なのはイベントハンドルで必要になるから
イベントハンドル(その1)
GUIのプログラムは基本的にイベント駆動型となる
ユーザーの操作に対してイベントが発生、何らかの処理が実行されることになる
したがって、イベントと処理を紐づけ(Bind)する必要がある
具体的には以下の部分
//メニューの終了を押したらプログラム終了
Bind(wxEVT_MENU, [=](wxCommandEvent& event)
{
Destroy();
}, ID_MENU_EXIT);
「Bind」関数で「メニューアイテム押下」のイベントと「関数オブジェクト」を紐づけている
「ID_MENU_EXIT」を指定しているのは、どのメニューアイテムかの判別のため
関数オブジェクトの引数は適切なイベントの型を一つ持つ必要がある
この引数にはイベント発生時の様々な情報が含まれる
※関数オブジェクトを引数で受けるので「Bind」関数はテンプレートで定義されている
少し複雑なメニューバー
コードは示さないが複雑なメニューも表現できる
ステータスバー
特に難しいところはない
表示する内容を変えたい場合は適宜「SetStatusText」関数を呼び出せばいい
5. widgetをウィンドウ上に配置する
ちょっと長いが最後だ、頑張ろう
ソースコード
#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;
};
#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);
}
});
}
#include <wx/wx.h>
//wxAppの派生クラスを定義してOnInit()をオーバーライド
class myApp : public wxApp
{
public:
virtual bool OnInit() override;
};
#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
実行結果
サイザー
widgetのレイアウトにはサイザーを使う
ウィンドウのサイズを変更したときなど、サイザーが追従してwidgetのレイアウトをコントロールしてくれる
//サイザー(垂直方向に詰める)
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だけでなくサイザーも受け取れるので構造を入れ子にすることもできる
第二引数以降はレイアウトに関するパラメーターだがここでは割愛する
※サイザーの詳細
https://docs.wxwidgets.org/3.2/overview_sizer.html
イベントハンドル(その2)
ここではどのオブジェクトの「Bind」関数を呼び出しているか意識してほしい
//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
ダイアログ
ダイアログにも触れておく
//ダイアログ(親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を探す上で役立つ
- ドキュメントの読み方
widgetのクラスごとにページが割かれているので必要になったら読みに行く- そのクラスの概要
- スタイル
- 関連するほかのクラス
- 発生させるイベントの種類
- publicなメンバ関数(つまり何ができるか)
※例としてwxTextCtrlのリンクを貼っておく
-
widgetのカスタマイズ
widgetクラスには「virtualかつpublic」または「virtualかつ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使ってるので注意