★☆=====================================================================☆★ 【wxWindowsでGUIプログラミング】 第5号: 計算結果を画面表示する(2) 2003.07.06(Sun) ★☆=====================================================================☆★  こんにちは,二条です。  発行が遅くなってすみません。頭が完全にボケてまして,発行日を一週間間違えていました。  今回から試験的に3箇所ほど広告を入れてみました。うざい!という方が多ければ減らすかやめることも考えますので,ご意見がありましたらお寄せください。連絡先は一番下にかいてあります。  最近Googleと戯れていて気がついたのですが,「wxWindows日本語プロジェクト」というものができて,ドキュメントの日本語化などが行われているようです。これでwxWindowsの敷居が少しでも低くなるとうれしいです。私は翻訳が大の苦手なのでお力にはなれませんが,陰ながら応援しています。  プロジェクトのページはこちらです。http://sourceforge.jp/projects/wxwindowsjp/  このメルマガでは,C言語やC++言語(特にC++)の初歩的な知識を前提とした説明が多いので,初心者の方にはわかりにくいかもしれません。サンプルソースを切り貼りしてコンパイルすればとりあえず動くようにはなりますが,CやC++についてもっと知りたいという方には,「実戦・C/C++言語」というメルマガをお勧めします。CやC++に関するメルマガはたくさんありますが,このメルマガはとても分かりやすくて実用的です。中級以上の方にもいろいろと役に立つと思いますので,ぜひ購読してみてください。  メルマガの紹介サイトはこちらです。http://www.log10jp.com/mmag/mmagcpp.htm  今回の内容は前回までの内容を前提として進めますので,初購読の方はお手数ですが,バックナンバーを参考にしてくださいませ。  バックナンバーは,まぐまぐのサイト http://www.mag2.com/m/0000108320.htm で見ることができます。  また, http://members10.tsukaeru.net/ariera/soft/wx.html こちらにダウンロード用のテキストファイルも用意してあります。  このメールマガジンは1行80文字で整形してあります。 *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- [1] サンプルプログラム 計算結果を画面表示する(2) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-  こちらは,今までの内容が簡単すぎるという方のために,少し複雑なサンプルを作ってみるコーナーです。(初心者の方でも,ソースをコピー&ペーストするだけで,とりあえず動くものは作れます。) ------------------------------------------------------------------------ (0)前回の訂正  予想通り(汗),トンでもない間違いがいくつかありました。文法的な間違いのほかに,設計がおかしいところもありましたので,まとめて訂正いたします。 ★ まず,point.h ですが,最初の #define X_MAX = 100; #define Y_MAX = 100; は明らかに変ですね。 #define X_MAX 100 #define Y_MAX 100 が正しいです。 ついでに,100 x 100ではさびしいので, #define X_MAX 400 #define Y_MAX 300 ぐらいにしてください。 それから, void set_y(int i) { x=j; } の最後の j は i の間違いです。 また,コンストラクタがあった方が何かと便利なので,public: の次の行に Point():x(0),y(0) {}; を追加してください。これは,x y ともに0で初期化するコンストラクタです。 最後に,クラス定義のおわりの } のあとにセミコロン ; をつけ忘れていたので,追加しておいてください。 ついでなので,必須ではありませんが,二重インクルード防止のため,ファイルの先頭に #ifndef _POINT_H_ #define _POINT_H_ の2行,末尾に #endif // _POINT_H_ の1行を追加しておくとよいでしょう。これは,たとえば point_wx.h と wx_point.cpp の両方で #include "point.h" としてしまったときに,クラスの二重定義とかいってコンパイラに怒られるのを防ぐためのものです。詳しくは説明しませんが,気になる場合はC言語の参考書などを見れば書いてあると思います。 ★ point_wx.h では,まず,Point クラスの変数を作る必要があるので,上の方に #include "point.h" を追加してください。 wx_point.cpp では,point_wx.h をインクルードするので, point.h を明示的にインクルードする必要はなくなります。 それから,wxSingleInstanceChecker と wxSplitterWindow のヘッダは明示的にinclude する必要があるようなので, #include "wx/snglinst.h" #include "wx/splitter.h" の2行も追加してください。 そして,class PointApp の publicメンバー変数として, wxCriticalSection pointLocker; Point* point; の2つを追加してください。 int OnExit(); と private: の間あたりです。 wxCriticalSection は前回,wx_point.cpp の中の PointApp::OnInit() で宣言しましたが,それでは他のクラスのインスタンス(オブジェクト)から呼び出せなくて大問題なので,こちらに移します。 Point は,表示する点の座標を表すクラスです。本来は private 変数にして,値を取得するメソッド(メンバー関数)を作成するべきなのですが,面倒なので public 変数にしてしまいます。 PointCanvasクラスを作成するときには,位置や大きさを指定したいので,コンストラクタの引数を PointCanvas(wxWindow* parent, wxWindowID id = -1); から, PointCanvas(wxWindow* parent, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize); に変更してください。 また,最後のenum のところを ID_POINT_THREAD, ID_MENU_ABOUT, ID_CLOSE_BUTTON から ID_POINT_THREAD, ID_CLOSE_BUTTON, ID_ABOUT_MENU, ID_CLOSE_MENU に変更してください。 ★ そして,wx_point.cpp ではまず,PointApp::OnInit() から,point_wx.h に移した wxCriticalSection pointLocker; を削除してください。 そのかわりに,点のインスタンスを作成する1行を追加します。 point = new Point(); そして, PointApp::OnExit() のほうには, delete point; の1行を return の前に追加してください。 また,wxImage のヘッダも明示的にinclude する必要がありますので,上の方に #include "wx/image.h" を追加してください。 wxWindowsのヘッダの中には,wx.h からインクルードされているとそうでないものがあるようです。文法的に間違っていないのにコンパイルエラーが出て,それが新しいwxクラスを導入する部分に近ければ,まずヘッダがインクルードされていないことを疑ってみてください。(WXDIR)/include/wx/wx.h を見ればどのヘッダをインクルードしているかがわかります。使おうとしているクラスが定義されているヘッダは,マニュアルを見て調べるのが早いです。 そして最後に,フレームの作成部分の PointFrame *frame = new PointFrame(_T("点が動くサンプル"), wxPoint(50, 50), wxSize(X_MAX+20, Y_MAX+100)); の最後の Y_MAX+100 を Y_MAX+150 に変えておいてください。 ------------------------------------------------------------------------ (1)PointFrame クラスの実装  前置きが長くなりましたが,前回作った wx_point.cpp に内容を追加していきます。  前回は PointApp クラスのメンバー関数を実装しましたので,次は PointFrame クラスです。前回作った wx_point.cpp ファイルの末尾に,以下の内容を追加してください。 // ここから PointFrame::PointFrame(const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(NULL, -1, title, pos, size, style) { // 終了ボタン closeButton = new wxButton(this, ID_CLOSE_BUTTON, "終了(&Q)", wxPoint(X_MAX-60,Y_MAX+70), wxSize(60,25)); // 計算結果を描画するキャンパス canvas = new PointCanvas(this, -1, wxPoint(5,10), wxSize(X_MAX,Y_MAX)); // ログウインドウ logWin = new wxTextCtrl(this, -1, "", wxPoint(5,Y_MAX+10), wxSize(X_MAX,60), wxTE_MULTILINE|wxTE_READONLY); // メニューバー wxMenu *menu = new wxMenu; menu->Append(ID_ABOUT_MENU, _T("バージョン情報(&V)"), _T("バージョン情報を表\示します")); menu->Append(ID_CLOSE_MENU, _T("終了(&Q)"), _T("プログラムを終了します")); wxMenuBar *menuBar = new wxMenuBar(); menuBar->Append(menu, _T("メニュー(&M)")); SetMenuBar(menuBar); // 計算スレッドを起動 pointThread = new PointCalcThread(this); if (pointThread->Create() != wxTHREAD_NO_ERROR) { wxMessageBox(_T("スレッド作成に失敗しました"), _T("エラー")); exit(-1); } pointThread->Run(); } //------------------------------------------------------------------------- void PointFrame::OnCalcThreadEvent(wxCommandEvent &event) { canvas->Refresh(); } //------------------------------------------------------------------------- void PointFrame::OnAboutMenu(wxCommandEvent &event) { wxMessageBox(_T("計算結果表\示\n作成者:二条\n作成日:2003.07.05"), _T("バージョン情報")); } //------------------------------------------------------------------------- void PointFrame::OnCloseButton(wxCommandEvent &event) { pointThread->Delete(); Close(TRUE); } //------------------------------------------------------------------------- void PointFrame::writeLogWin(wxString text) { logWin->WriteText(text); } //------------------------------------------------------------------------- void PointFrame::clearLogWin() { logWin->Clear(); } // ここまで  PointFrameのコンストラクタは,HelloWorld のときのメニューつきのフレームのコンストラクタとよく似ています。ボタンとメニューバーについては HelloWorld とほとんどおなじですので,ここでは説明しません。  canvas = 〜 の部分では,PointCanvas のインスタンスを作っています。引数は親ウインドウのポインタ,ウインドウID(ここでは使わないので-1),位置,サイズです。位置とサイズはピクセル単位で,x(最初の値) は右から左へ,y(2番目の値) は上から下に数えます。  logWin = 〜 の部分では,ログ出力用のウインドウを作成しています。ここでは wxTextCtrl クラスを使います。これは,テキストエディタのメイン画面などにも使えるクラスです。引数は親ウインドウのポインタ,ウインドウID,表示するテキストの初期値,位置,サイズ,ウインドウのスタイルです。ここで指定したスタイルは,複数行で読み込み専用という意味です。  ここで,canvas, logWin, closeButton の縦位置を考えてみると,canvas が上から10ピクセルのところからY_MAX ピクセル,logWin が上からY_MAX+10 ピクセルのところから60ピクセルなので,canvas の直下に60ピクセル,closeButton がY_MAX+70 ピクセルのところから25ピクセルなので,logWin の直下に25ピクセルということになります。合計Y_MAX+95ピクセルなので,フレームの大きさはY_MAX+100 で十分なように見えますが,メニューを追加するとメニューバーの分もフレームサイズに含まれてしまうので,Y_MAX+100 ではボタンが画面に入りきりません。  メニューの部分を飛ばして,計算スレッドを起動する部分では,まず,スレッドクラスのインスタンスを作成します。これだけではまだスレッドは作成されていません。実際にスレッドを作成するのは,pointThread->Create() の部分です。この戻り値が,wxTHREAD_NO_ERROR でなければスレッドの作成に失敗しているので,メッセージを表示してプログラムを終了します。wxTHREAD_NO_ERROR 以外の戻り値には,wxTHREAD_NO_RESOURCE(リソース不足)やwxTHREAD_RUNNING(スレッドが既に動いている)などがあります。  そして,pointThread->Run(); でスレッド関数を呼び出します。スレッド関数とは,スレッドクラスの Entry() というメソッド(メンバー関数)のことです。Run() が呼ばれると,Entry() が自動的に呼び出されます。Run() には,Entry()を呼び出す他に,スレッドが関数が既に走っているという目印をつける機能もあります。Entry() はprotected なので,外部から直接呼び出すことはできません。  OnCalcThreadEvent は,スレッドがイベントを発行したときに呼ばれる関数です。イベントについては後ほど詳しく説明します。  Refresh(); は,指定したウインドウを再描画するという関数で,具体的には指定したウインドウに Paint イベントを送ります。  OnAboutMenu と OnCloseButton は,HelloWorld とほとんど同じです。OnCloseButton の pointThread->Delete(); は,走っているスレッドを止めるための関数です。  writeLogWin と,clearLogWin は,ログ出力用の wxTextCtrl を操作するための関数です。 WriteText と Clear はどちらも wxTextCtrl クラスのメンバー関数です。 writeLogWin では,引数で指定された文字列を,画面に出力します。 clearLogWin では,画面に書かれた文字を全部消します。 この二つの関数は,スレッド関数の中から呼び出します。 ------------------------------------------------------------------------ (2)PointCalcThread クラスの実装  長くなったのでファイルを分けてもよいのですが,面倒なので wx_point.cpp にさらに追加していきます。 // ここから PointCalcThread::PointCalcThread(PointFrame* parent) : wxThread(wxTHREAD_JOINABLE) { parentFrame = parent; } //------------------------------------------------------------------------- void* PointCalcThread::Entry() { int logLine = 0; while(!TestDestroy()) { // 点を動かすシミュレーション部分 wxGetApp().pointLocker.Enter(); wxGetApp().point->move(); wxGetApp().pointLocker.Leave(); // ログ出力 if(logLine > 50) { parentFrame->clearLogWin(); logLine=0; } logLine++; wxString wx_msg; wx_msg<<"x="<<(wxGetApp().point)->get_x()<<" , y="<<(wxGetApp().point)->get_y()<<"\n"; parentFrame->writeLogWin(wx_msg); wxSleep(1); wxCommandEvent event(wxEVT_USER_FIRST, ID_POINT_THREAD); wxPostEvent(parentFrame, event); } return NULL; } // ここまで  コンストラクタでは,メンバー変数の parentFrame に親ウインドウである PointFrame のポインタを入れています。これは後ほど,ログウインドウに文字を書くときやイベントを送るときに使います。  Entry() は先ほど説明したように,スレッド関数(スレッドのエントリーポイント)です。PointFramepoint のコンストラクタで Thread->Run(); が呼ばれたときに,この関数が呼ばれます。  今回の計算用スレッドは,外部から止めるまで,延々と計算を続ける無限ループとなっています。  最初の logLine は,ログの行数を数えるための変数です。ログがあまり多くたまるとメモリを消費しますので,ある行数たまったらクリアするようにしてあります。  次の while(!TestDestroy()) のブロックがループのブロックです。TestDestroy() は,スレッド外部から Delete() または Pause() が呼ばれていないかどうかチェックする関数です。終了ボタンを押したとき,PointFrame::OnCloseButton() で pointThread->Delete(); が呼ばれますので,そこでループを抜けるようになっています。  ループの中では,まず PointApp クラスに用意したクリティカルセッションに入ります。これは,このスレッドと表示用のメインスレッドで,point に同時アクセスしてデータを壊してしまうのを防ぐための仕組みです。もしメインスレッドが先にクリティカルセッションに入っていれば,そのスレッドがクリティカルセッションから抜けるまで,wxGetApp().pointLocker.Enter(); のところで止まっています。  wxGetApp() は,アプリケーションクラスのインスタンス(オブジェクト)を取得するための関数です。これを使うために,DECLARE_APP(PointApp) のマクロが必要なのです。  そして,wxGetApp().point->move(); で点の座標を進めます。点の進み方は,前回 point.h で定義しました。  pointの値の変更が終わったら,wxGetApp().pointLocker.Leave(); でクリティカルセッションから出ます。これで,メインスレッドがクリティカルセッションに入れるようになります。  ログ出力の部分では,ログが50行を超えると一度画面をクリアします。古いものから1行ずつ消しているのではなく,50行溜まったらいきなり全部消すという手抜きです。  wxString wx_msg が,メッセージの文字列を入れるための変数で,cout などと同じようにストリーム演算子が使えます。ここに文字列を書き込んだら,writeLogWin を呼び出してログウインドウに書き込みます。  wxSleep(1); で1秒待ちます。これは,あまり早く画面が流れてしまうと,何が起こっているか確認しにくいためです。  次の2行で,親フレーム parentFrame にイベントを送っています。wxCommandEvent event(wxEVT_USER_FIRST, ID_POINT_THREAD); で,wxCommandEvent クラスのインスタンスを作成し,それを wxPostEvent で送っています。wxCommandEvent のコンストラクタの第1引数はイベントの種類,第2引数はイベントのIDです。イベントのIDは,point_wx.h で enum で定義したものです。イベントの種類は,ボタンをクリックしたときならwxEVT_COMMAND_BUTTON_CLICKED,メニューを選択したときならwxEVT_COMMAND_MENU_SELECTED などと決まっているものもありますが,自分で定義することもできます。自分で定義する場合は,wxEVT_USER_FIRST 以降の数字を適当にdefine して使います。今回は一つしか使わないので,wxEVT_USER_FIRST をそのまま使います。このイベントの種類は,イベントテーブルを作るときに EVT_MENU,EVT_BUTTON などのうちからどれを選ぶかに関連してきます。EVT_COMMAND を使えば,イベントの種類とIDの両方を指定できますので,自分で定義したイベントにはこれを使うことが多いです。  そして wxPostEvent の第1引数は送り先のポインタ,第2引数は送るイベントです。  点の座標を描画するのは PointCanvas なので,PointFrame ではなく PointCanvas に直接イベントを送ると早いのですが,PointCalcThread と PointCanvas はどちらも PointFrame 内の要素なので,PointCalcThread から PointFrame にwxEVT_USER_FIRST(ユーザー定義) のイベントを送り,それを受け取った PointFrame がPointCanvas のRefresh() を呼ぶ(=Paintイベントを送る) という形にしてあります。 最後の return NULL; は,戻り値が void* なので,コンパイルエラーが出ないように書いてあるだけです。Entry()の戻り値は,外部からスレッドが終了するのを待つ関数Wait() を呼んだときに使います。 ------------------------------------------------------------------------ (3)PointCanvas クラスの実装  もう少しです。 wx_point.cpp にさらに追加してください。 // ここから PointCanvas::PointCanvas(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) : wxSplitterWindow(parent, id, pos, size) { SetBackgroundColour(wxColour("WHITE")); Clear(); } //------------------------------------------------------------------------- void PointCanvas::OnPaint(wxPaintEvent &event) { Clear(); wxPaintDC dc(this); dc.SetBrush(wxBrush("red", wxSOLID)); dc.SetPen(*wxBLACK_PEN); wxGetApp().pointLocker.Enter(); dc.DrawRectangle((wxGetApp().point)->get_x(), (wxGetApp().point)->get_y(), 6, 6); dc.DrawText(_T("Now Here!"), (wxGetApp().point)->get_x()+6, (wxGetApp().point)->get_y()+6); wxGetApp().pointLocker.Leave(); } // ここまで  PointCanvas は点を描く画面です。コンストラクタでは,SetBackgroundColour で背景を白にして,Clear で画面を初期化しています。  OnPaint() が,点を描く関数です。後でイベントテーブルで関連づけますが, PointFrame::OnCalcThreadEvent() で canvas->Refresh(); が呼ばれたときに呼び出されます。  最初の wxPaintDC dc(this); で,デバイスコンテキストを作成しています。デバイスコンテキストとは,簡単に言うと「お絵かきセット」のようなものだと思ってください。  最初に,Clear() で画面を初期化します。なくても前の点が残ることはありませんが,念のためです。  dc.SetBrush(wxBrush("red", wxSOLID)); で「ブラシ」の設定をしています。第1引数は色,第2引数は塗りつぶしタイプです。wxSOLID の他には,wxBDIAGONAL_HATCH ,wxCROSSDIAG_HATCH などがあります。  dc.SetPen(*wxBLACK_PEN); ではペンの色を指定しています。  ここから,pointにアクセスするので,クリティカルセッションに入ります。  次の dc.DrawRectangle() では,四角形をかきます。最初の引数がx座標(横位置),2番目がy座標(縦位置),3番目が横幅,4番目が縦幅になります。単位はすべてピクセルです。縦と横の位置は point の値からもってきて,幅は適当に6としておきます。  ここで,四角の枠はペンの色で描かれ,中はブラシの色と塗りつぶしタイプで塗りつぶされます。  次のdc.DrawText() では,第1引数で指定した文字列を,2番目と3番目で指定した位置に書き込みます。ここでは,点の右下にくっつけて書いています。点が右や下の方に行くと見えなくなるというマヌケなものですが……  文字の色は,ペンの色で書かれます。  そして,最後にクリティカルセッションを出ます。 ------------------------------------------------------------------------ (4)イベントテーブル  これで最後です。 wx_point.cpp にさらに追加してください。 // ここから BEGIN_EVENT_TABLE(PointCanvas, wxSplitterWindow) EVT_PAINT(PointCanvas::OnPaint) END_EVENT_TABLE() BEGIN_EVENT_TABLE(PointFrame, wxFrame) EVT_MENU(ID_ABOUT_MENU, PointFrame::OnAboutMenu) EVT_MENU(ID_CLOSE_MENU, PointFrame::OnCloseButton) EVT_BUTTON(ID_CLOSE_BUTTON, PointFrame::OnCloseButton) EVT_COMMAND(ID_POINT_THREAD, wxEVT_USER_FIRST, PointFrame::OnCalcThreadEvent) END_EVENT_TABLE() // ここまで  Refresh が呼ばれたときの関数は,EVT_PAINT で指定します。この場合はIDなどは必要ありません。  メニューとボタンは HelloWorld と同じです。  最後の EVT_COMMAND が,自分で定義したイベントと関数を関連づけるものです。IDの次に,イベントの種類を指定する必要があります。  ボタンやメニューなどでも,イベントの種類を指定すれば EVT_COMMAND で関連づけを行うこともできます。  これでやっとコンパイルして動かすことができるようになりました。  実際に動かしてみて,適当にいじってみてください。  もし,コンパイルエラーが出るようでしたら,最初の訂正の部分で何か書き忘れているかもしれませんので, ご連絡いただけるとうれしいです。  次回は四角のかわりに絵を使ったり,点を増やしたりしてみます。たぶん,点の表示プログラムは次回で終わると思います。 =[広告]======================================================================   ★━┓   ★━┓   ─★ 総計10222名様にプレゼント ★─   ┃当┃┏━┓┃る┃┏━┓ ¢SONYバイオデスクトップパソコン   ┗━┛┃た┃┗━┛┃♪┃ ¢ルイ・ヴィトン モノグラムアルマ      ★━┛   ★━┛ ¢JTB商品券5000円分   >>> http://px.a8.net/svt/ejp?a8mat=I8F5V+6HZEAI+5WI+609HV ============================================================================= *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- [2] ワンポイント解説 メッセージボックス *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-  こちらは,前回までのHelloWorldプログラムを少しずついじってみるコーナーです。基本的なことから少しずつ覚えたい方向けです。  気がつくと第1部がとっても長くなってしまったので,今回は手抜きです。  前回までの HelloWorld プログラムの一番下の,HelloWorldFrame::OnAboutMenu() のwxMessageBox() の引数をいろいろ変えてみます。 ------------------------------------------------------------------------ (1)wxMessageBox()  wxMessageBox() はグローバル関数です。今までの HelloWorld では, wxMessageBox(_T("メッセージの中身"), _T("タイトル")); のような使い方をしていましたが,これは,デフォルトで wxOK | wxCENTRE というスタイルとなっているからです。3つ目の引数として,スタイルを指定すると,いろいろなダイアログを出すことができます。 wxMessageBox(_T("メッセージの中身"), _T("タイトル"), wxYES_NO); とすると,「はい」「いいえ」の二つのボタンを持ったダイアログ, wxMessageBox(_T("メッセージの中身"), _T("タイトル"), wxYES_NO|wxCANCEL); とすると「はい」「いいえ」「キャンセル」の三つのボタンを持ったダイアログが出ます。 wxMessageBox(_T("メッセージの中身"), _T("タイトル"), wxCANCEL); wxMessageBox(_T("メッセージの中身"), _T("タイトル"), wxOK); wxMessageBox(_T("メッセージの中身"), _T("タイトル"), wxYES_NO|wxOK); この三つは全部同じで「OK」ボタンだけのメッセージとなるようです。 この関数の戻り値は,wxYES, wxNO, wxCANCEL, wxOK のうちのどれかとなります。複数のボタンがある場合は,戻り値をチェックすることで,どのボタンが押されたかがわかります。 これらの指定に,| wxCENTRE を追加すると,メッセージの文字列がセンタリングされます。 また,以下のものを追加すると,メッセージの横にアイコンが出ます。 説明:wxICON_EXCLAMATION エラー:wxICON_HAND または wxICON_ERROR 質問:wxICON_QUESTION 情報:wxICON_INFORMATION また,4つめの引数で親ウインドウ,4つめの引数でx 座標,5つ目の引数でy 座標を指定できます。 ------------------------------------------------------------------------ (2)wxShowTip()  もうひとつ,似たようなグローバル関数を紹介します。 まず,ファイルの上の方,クラス定義をはじめる前に, #include "wx/tipdlg.h" を追加してください。 それから,tips.txt というテキストファイルを,ソースコードと同じディレクトリに用意し,何か適当な内容を書いておいてください。 そして,HelloWorldFrame::OnAboutMenu() の中に,以下の3行を追加してください。 もとのメッセージボックスはコメントアウトしておくとよいでしょう。 wxTipProvider *tipProvider = wxCreateFileTipProvider("tips.txt", 0); wxShowTip(this, tipProvider); delete tipProvider; コンパイルして実行し,メニューの「バージョン情報」を選ぶと,tips.txt の内容が1行ずつ表示されます。Next Tip を押すと,次の行が表示されます。 wxCreateFileTipProvider の2番目の引数は,表示する行の初期値を表しています。最後まで行くと最初の行に戻ります。 また,Show tips at startup というチェックボックスがありますが,これを押しても自動的に起動時に表示されるようになるわけではありません。wxCreateFileTipProvider の3つ目の引数(省略可,デフォルトTRUE)と戻り値が,このチェックボックスの値となっているので,それを起動時にチェックするコードを描く必要があります。 ------------------------------------------------------------------------ 編集後記:  最近,引越しサイト馬鹿になっています。  特に意味もなく勤務先から1時間半ほどかかるところに住んでいるのですが,電車が止まったりするたびに,だるいから近くに引っ越そうと思い立ちます。そして,気に入った物件がなくてそのまま忘れ去って,という繰り返しで1年以上たってしまいました。  で,最近また引越し熱に取り付かれて,賃貸検索サイトとか,引越しのコツなんかを見ていると,2〜3時間ぐらい経っていたりして,頭が完全にアホになっているのに気がついたりします。  今度こそ,ちゃんと引越ししようと思うのですが,条件が厳しすぎるのか,なかなか気に入ったものがありません。2部屋以上必要,犬飼いたい,楽器も弾きたい,家賃が高いのは×というのは贅沢すぎでしょうか??  次回発行日は2003.7.20(日)の予定です。  今回は発行日を間違えてしまったのでできれば次回は早めに発行したいと思います。 ★☆=====================================================================☆★ メールマガジン:wxWindowsでGUIプログラミング 第5号 2003.07.06(Sun) 発行人:二条 ご意見・ご感想はこちらへ: ariera@members10.tsukaeru.net こちらからもメールが送れます http://members10.tsukaeru.net/ariera/other/form/form.cgi 解除・バックナンバーはこちらからどうぞ http://members10.tsukaeru.net/ariera/soft/wx.html マイサイト「気まぐれ歴史散歩」もよろしくお願いします http://members10.tsukaeru.net/walk/ このメールマガジンは「まぐまぐ」を使って配信しています http://www.mag2.com/ ★☆=====================================================================☆★ =[広告]====================================================================== ■■━━【 取れる!激安!】★☆★【今からでもまだ間に合う!】 ━━■■ ■■ 24時間その場で予約が可能!!残席に限りあり早い者勝ちです! ■■ ■■→→→→ ハワイ・グアム・サイパン・台湾・韓国・香港 ←←←←■■           http://px.a8.net/svt/ejp?a8mat=I8FXS+2HWHWA+1O0+HXSGJ =============================================================================