[[Hirofumi Fujii Start Page]] * MinGW/MSYS での wxWidgets について [#kfeafdf7] 以前 [[WindowsでのEclipseによるC/C++プログラム開発]] で wxWidgets/wxGrade を やろうとして失敗した。 今回は、wxGrade に頼らずに wxWidgets と、その application を 動かしてみる。今回の主な興味は UNICODE 対応状況をみたいということである。 かなりの予備知識が必要な気もするが、日本語まで含め、 一応すんなり動いたので、まとめておく。 * Install [#t27e7891] ** Install [#t27e7891] wxWidgets を MSYS/MinGW で install してみた。通常の(Unix-likeな)やりかた (configure;make;make install)で、すんなりできた。 - wxWidgets-2.8.10 - gcc 3.4.5 (mingw-vista special r3) 今回 install した machine は、733MHz 512K RAM Windows-2000(SP4) という 構成であるが configure に 約7分、make に約1時間10分、make install に約2分であった。 samples のいくつかも make してみたが、こちらもすんなり動いた。 が、、よく見たら、Unicode を enable にしてなかった。 というわけで、2009-09-14 Unicode を enable にして再 install。 ../configure --prefix="/mingw" --with-msw --enable-unicode --disable-shared ** 愚痴、、 [#md85e4ba] おもむろに sample を見てみたが、、 これ、Microsoft Foundation Class (MFC) を base にしてるみたいだ。 MFC は古くから(Windows 3.1 ぐらいから?)提供されているもので、 互換性を可能な限り保ったまま進化してきているので、今の C++ の 感覚からすると、ひどく古い感じがする(better C と言ったところか、、)。 まあ、これはもう一段 wrap すればよいと言えばよいのだが、、。 もう一つの問題は、今なら STL を使うところを全部自前でやっている点。 せっかく STL を使おうと思っても、こちらも、もう 一段 wrap しなければ 使えない。std::string 対応の wxString などは、80% 互換性を達している とのことらしいが、80% だろうが、90% だろうが、99.999% だろうが 互換で無い部分がある以上、user は気を使って wrap しなければならない。 std::iostream もしかり。 それに、wxString は Unicode 版か ANSI 版かで異なる。これも Microsoft の古くからの手法であるが、単一言語を扱うならともかく、 多国語対応にしようとすると、内部的には Unicode (あるいは もっと大きな set )にして、読み込む相手言語や encode 方法に より std::string と std::wstring を使いわけるなどということが 頻繁に生じる。つまり、std::string 、std::wstring どちらか一方で 済むというものではない。 と思ったが、configure option に enable-std_string とか enable-std_iostream とかある。これも付けておもむろに、、と思ったら、どうやら、これが default らしい。[2009-09-14 記] また、namespace を使っていない、MACRO が多用されているのも問題。 名前や MACRO が global space に置かれてしまうと、例えば他の library との衝突が起こった時、それを回避するのが非常に困難になる。 wxWidgets の application は他の library を一切使うなというなら 話は別だが。 というわけで、ちょっと wxWidgets application を書く意欲がかなり 低下中。 ** 自前の application を動かす [#t9e2adf8] ま、愚痴っても始まらないので、まずは、 http://www.wxwidgets.org/docs/tutorials/hello.htm を動かしてみる。 書かれている通りに hworld.cpp を作る。 // hworld.cpp #include <wx/wx.h> class MyApp: public wxApp { virtual bool OnInit(); }; class MyFrame: public wxFrame { public: MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); DECLARE_EVENT_TABLE() }; enum { ID_Quit = 1, ID_About, }; BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(ID_Quit, MyFrame::OnQuit) EVT_MENU(ID_About, MyFrame::OnAbout) END_EVENT_TABLE() IMPLEMENT_APP(MyApp) bool MyApp::OnInit() { MyFrame* frame = new MyFrame( _T("Hello World"), wxPoint(50,50), wxSize(450,340)); frame->Show(TRUE); SetTopWindow(frame); return true; } MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame((wxFrame*)0, -1, title, pos, size) { wxMenu* menuFile = new wxMenu; menuFile->Append(ID_About, _T("&About...")); menuFile->AppendSeparator(); menuFile->Append(ID_Quit, _T("E&xit")); wxMenuBar* menuBar = new wxMenuBar; menuBar->Append(menuFile, _T("&File")); SetMenuBar(menuBar); CreateStatusBar(); SetStatusText(_("Welcome to wxWidgets!")); } void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) { Close(true); } void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { wxMessageBox(_T("This is a wxWidgets Hello world sample"), _T("About Hello World"), wxOK | wxICON_INFORMATION, this); } 次に書かれている通りに g++ hworld.cpp `wx-config --libs` `wx-config --cxxflags` -o hworld としてみる。おお、できた。 ./hworld おお、動いた。 が、ちょっと待て。この wx-cofig は、option で指定された 文字列を打ち出すもので、wxWidgets を install した各種 path やら 必要な library やらを打ち出してくる。で、よく見ると -lwsock32 となって いる!これは古い WINSOCK だ。configure で --disable-socket とか するべきだったか、、 ** 自前の日本語 application を動かす [#oe786d27] せっかく UNICODE 対応、std::string 対応で install した(はずな)ので、 一部日本語を入れてみる。UNICODE 対応なので、UNICODE を直接そのまま入れれば 表示できるはずである。また、wxString は(多分)std::wstring と等価に なるように設計されているのではないかと想像されるので、wxString を引数と しているところに std::wstring を入れる。というわけで、いささか強引では あるが、、 // jworld.cpp #include <wx/wx.h> #include <string> class MyApp: public wxApp { virtual bool OnInit(); }; class MyFrame: public wxFrame { public: MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); DECLARE_EVENT_TABLE() }; enum { ID_Quit = 1, ID_About, }; BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(ID_Quit, MyFrame::OnQuit) EVT_MENU(ID_About, MyFrame::OnAbout) END_EVENT_TABLE() IMPLEMENT_APP(MyApp) bool MyApp::OnInit() { MyFrame* frame = new MyFrame( _T("Hello World"), wxPoint(50,50), wxSize(450,340)); frame->Show(TRUE); SetTopWindow(frame); return true; } MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame((wxFrame*)0, -1, title, pos, size) { wxMenu* menuFile = new wxMenu; menuFile->Append(ID_About, _T("&About...")); menuFile->AppendSeparator(); menuFile->Append(ID_Quit, _T("E&xit")); std::wstring menutitle; menutitle.push_back((wchar_t)0x30d5); menutitle.push_back((wchar_t)0x30a1); menutitle.push_back((wchar_t)0x30a4); menutitle.push_back((wchar_t)0x30eb); wxMenuBar* menuBar = new wxMenuBar; menuBar->Append(menuFile, menutitle); SetMenuBar(menuBar); CreateStatusBar(); std::wstring msg; msg.append(_T("wxWidgets ")); msg.push_back((wchar_t)0x306b); msg.push_back((wchar_t)0x3088); msg.push_back((wchar_t)0x3046); msg.push_back((wchar_t)0x3053); msg.push_back((wchar_t)0x305d); msg.push_back((wchar_t)0x0021); SetStatusText(msg); } void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) { Close(true); } void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { wxMessageBox(_T("This is a wxWidgets Hello world sample"), _T("About Hello World"), wxOK | wxICON_INFORMATION, this); } で、上と同様に g++ jworld.cpp `wx-config --libs` `wx-config --cxxflags` -o jworld としてみる。あ、できた。 ./jworld あ、動いた。日本語が表示されてる。