zwx_helper、wxWidgetsインタフェースの開発を楽にします.
37994 ワード
c++operatorをリロードすることで、htmlでページを書くように直感的に簡単なwxWidgetsインタフェースのプログラミングスタイルを実現します.
例えば、1つのインタフェースページには4つのエリアがあり、htmlを開発する場合は、頭から足まで一気に書きます.
私の目標は、c++開発のコードを一気に書くことです.
メニューレイアウトの作成は直感的で自然で、プロセッサ関数のバインドは同時に位置しています.
理想はいつも美しくて、今現実の中のインタフェースの開発に戻って、人の目を痛めるc++コード、
1複数のコードで操作し、手順が煩雑で、複数のコードに分散しなければならない.
2レイアウトの作成は人間の思考に合わない-全体を分割して再分割するのではなく、枝の末端からフックを1層ずつ作成して上に追加します.
MFC,WTLはwxWidgetsの開発手順と類似しており,ここではwxWidgetsのみに注目し,
1ヘッダー・ファイルで、カスタム・ウィンドウ・クラス宣言イベント(ウィンドウ・メッセージ)割り当て関数.
2ソースファイルに、イベント(ウィンドウメッセージ)割り当て関数の実装マクロを追加する.
3イベント(ウィンドウメッセージ)プロセッサ関数を追加します.
3-1ヘッダー・ファイルで、カスタム・ウィンドウ・クラスとして宣言されたメンバー関数
3-2ソースファイルにおいて、この関数を実装する
3-3ソースファイルに、そのTABLEマクロにイベントid、プロセッサ関数を追加
4あるウィンドウコンテナの初期化コールバックで、イベントidに対応するサブウィンドウ/コントロールを作成し、関連するidを設定する
5しばらくしたら、コントロールのプロセッサ関数を維持します.
5-1レイアウトコードでこのコントロールを見つけ、それに関連するidを見る
5-2ソースコードでイベントを割り当てるウィンドウクラスを見つけ、そのTABLEマクロの多くのエントリの中で対応するエントリを見つけます.
5-3最終的にターゲットプロセッサ関数にナビゲート
同じことをしているのに、複数のコードファイルの中でジャンプして切り替えなければならないので、一歩漏れてもデバッグに時間を浪費してしまうので、本当にうんざりしています.
次はzwx_helperは公式layout sampleレイアウトのコードの対比を書き換えます
まず公式コード
layout.h https://github.com/wxWidgets/wxWidgets/blob/master/samples/layout/layout.h
layout.cpp https://github.com/wxWidgets/wxWidgets/blob/master/samples/layout/layout.cpp
最後は私のコード
zwx_helperはhttps://github.com/bbqz007/zhelper-wxWidgets/パブリッシュします.
例えば、1つのインタフェースページには4つのエリアがあり、htmlを開発する場合は、頭から足まで一気に書きます.
<div id='0'>
<div id='1'>
<input type="button" onclick="handler()">
div>
<div id='2'>
<input type="button" onclick="handler()">
div>
<div id='3'>
<input type="button" onclick="handler()">
div>
<div id='4'>
<input type="button" onclick="handler()">
div>
div>
私の目標は、c++開発のコードを一気に書くことです.
Frame* frame = new Frame;
layout::begin(new layout)
(layout::begin(new layout)
(new button) [ onclick = [] (event&) {} ]
(layout::end)
)
(layout::begin(new layout)
(new button) [ onclick = [] (event&) {} ]
(layout::end)
)
(layout::begin(new layout)
(new button) [ onclick = [] (event&) {} ]
(layout::end)
)
(layout::begin(new layout)
(new button) [ onclick = [] (event&) {} ]
(layout::end)
)
(layout::end, [=] (layout& layout) {
frame->SetLayout(layout);
});
メニューレイアウトの作成は直感的で自然で、プロセッサ関数のバインドは同時に位置しています.
Frame* frame = new Frame;
menu::begin(new MenuBar)
("File",
menu::begin(new Menu)
(ID_OPEN, "open", [=] (event&) { })
(ID_NEW, "new", [=] (event&) { })
(menu::end)
)
("About",
menu::begin(new Menu)
(ID_HELP, "help", [=] (event&) { })
(menu::end)
)
(menu::end, [=] (MenuBar* mb) {
frame->SetMenuBar(mb);
});
理想はいつも美しくて、今現実の中のインタフェースの開発に戻って、人の目を痛めるc++コード、
1複数のコードで操作し、手順が煩雑で、複数のコードに分散しなければならない.
2レイアウトの作成は人間の思考に合わない-全体を分割して再分割するのではなく、枝の末端からフックを1層ずつ作成して上に追加します.
MFC,WTLはwxWidgetsの開発手順と類似しており,ここではwxWidgetsのみに注目し,
1ヘッダー・ファイルで、カスタム・ウィンドウ・クラス宣言イベント(ウィンドウ・メッセージ)割り当て関数.
2ソースファイルに、イベント(ウィンドウメッセージ)割り当て関数の実装マクロを追加する.
3イベント(ウィンドウメッセージ)プロセッサ関数を追加します.
3-1ヘッダー・ファイルで、カスタム・ウィンドウ・クラスとして宣言されたメンバー関数
3-2ソースファイルにおいて、この関数を実装する
3-3ソースファイルに、そのTABLEマクロにイベントid、プロセッサ関数を追加
4あるウィンドウコンテナの初期化コールバックで、イベントidに対応するサブウィンドウ/コントロールを作成し、関連するidを設定する
5しばらくしたら、コントロールのプロセッサ関数を維持します.
5-1レイアウトコードでこのコントロールを見つけ、それに関連するidを見る
5-2ソースコードでイベントを割り当てるウィンドウクラスを見つけ、そのTABLEマクロの多くのエントリの中で対応するエントリを見つけます.
5-3最終的にターゲットプロセッサ関数にナビゲート
同じことをしているのに、複数のコードファイルの中でジャンプして切り替えなければならないので、一歩漏れてもデバッグに時間を浪費してしまうので、本当にうんざりしています.
// MyFrame.h
enum
{
ID_SOME
};
class MyFrame : public wxFrame
{
public:
void hanlde_some_event(wxEvent&);
private:
wxDECLARE_EVENT_TABLE()
}
// MyFrame.cpp
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_XXXX(ID_SOME, &MyFrame::handle_some_event)
wxEND_EVENT_TABLE()
void MyFrame::handle_some_event(wxEvent&)
{
// todo
}
MyFrame::MyFrame()
{
// ....
this->Add(new wxSomeWindow(this, ID_SOME, ...);
// ....
}
次はzwx_helperは公式layout sampleレイアウトのコードの対比を書き換えます
まず公式コード
layout.h https://github.com/wxWidgets/wxWidgets/blob/master/samples/layout/layout.h
layout.cpp https://github.com/wxWidgets/wxWidgets/blob/master/samples/layout/layout.cpp
// ----------------------------------------------------------------------------
// MyFrame
// ----------------------------------------------------------------------------
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(LAYOUT_ABOUT, MyFrame::OnAbout)
EVT_MENU(LAYOUT_QUIT, MyFrame::OnQuit)
EVT_MENU(LAYOUT_TEST_PROPORTIONS, MyFrame::TestProportions)
EVT_MENU(LAYOUT_TEST_SIZER, MyFrame::TestFlexSizers)
EVT_MENU(LAYOUT_TEST_NB_SIZER, MyFrame::TestNotebookSizers)
EVT_MENU(LAYOUT_TEST_GB_SIZER, MyFrame::TestGridBagSizer)
EVT_MENU(LAYOUT_TEST_SET_MINIMAL, MyFrame::TestSetMinimal)
EVT_MENU(LAYOUT_TEST_NESTED, MyFrame::TestNested)
EVT_MENU(LAYOUT_TEST_WRAP, MyFrame::TestWrap)
wxEND_EVENT_TABLE()
// Define my frame constructor
MyFrame::MyFrame()
: wxFrame(NULL, wxID_ANY, "wxWidgets Layout Demo")
{
SetIcon(wxICON(sample));
// Make a menubar
wxMenu *file_menu = new wxMenu;
file_menu->Append(LAYOUT_TEST_PROPORTIONS, "&Proportions demo...\tF1");
file_menu->Append(LAYOUT_TEST_SIZER, "Test wx&FlexSizer...\tF2");
file_menu->Append(LAYOUT_TEST_NB_SIZER, "Test ¬ebook sizers...\tF3");
file_menu->Append(LAYOUT_TEST_GB_SIZER, "Test &gridbag sizer...\tF4");
file_menu->Append(LAYOUT_TEST_SET_MINIMAL, "Test Set&ItemMinSize...\tF5");
file_menu->Append(LAYOUT_TEST_NESTED, "Test nested sizer in a wxPanel...\tF6");
file_menu->Append(LAYOUT_TEST_WRAP, "Test wrap sizers...\tF7");
file_menu->AppendSeparator();
file_menu->Append(LAYOUT_QUIT, "E&xit", "Quit program");
wxMenu *help_menu = new wxMenu;
help_menu->Append(LAYOUT_ABOUT, "&About", "About layout demo...");
wxMenuBar *menu_bar = new wxMenuBar;
menu_bar->Append(file_menu, "&File");
menu_bar->Append(help_menu, "&Help");
// Associate the menu bar with the frame
SetMenuBar(menu_bar);
#if wxUSE_STATUSBAR
CreateStatusBar(2);
SetStatusText("wxWidgets layout demo");
#endif // wxUSE_STATUSBAR
wxPanel* p = new wxPanel(this, wxID_ANY);
// we want to get a dialog that is stretchable because it
// has a text ctrl in the middle. at the bottom, we have
// two buttons which.
wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
// 1) top: create wxStaticText with minimum size equal to its default size
topsizer->Add(
new wxStaticText( p, wxID_ANY, "An explanation (wxALIGN_RIGHT)." ),
wxSizerFlags().Align(wxALIGN_RIGHT).Border(wxALL & ~wxBOTTOM, 5));
topsizer->Add(
new wxStaticText( p, wxID_ANY, "An explanation (wxALIGN_LEFT)." ),
wxSizerFlags().Align(wxALIGN_LEFT).Border(wxALL & ~wxBOTTOM, 5));
topsizer->Add(
new wxStaticText( p, wxID_ANY, "An explanation (wxALIGN_CENTRE_HORIZONTAL)." ),
wxSizerFlags().Align(wxALIGN_CENTRE_HORIZONTAL).Border(wxALL & ~wxBOTTOM, 5));
// 2) top: create wxTextCtrl with minimum size (100x60)
topsizer->Add(
new wxTextCtrl( p, wxID_ANY, "My text (wxEXPAND).", wxDefaultPosition, wxSize(100,60), wxTE_MULTILINE),
wxSizerFlags(1).Expand().Border(wxALL, 5));
// 2.5) Gratuitous test of wxStaticBoxSizers
wxBoxSizer *statsizer = new wxStaticBoxSizer(
new wxStaticBox(p, wxID_ANY, "A wxStaticBoxSizer"), wxVERTICAL );
statsizer->Add(
new wxStaticText(p, wxID_ANY, "And some TEXT inside it"),
wxSizerFlags().Border(wxALL, 30));
topsizer->Add(
statsizer,
wxSizerFlags(1).Expand().Border(wxALL, 10));
// 2.7) And a test of wxGridSizer
wxGridSizer *gridsizer = new wxGridSizer(2, 5, 5);
gridsizer->Add(new wxStaticText(p, wxID_ANY, "Label"),
wxSizerFlags().Align(wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL));
gridsizer->Add(new wxTextCtrl(p, wxID_ANY, "Grid sizer demo"),
wxSizerFlags(1).Align(wxGROW | wxALIGN_CENTER_VERTICAL));
gridsizer->Add(new wxStaticText(p, wxID_ANY, "Another label"),
wxSizerFlags().Align(wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL));
gridsizer->Add(new wxTextCtrl(p, wxID_ANY, "More text"),
wxSizerFlags(1).Align(wxGROW | wxALIGN_CENTER_VERTICAL));
gridsizer->Add(new wxStaticText(p, wxID_ANY, "Final label"),
wxSizerFlags().Align(wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL));
gridsizer->Add(new wxTextCtrl(p, wxID_ANY, "And yet more text"),
wxSizerFlags().Align(wxGROW | wxALIGN_CENTER_VERTICAL));
topsizer->Add(
gridsizer,
wxSizerFlags().Proportion(1).Expand().Border(wxALL, 10));
#if wxUSE_STATLINE
// 3) middle: create wxStaticLine with minimum size (3x3)
topsizer->Add(
new wxStaticLine( p, wxID_ANY, wxDefaultPosition, wxSize(3,3), wxHORIZONTAL),
wxSizerFlags().Expand());
#endif // wxUSE_STATLINE
// 4) bottom: create two centred wxButtons
wxBoxSizer *button_box = new wxBoxSizer( wxHORIZONTAL );
button_box->Add(
new wxButton( p, wxID_ANY, "Two buttons in a box" ),
wxSizerFlags().Border(wxALL, 7));
button_box->Add(
new wxButton( p, wxID_ANY, "(wxCENTER)" ),
wxSizerFlags().Border(wxALL, 7));
topsizer->Add(button_box, wxSizerFlags().Center());
p->SetSizer( topsizer );
// don't allow frame to get smaller than what the sizers tell it and also set
// the initial size as calculated by the sizers
topsizer->SetSizeHints( this );
}
最後は私のコード
std::shared_ptr sptr_delegate;
bool MyApp::OnInit()
{
if (!wxApp::OnInit())
return false;
MyFrame* frame = new MyFrame;
sptr_delegate = std::shared_ptr(new MyFrameDelegate(frame));
MyFrameDelegate* delegate = sptr_delegate.get();
wxPanel* p = new wxPanel((wxWindow*)frame, wxID_ANY);
wxMenuBar* mb =
menu::begin(new wxMenuBar)
("&File",
menu::begin(new wxMenu)
(LAYOUT_TEST_PROPORTIONS, "&Proportions demo...\tF1", &MyFrame::TestMenuCommand, frame)
(LAYOUT_TEST_SIZER, "Test wx&FlexSizer...\tF2", &MyFrame::TestMenuCommand, frame)
(LAYOUT_TEST_NB_SIZER, "Test ¬ebook sizers...\tF3", &MyFrame::TestMenuCommand, frame)
(LAYOUT_TEST_GB_SIZER, "Test &gridbag sizer...\tF4", frame, [=](wxCommandEvent& event) { frame->TestMenuCommand(event); })
(LAYOUT_TEST_SET_MINIMAL, "Test Set&ItemMinSize...\tF5")
(LAYOUT_TEST_NESTED, "Test nested sizer in a wxPanel...\tF6", frame, [=](wxCommandEvent& event) { sptr_delegate->TestMenuCommand(event); })(LAYOUT_TEST_WRAP, "Test wrap sizers...\tF7")
(menu::end))
("&Help",
menu::begin(new wxMenu)
(LAYOUT_ABOUT, "&About", "About layout demo...")
(menu::end))
("level-tree",
menu::begin(new wxMenu)
(wxID_ANY, "level-1.1",
menu::begin(new wxMenu)
(wxID_ANY, "level-1.1-level-2.1")
(wxID_ANY, "level-1.1-level-2.2")
(menu::end))
(wxID_ANY, "level-1.2",
menu::begin(new wxMenu)
(wxID_ANY, "level-1.2-level-2.1")
(wxID_ANY, "level-1.2-level-2.2")
(menu::end))
(menu::end))
(menu::end,
[=](wxMenuBar* mb) {
frame->SetMenuBar(mb);
});
layout::begin(new wxBoxSizer(wxVERTICAL))
// 1) top: create wxStaticText with minimum size equal to its default size
(new wxStaticText( p, wxID_ANY, "An explanation (wxALIGN_RIGHT)." ),
wxSizerFlags().Align(wxALIGN_RIGHT).Border(wxALL & ~wxBOTTOM, 5))
(new wxStaticText( p, wxID_ANY, "An explanation (wxALIGN_LEFT)." ),
wxSizerFlags().Align(wxALIGN_LEFT).Border(wxALL & ~wxBOTTOM, 5))
(new wxStaticText( p, wxID_ANY, "An explanation (wxALIGN_CENTRE_HORIZONTAL)." ),
wxSizerFlags().Align(wxALIGN_CENTRE_HORIZONTAL).Border(wxALL & ~wxBOTTOM, 5))
// 2) top: create wxTextCtrl with minimum size (100x60)
(new wxTextCtrl( p, wxID_ANY, "My text (wxEXPAND).", wxDefaultPosition, wxSize(100,60), wxTE_MULTILINE),
wxSizerFlags(1).Expand().Border(wxALL, 5))
// 2.5) Gratuitous test of wxStaticBoxSizers
(layout::begin(new wxStaticBoxSizer(new wxStaticBox(p, wxID_ANY, "A wxStaticBoxSizer"), wxVERTICAL))
(new wxStaticText(p, wxID_ANY, "And some TEXT inside it"), wxSizerFlags().Border(wxALL, 30))
(layout::end), wxSizerFlags(1).Expand().Border(wxALL, 10))
// 2.7) And a test of wxGridSizer
(layout::begin(new wxGridSizer(2, 5, 5))
(new wxStaticText(p, wxID_ANY, "Label"),
wxSizerFlags().Align(wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL))
(new wxTextCtrl(p, wxID_ANY, "Grid sizer demo"),
wxSizerFlags(1).Align(wxGROW | wxALIGN_CENTER_VERTICAL))
(new wxStaticText(p, wxID_ANY, "Another label"),
wxSizerFlags().Align(wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL))
(new wxTextCtrl(p, wxID_ANY, "More text"),
wxSizerFlags(1).Align(wxGROW | wxALIGN_CENTER_VERTICAL))
(new wxStaticText(p, wxID_ANY, "Final label"),
wxSizerFlags().Align(wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL))
(new wxTextCtrl(p, wxID_ANY, "And yet more text"),
wxSizerFlags().Align(wxGROW | wxALIGN_CENTER_VERTICAL))
(layout::end), wxSizerFlags().Proportion(1).Expand().Border(wxALL, 10))
#if wxUSE_STATLINE
// 3) middle: create wxStaticLine with minimum size (3x3)
(new wxStaticLine( p, wxID_ANY, wxDefaultPosition, wxSize(3,3), wxHORIZONTAL),
wxSizerFlags().Expand())
#endif // wxUSE_STATLINE
// 4) bottom: create two centred wxButtons
(layout::begin(new wxBoxSizer( wxHORIZONTAL ))
(new wxButton( p, wxID_ANY, "Two buttons in a box" ),
wxSizerFlags().Border(wxALL, 7))[onclick = [=](wxCommandEvent& e) { delegate->OnClick(e); } ]
(new wxButton( p, wxID_ANY, "(wxCENTER)" ),
wxSizerFlags().Border(wxALL, 7))
(layout::end), wxSizerFlags().Center())
(layout::end,
[=](wxSizer* s) {
p->SetSizer(s);
s->SetSizeHints(frame);
});
frame->Show(true);
return true;
}
zwx_helperはhttps://github.com/bbqz007/zhelper-wxWidgets/パブリッシュします.