トップコンテンツプログラムノベルゲーム>ウィンドウ(wxWidgets編)



ウィンドウ(wxWidgets編)

初歩の初歩、ウィンドウの表示を行なうプログラムを書きたいと思います。
とは言え、wxWidgets ライブラリを使う場合の基本的なことがわかると思うので、コードの意味を考えながら、プログラムの動きを見てください。

このページで登場する wxWidgets のクラスは、以下の 3 つです。

クラスのメソッドについては後々触れますので、「こんなクラスが登場する」ということだけ頭に入れてください。


プログラム その1

それではソースコードです。
まあ、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;
}

実行結果はこちら

ウィンドウ その1

それじゃまあ、重要なマクロ, メソッドを紹介します。

プログラムの流れはこんな感じです。

  1. プログラム開始と同時に、IMPLEMENT_APP マクロによって myApp が生成される
  2. myApp::OnInit() が実行され、myFrame で定義されたウィンドウが生成される
  3. メインループに入り、イベント待ち状態となる(GLUT を使った時と同じ)

wxApp の派生クラスの myApp ですが、これは wxWidgets を使った GUI アプリケーションの場合は必須らしいです。
仮想関数である OnInit をオーバーライドすると、そこに書いた処理がプログラム起動時に実行されると。
今回のプログラムだと、ウィンドウを作成して、問題がなければ true を返す感じ。

wxFrame の派生クラスの myFrame は、title(ウィンドウの題名)を引数にとって、ウィンドウの設定を行なっている感じ。

なお、ヘッダファイルの 1 ~ 10 行目の部分は、ライブラリを作った人たちが色々試してみて、一番エラーが少なかった結果らしいです。
ということで、基本的にはここの部分については何もいじらず、常にコピペで大丈夫と思います。


プログラム その2

次はもう少し設定を加えてみます。
最初にソースコードを書いていきます。

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();  // ウィンドウを安全に破棄する
}

実行結果はこちら。

ウィンドウ その2(終了時、確認を行なう)

それでは、太字で示した関数の紹介をします。

関数やマクロの説明が結構大雑把だったり、英語を直訳したような感じなのですが、もう少しわかりやすい表現が書けたらな…と思う。
最初はイベントハンドラの登録を DECLARE_EVENT_TABLE()wxBEGIN_EVENT_TABLE(), wxEND_EVENT_TABLE のマクロで行なっていたのですが、このページを作成中、この記事を見て早速 Bind を使う方法に切り替えました。
それにしても、GLUT だとウィンドウを閉じる時に終了確認が出来なかった(freeglut は出来るかも)ので、終了確認が実装出来るようになったことが個人的にかなり嬉しい。


プログラム その3

それでは後もう 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;
  }
}

実行結果の画像は、今回はなし。
にしても、今のところはあまりソースコードが長くならずに済んでますねー。
ということで、太字で示した関数の紹介を。

本当は最大化ボタンか F11 キーを押すことでフルスクリーンモードと通常のウィンドウモードを切り替える、ということをやりたかったのですが……
よくわからないんだけど、最大化ボタンを押して wxMaximizeEvent が発生した時にフルスクリーンモードをオンにする処理を書いただけなのに、何か他の処理もやっているんだか知らないけど上手くいかない。
しょうがないから、F11 キーだけで切り替えるようにして、最大化ボタンは無効にしておいた。
何がいけないんだろう?

後、詳しくは次のページで書きますが、Skip() を行なっても上の階層のオブジェクトへとイベントが伝播しない場合があります。
その場合、伝播レベルを適当な数字に設定する必要があるので注意。

それでは最後に、このページで紹介した関数・マクロの一覧を。


2. OpenGL との連携へ