wxWidgetsを使ったGUI版HTTPクライアント
ようやくGUI版HTTPクライアントが完成した。本当はこの前使ったReadHtmlを組み込んで使うつもりだったんだけど、wxWidgetsにWinInetを組み入れるとエラーが出てどうにもならんかった(※まあマルチプラットフォームとは言えどもUNIX中心に開発された言語だからかも)。で、実際そんなことをする必要はなくて、もともとwxURLとかいうクラスがあるんで割と簡単にHTTPを使った通信ができるようだ。そこはかとなくJavaに近いような…。それにしてもクソみたいに読みにくいコード&エラー処理がない…なのでまたコメントなどを書き足したい。
/* * Main.cpp * * Created on: 2011/06/26 * Author: Nantonaku-Shiawase */ #include "Main.h" #include "WxBrowserFrame.h" IMPLEMENT_APP(MyApp) bool MyApp::OnInit() { WxBrowserFrame *wxbrowserframe = new WxBrowserFrame(wxT("WxBrowserFrame")); wxbrowserframe->Show(true); return true; }
/* * Main.h * * Created on: 2011/06/26 * Author: Nantonaku-Shiawase */ #ifndef MAIN_H_ #define MAIN_H_ #include <wx/wx.h> class MyApp : public wxApp { public: virtual bool OnInit(); }; #endif /* MAIN_H_ */
/* * WxBrowserFrame.cpp * * Created on: 2011/06/26 * Author: Nantonaku-Shiawase */ #include "iostream" #include "WxBrowserFrame.h" using namespace std; WxBrowserFrame::WxBrowserFrame(const wxString& title) : wxFrame(NULL, -1, title, wxPoint(-1, -1), wxSize(640, 480)) { wxPanel *panel = new wxPanel(this, -1); wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); //hbox1 説明ラベルとURL入力欄 wxBoxSizer *hbox1 = new wxBoxSizer(wxHORIZONTAL); wxStaticText *st1 = new wxStaticText(panel, wxID_ANY, wxT("Input URL Here")); hbox1->Add(st1, 0, wxRIGHT, 8); //外部からアクセスできるようにprotectedで宣言 m_tc = new wxTextCtrl(panel, wxID_ANY); hbox1->Add(m_tc, 1); vbox->Add(hbox1, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 10); vbox->Add(-1, 10); //hbox2 ラベル部分 wxBoxSizer *hbox2 = new wxBoxSizer(wxHORIZONTAL); wxStaticText *st2 = new wxStaticText(panel, wxID_ANY, wxT("HTML Sources")); hbox2->Add(st2, 0); vbox->Add(hbox2, 0, wxLEFT | wxTOP, 10); vbox->Add(-1, 10); //hbox3 HTML文表示部分 wxBoxSizer *hbox3 = new wxBoxSizer(wxHORIZONTAL); //外部からアクセスできるようにprotectedで宣言 m_tc2 = new wxTextCtrl(panel, wxID_ANY, wxT(""), wxPoint(-1, -1), wxSize(-1, -1), wxTE_MULTILINE); hbox3->Add(m_tc2, 1, wxEXPAND); vbox->Add(hbox3, 1, wxLEFT | wxRIGHT | wxEXPAND, 10); vbox->Add(-1, 25); //hbox 5 ボタン配置部分 wxBoxSizer *hbox5 = new wxBoxSizer(wxHORIZONTAL); //ボタン1はOK HTTPクライアントを起動させる wxButton *btn1 = new wxButton(panel, wxID_GETHTTP, wxT("Ok")); hbox5->Add(btn1, 0); //ボタン2はクローズ アプリケーションを終了させる wxButton *btn2 = new wxButton(panel, wxID_EXIT, wxT("Close")); hbox5->Add(btn2, 0, wxLEFT | wxBOTTOM, 5); vbox->Add(hbox5, 0, wxALIGN_RIGHT | wxRIGHT, 10); panel->SetSizer(vbox); Centre(); } void WxBrowserFrame::OnButtonQuit(wxCommandEvent& WXUNUSED(event)) { Close(true); } void WxBrowserFrame::OnButtonGetHttp(wxCommandEvent& WXUNUSED(event)) { wxString inputURL = m_tc->GetValue(); wxURL url(inputURL); wxInputStream* readHtml = url.GetInputStream(); wxTextInputStream in(*readHtml); wxString HTTPtext; while (readHtml->CanRead()) { HTTPtext += in.ReadLine(); } delete readHtml; m_tc2->SetValue(HTTPtext); } BEGIN_EVENT_TABLE(WxBrowserFrame, wxFrame) //ボタン1はOK HTTPクライアントを起動させる EVT_BUTTON(wxID_EXIT, WxBrowserFrame::OnButtonQuit) //ボタン2はクローズ アプリケーションを終了させる EVT_BUTTON(wxID_GETHTTP, WxBrowserFrame::OnButtonGetHttp) END_EVENT_TABLE()
/* * WxBrowserFrame.h * * Created on: 2011/06/26 * Author: Nantonaku-Shiawase */ #ifndef WXBROWSERFRAME_H_ #define WXBROWSERFRAME_H_ #include <wx/wx.h> #include <wx/url.h> #include <wx/stream.h> #include <wx/txtstrm.h> // control ids enum { wxID_GETHTTP }; class WxBrowserFrame : public wxFrame { public: WxBrowserFrame(const wxString& title); void OnButtonQuit(wxCommandEvent& event); void OnButtonGetHttp(wxCommandEvent& event); protected: //URL入力用文字列 wxTextCtrl *m_tc; //HTTP文出力用文字列 wxTextCtrl *m_tc2; private: DECLARE_EVENT_TABLE() }; #endif /* WXBROWSERFRAME_H_ */
# Makefile CC = gcc CXX = $(shell wx-config --cxx) TARGET = WxBrowser OBJECTS = Main.o WxBrowserFrame.o # all : $(TARGET) $(TARGET) : $(OBJECTS) $(CXX) $(OBJECTS) -o $(TARGET) `wx-config --cxxflags --libs` WxBrowserFrame.o : WxBrowserFrame.h $(CXX) -c WxBrowserFrame.cpp `wx-config --cxxflags --libs` Main.o : Main.h WxBrowserFrame.h $(CXX) -c Main.cpp `wx-config --cxxflags --libs` .PHONY: clean clean: rm -f *.o
wxWidgets続き
First programs in wxWidgets
ここを見ながら初めてのwxWidgetsをやってみる。開発環境をDEVC++にしようとしたんだが、プロジェクトを作って開くたびにエラーが出て嫌な感じなのでeclipse CDTでMakefileを書いて作る(IDEとはなんだったのか…)。
自分が書いたやつはこんな感じ。またまたHttpClientを作りたいので、最終的な実行ファイルの名前がwxHttpClient.exe。(アイコンを読み込む段階で躓いてるので完成はしてないが…)
# Makefile CC = gcc CXX = $(shell wx-config --cxx) TARGET = wxHttpClient OBJECTS = main.o frame.o # all : $(TARGET) $(TARGET) : $(OBJECTS) $(CXX) $(OBJECTS) -o $(TARGET) `wx-config --cxxflags --libs` frame.o : frame.h $(CXX) -c frame.cpp `wx-config --cxxflags --libs` main.o : main.cpp main.h frame.h Tutorial.xpm $(CXX) -c main.cpp `wx-config --cxxflags --libs`
wxWidgetsでの日本語の表示
追記:2012/01/23 現在wxWidgetsはソースをUTF-8で書けば日本語をそのままwxStringに入れることができます。よって以下の記述はアプリケーションの国際化のためだと思ってください。国際化ってのはひとつのアプリケーションで英語、ドイツ語、フランス語バージョンを作れるってことね。
===
さて、wxWidgets自体は導入できたが、アプリケーションに日本語を表示させるにはどうしたらよいのか。以下のサイトを見ると、その工程がめんどくさいことだけはわかる。
wxWidgetsでの国際化(翻訳) | あるデベロッパーの空間
プログラミング/C_C++/wxWidgets/多国語対応にしてみる - Flightless wing
とにかくそのままでは日本語を表示できないので、
たとえば一番簡単なHelloWorldのコードなら「_T("Minimal wxWidgets App")」→「_("Minimal wxWidgets App")」と編集して
$ xgettext --from-code=utf-8 -k"_" minimal.cpp //messages.poができる
$ msginit --locale=ja --input=messages.po //ja.poができる。適当なエディタ編集
※xgettextを使うにはgettextが必要。まず最初にmsysのsourceforgeで配布されてるバイナリを使おうとしたんだが、依存関係の欠如でうまくいかなかった。じゃあソースからコンパイルできるのかってことで、やってみたけどこれがまたキツイ。0.17はバグがあるので手直しが必要。gettextをMinGWだけでコンパイルすることはできるんかね…?。公式のREADMEにmno-cygwinオプションを使ってconfigureするよう書いてある。gettextにはlibiconvが必要なので、もしgettextをソースからコンパイルする場合はiconvをまず作らなければいけない(…はず?)。自分は諦めてcygwinからxgettextを使った。cygwinの最初のセットアップでgettextのパッケージを入れておいたので普通に使えた。(もちろんcygwinとmsysをいちいち起動するのではなく、環境変数にcygwinを追加しておくのですよ。。。)
2011/09/03追記:xgettextはmingwのパッケージにちゃんと含まれている。ビルドしなくてもよい。
"Content-Type: text/plain; charset=ASCII\n" → "Content-Type: text/plain; charset=UTF-8\n"
#: minimal.cpp:35
msgid "hello, world!"
msgstr "こんにちは、世界!"
※ja.poを編集したあとファイルの文字コードをUTF-8に変えるのだが、その時にファイルの先頭にバイナリ単位でゴミが混じる。バイナリエディタでその部分を削る必要がある。
※追記:私はTeraPadを使っているのだが、保存時にUTF-8とUTF-8Nを選べる。普通のUTF-8にはファイルの先頭に目印となるコードがつくらしい(参考:utf8とutf8Nって? (タスクマザー))。こいつがmsgfmtを使う際に邪魔になる。この現象に困っているのは日本人だけではないことがググッたらわかるのだが…とりあえずUTF-8Nで保存しておけばいいでしょう。
試しにここプログラミング/C_C++/wxWidgets/多国語対応にしてみる - Flightless wingにあるコードをちょっといじって
$ msgfmt ja.po -o minimal.mo
あとはコードの中で指定した位置にminimal.moを置いてコンパイルすればいけるはず。
ここまでの行程はMinGW/MSYS での wxWidgets について - PukiWikiここにも書いているように、最初のwxWidgetsのコンパイルの際に --enable-unicodeを指定しておく必要があると思う。