MinGW/MSYS での wxWidgets について †以前 WindowsでのEclipseによるC/C++プログラム開発 で wxWidgets/wxGrade を やろうとして失敗した。 今回は、wxGrade に頼らずに wxWidgets と、その application を 動かしてみる。今回の主な興味は UNICODE 対応状況をみたいということである。 かなりの予備知識が必要な気もするが、日本語まで含め、 一応すんなり動いたので、まとめておく。 Install †wxWidgets を MSYS/MinGW で install してみた。通常の(Unix-likeな)やりかた (configure;make;make install)で、すんなりできた。
今回 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 愚痴、、 †おもむろに 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 を動かす †ま、愚痴っても始まらないので、まずは、 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 を動かす †せっかく 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 あ、動いた。日本語が表示されてる。 |