初歩の初歩、ウィンドウの表示を行なうプログラムを書きたいと思います。
とは言え、wxWidgets ライブラリを使う場合の基本的なことがわかると思うので、コードの意味を考えながら、プログラムの動きを見てください。
このページで登場する wxWidgets のクラスは、以下の 3 つです。
- wxApp (アプリケーションに関するクラス, CUI・GUI 関係なく、wxWidgets を使う場合は必要)
- wxFrame (ウィンドウに関するクラス)
- wxEvent (マウスクリック・キーボード操作などのイベントに関するクラス)
クラスのメソッドについては後々触れますので、「こんなクラスが登場する」ということだけ頭に入れてください。
それではソースコードです。
まあ、sample ディレクトリにある「minimal」のコードからさらに削っただけですが。
wx1_1.h (wx1_1.cpp のヘッダファイル)
[表示・非表示]
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
|
/* wxWidgets関連 */
#include <wx/wxprec.h>
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
// 前方参照用
class myApp;
class myFrame;
class myApp : public wxApp
{
public:
virtual bool OnInit();
private:
myFrame* frame;
};
class myFrame : public wxFrame
{
public:
myFrame(const wxString& title) : wxFrame(NULL, -1, title)
{
Show(true);.
}
};
|
wx1_1.cpp (「Window Test」という題名の空ウィンドウを表示)
[表示・非表示]
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
|
#include "wx1_1.h"
// main 関数の代わり
IMPLEMENT_APP(myApp)
bool myApp::OnInit()
{
if ( !wxApp::OnInit() )
return false;
// ウィンドウの作成
frame = new myFrame("Window Test");
return true;
}
|
実行結果はこちら

それじゃまあ、重要なマクロ, メソッドを紹介します。
- virtual bool wxAppConsole::OnInit()
wxApp の基底クラス、wxAppConsole のメソッド。
必ず用意する必要があり、この中でアプリケーションのメインウィンドウを作成したり、SetTopWindow メソッド(最上面のウィンドウを設定する関数)を呼び出したりする。
true が返された場合、プログラムは続行され, false が返された場合、プログラムは即座に終了する。
- virtual bool wxWindow::Show(bool show = true)
show が true ならウィンドウを表示, false ならウィンドウを隠す。
最前面にウィンドウを持ってきたい場合 Raise() が必要になる場合もあるが、ウィンドウ作成後すぐに Show() を呼んだならその必要はない。
ウィンドウの可視状態が変更されたら true, 既に変更済みであったら false が返される。
wxFrame::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)
wxFrame のコンストラクタ。parent には 親ウィンドウのポインタを渡す。
プログラム開始時はウィンドウが存在しないので、通常は NULL を渡すと思われるが、NULL でないものを渡した場合、常に親ウィンドウの全面に表示されるようになる。
id には、ウィンドウを識別するための番号を渡す。デフォルト値として -1 を取ることが出来る。
title は、ウィンドウのタイトルバーに表示される文字列を指定する。Unicode のソースファイルを用いてコンパイルしている場合、wxWidgets 2.9 以降なら日本語も普通に使える。
pos はモニタ左上を原点とする、ウィンドウの表示位置, size はウィンドウの寸法。
どちらとも、指定しない場合はデフォルトの設定が使われる。
style はウィンドウの見た目, 出来る操作などを指定する。使う設定を表す定数を「|」で区切って横に並べていく。
name はウィンドウの名称。
style に指定できる主な定数(それ以外の定数については、こちらやこちらの「Styles」の項を参照)
定数名 | 意味 |
wxDEFAULT_FRAME_STYLE | wxCAPTION, wxSYSTEM_MENU, wxMINIMIZE_BOX, wxMAXIMIZE_BOX, wxCLOSE_BOX, wxRESIZE_BORDER, wxCLIP_CHILDREN を有効にする |
wxCAPTION | ウィンドウの枠とタイトルバーを表示 (最小化・最大化ボタン, 「閉じる」ボタンを表示したいなら必須) |
wxSYSTEM_MENU | システムメニューを表示する(Windows のみ?)動作の一貫性を保つため、wxCAPTION と一緒に使用することが推奨されている |
wxMINIMIZE_BOX | ウィンドウの最小化ボタンを表示 |
wxMAXIMIZE_BOX | ウィンドウの最大化ボタンを表示 |
wxCLOSE_BOX | 「閉じる」ボタンを表示 |
wxRESIZE_BORDER | ウィンドウのリサイズを許可する |
wxCLIP_CHILDREN | 子ウィンドウが描画される際、下にある親ウィンドウも再描画する(Windows のみ) |
wxFRAME_EX_METAL | メタリックフレームなウィンドウの枠にする(Mac OS X のみ) |
- IMPLEMENT_APP(appname)
appname に指定した wxApp 系クラスのインスタンスを動的に生成する。
wx1_1.cpp のソースコードには main 関数がないが、マクロの定義(wx/app.h)を追っていくとわかる通り、最終的には main 関数の存在するコードに変換される。
プログラムの流れはこんな感じです。
- プログラム開始と同時に、IMPLEMENT_APP マクロによって myApp が生成される
- myApp::OnInit() が実行され、myFrame で定義されたウィンドウが生成される
- メインループに入り、イベント待ち状態となる(GLUT を使った時と同じ)
wxApp の派生クラスの myApp ですが、これは wxWidgets を使った GUI アプリケーションの場合は必須らしいです。
仮想関数である OnInit をオーバーライドすると、そこに書いた処理がプログラム起動時に実行されると。
今回のプログラムだと、ウィンドウを作成して、問題がなければ true を返す感じ。
wxFrame の派生クラスの myFrame は、title(ウィンドウの題名)を引数にとって、ウィンドウの設定を行なっている感じ。
なお、ヘッダファイルの 1 ~ 10 行目の部分は、ライブラリを作った人たちが色々試してみて、一番エラーが少なかった結果らしいです。
ということで、基本的にはここの部分については何もいじらず、常にコピペで大丈夫と思います。
次はもう少し設定を加えてみます。
最初にソースコードを書いていきます。
wx1_2.h (wx1_2.cpp のヘッダファイル)
[表示・非表示]
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
|
~ インクルードファイル, myApp の定義等 変更なし ~
class myFrame : public wxFrame
{
public:
myFrame(const wxString& title);
private:
// ウィンドウが閉じられた時の動作を設定
void OnClose(wxCloseEvent& event);
};
|
wx1_2.cpp (「Window Test」という題名の空ウィンドウを表示, 終了時は確認を行なう)
[表示・非表示]
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
|
~ インクルードファイル, OnInit()等 変更なし ~
myFrame::myFrame(const wxString& title) : wxFrame(NULL, -1, title)
{
// イベントハンドラの登録
Bind(wxEVT_CLOSE_WINDOW, &myFrame:OnClose, this);
Show(true);
}
void myFrame::OnClose(wxCloseEvent& event)
{
if ( wxMessageBox("ゲームを終了してもいいですか?",
"確認",
wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT) == wxNO )
{
return; // 終了せずに、アプリケーションの操作に戻る
}
Destroy(); // ウィンドウを安全に破棄する
}
|
実行結果はこちら。
それでは、太字で示した関数の紹介をします。
template<typename EventTag, typename Class, typename EventArg, typename EventHandler>
void wxEvtHandler::Bind(const EventTag& eventType, void(Class::*)(EventArg& ) method,
EventHandler* handler, int id = wxID_ANY, int lastId = wxID_ANY,
wxObject* userData = NULL)
イベントハンドラを登録するためのメソッド。(2.9.0 以降)
いくつかオーバーロードされた形式(こちらの「Binding and UnBinding」を参照)があるが、この形式ではメンバ関数をメソッドとして登録できる。
- int wxMessageBox(const wxString& message, const wxString& caption = "Message", int style = wxOK, wxWindow* parent = NULL, int x = wxDefaultCoord, int y = wxDefaultCoord)
メッセージボックスを表示し、ボタンを押すなどといったユーザ操作の結果を返却値として返す。
message はメッセージボックス中に表示する文章, caption はタイトルバーに表示される題名を指定する。
style にはメッセージボックスの表示形式を表す定数を「|」で区切りながら指定する。wxFrame とは使える定数が違うので注意。
parent は親ウィンドウのアドレスを指定する。 x, y は表示するディスプレイ上の座標位置を指定する。
なお、この関数は wxMessageDialog クラスを、さらに簡単に扱えるようにしてあるものである。
style に指定できる定数(wxMessageBox)
定数名 | 意味 |
wxOK | 「Ok」ボタンを表示 |
wxCANCEL | 「Cancel」ボタンを表示すると同時に「×」ボタンを有効にする wxOK, または wxYES_NO と一緒に使わなければいけない |
wxYES_NO | 「Yes」「No」ボタンを表示する。Windows の場合、「×」ボタンが使えなくなる |
wx_HELP | 「ヘルプ」ボタンを表示(2.9.3 以降?)。Cocoa ではメインスレッド以外から呼び出した場合には使えず、Carbon では完全にサポートされていない |
wxOK_DEFAULT | デフォルトで「Ok」ボタンにフォーカスを当てておく。 wxOK が有効になっている必要がある |
wxCANCEL_DEFAULT | デフォルトで「Cancel」ボタンにフォーカスを当てておく。 wxCancel が有効になっている必要がある |
wxYES_DEFAULT | デフォルトで「Yes」ボタンにフォーカスを当てておく |
wxNO_DEFAULT | デフォルトで「No」ボタンにフォーカスを当てておく |
wxICON_NONE | メッセージボックスにアイコンを表示しない |
wxICON_EXCLAMATION | 警告を表すアイコンを、メッセージの左側に表示 |
wxICON_ERROR | エラーを表すアイコンを、メッセージの左側に表示 |
wxICON_HAND | エラーシンボルである「手のひら」アイコンを、メッセージの左側に表示(Windows だと wxICON_ERROR と一緒?) |
wxICON_QUESTION | 質問を表すアイコンを、メッセージの左側に表示 |
wxICON_INFORMATION | 情報を表すアイコンを、メッセージの左側に表示 |
wxSTAY_ON_TOP | メッセージボックスを、全てのウィンドウの最上面に存在し続けるようにする |
wxCENTRE | ディスプレイ中央にメッセージボックスを表示 |
ちなみに、メッセージボックスのボタンのラベル名だけ変える, 「×」ボタンを使えるようにする、ということも出来るはずだが、その場合は wxMessageDialog, もしくは wxDialog クラスを利用して自分自身で少しいじる必要が出てくるっぽいため、手抜きしたい方にはおすすめしない。
- virtual bool wxWindow::Destroy()
生成したウィンドウを安全に破棄する。
デリートが成功するか、既にウィンドウのデリートリストに加えられていたら true が返される。
Destroy() の代わりに delete を使ってしまうと強制的にプログラムが止まってしまったので、必ず Destroy() を使ってウィンドウを破棄しましょう。
関数やマクロの説明が結構大雑把だったり、英語を直訳したような感じなのですが、もう少しわかりやすい表現が書けたらな…と思う。
最初はイベントハンドラの登録を DECLARE_EVENT_TABLE() や wxBEGIN_EVENT_TABLE(), wxEND_EVENT_TABLE のマクロで行なっていたのですが、このページを作成中、この記事を見て早速 Bind を使う方法に切り替えました。
それにしても、GLUT だとウィンドウを閉じる時に終了確認が出来なかった(freeglut は出来るかも)ので、終了確認が実装出来るようになったことが個人的にかなり嬉しい。
それでは後もう 1 つ、描画領域の縦横比を固定する機能を付け加えます。
「必要か?」と思われる方もいるかもですが、思いっきり私怨が入っています。
というのも“自分”の使っているモニタが 16 : 9 なので、4 : 3 の画面のゲームをフルスクリーンにすると、縦横比が崩れることがよくあって「フルスクリーン使えねーよ!」とよく思っていました。
それはともかくプログラムを書いてみます。
wx1_3.h (wx1_3.cpp のヘッダファイル)
[表示・非表示]
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
|
~ インクルードファイル, myApp の定義等 変更なし ~
class myFrame : public wxFrame
{
public:
myFrame(const wxString& title);
private:
// ウィンドウが閉じられた時の動作を設定
void OnClose(wxCloseEvent& event);
void OnKeyDown(wxKeyEvent& event);
};
|
wx1_3.cpp (「Window Test」という題名の空ウィンドウを表示, ウィンドウの縦横比固定)
[表示・非表示]
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
|
~ インクルードファイル, OnInit()等 変更なし ~
myFrame::myFrame(const wxString& title, const wxSize& size)
: wxFrame(NULL, -1, title, wxDefaultPosition, size,
wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN)
{
// イベントハンドラの登録
Bind(wxEVT_CLOSE_WINDOW, &gameWindow::OnClose, this);
Bind(wxEVT_KEY_DOWN, &gameWindow::OnKeyDown, this);
Show(true);
}
~ OnClose の定義 変更なし ~
void myFrame::OnKeyDown(wxKeyEvent& event)
{
switch (event.GetKeyCode())
{
// フルスクリーン・ウィンドウモードの切り替え
case WXK_F11:
ShowFullScreen(!IsFullScreen(), wxFULLSCREEN_ALL);
break;
default:
event.Skip();
return;
}
}
|
実行結果の画像は、今回はなし。
にしても、今のところはあまりソースコードが長くならずに済んでますねー。
ということで、太字で示した関数の紹介を。
- virtual bool wxTopLevelWindow::ShowFullScreen(bool show, long style = wxFULLSCREEN_ALL)
フルスクリーンモードのオン・オフを行なう関数。仮想関数なのでオーバーライド可能。
show が true なら フルスクリーンモードが有効, false なら無効になる。
style はフルスクリーンモードの時、ウィンドウのパーツの隠す部分を表す定数を「|」で区切って指定する。
style に指定できる定数(ShowFullScreen)
定数名 | 意味 |
wxFULLSCREEN_NOMENUBAR | メニューバーを隠す |
wxFULLSCREEN_NOTOOLBAR | ツールバーを隠す |
wxFULLSCREEN_NOSTATUSBAR | ステータスバーを隠す |
wxFULLSCREEN_NOBORDER | ウィンドウの境界を隠す |
wxFULLSCREEN_NOCAPTION | キャプション(「×」ボタンとかウィンドウ名が書かれている部分)を隠す |
wxFULLSCREEN_ALL | 上のオプション全てを有効にする |
- void wxEvent::Skip(bool skip = true)
skip が true の場合、他にイベントを受け取るハンドラを探し続ける(親階層のオブジェクトにイベントを伝播させる)。
false, もしくは Skip() を書かなかった場合、処理はそのイベントハンドラ内で終了。
本当は最大化ボタンか F11 キーを押すことでフルスクリーンモードと通常のウィンドウモードを切り替える、ということをやりたかったのですが……
よくわからないんだけど、最大化ボタンを押して wxMaximizeEvent が発生した時にフルスクリーンモードをオンにする処理を書いただけなのに、何か他の処理もやっているんだか知らないけど上手くいかない。
しょうがないから、F11 キーだけで切り替えるようにして、最大化ボタンは無効にしておいた。
何がいけないんだろう?
後、詳しくは次のページで書きますが、Skip() を行なっても上の階層のオブジェクトへとイベントが伝播しない場合があります。
その場合、伝播レベルを適当な数字に設定する必要があるので注意。
それでは最後に、このページで紹介した関数・マクロの一覧を。
- アプリケーション関連
- ウィンドウ関連
- イベント関連
2. OpenGL との連携へ