目次


wxWindowsの概要

ポータブルC++ and Python GUIツールキットの紹介

Comments

wxWindowsライブラリーは、ダイナミック・リンク・ライブラリー (DLL) としてコンパイルされているかどうかにかかわらず、きわめて小さな実行ファイルを作成することができます。また、マルチプラットフォーム開発のためのさまざまなツールを提供します。たとえば、HTML、ユニコード、および国際化対応のためのOpenGLインターフェースおよび組み込みサポートが用意されています。そして、Windows専用のMFC (Microsoft Foundation Classes) からLinuxなどにアプリケーションを移植するための支援を行います。wxWindowsの主要な目標の1つに、できるかぎり多くのプラットフォームで稼働して、使用可能なほとんどすべてのC++ コンパイラーをサポートすることがあります。まだ標準C++ のすべての機能 (たとえば、ネームスペース、std::stringクラス、およびSTLコンテナー) を使用してはいません。しかし標準C++ はTo-Doリストに含まれていて、すでに新しいキャスト構文およびstd::stringはある程度サポートされています。

wxWindowsの歴史

wxWindowsは1992年に、エディンバラ大学の人工知能応用研究所でJulian Smartによって開発が開始されました。1995年にMarkus HolzemがwxWindowsをXtに移植したX toolkitをリリースしました。短い停滞期を経て、1997年の5月にWindowsおよびGTK+ への移植がマージされ、CVSリポジトリーに組み込まれて、wxWindowsのすべての協力者によって使用できるようになりました。1997年の終わり近くにJulian Smartが、完全なソース、コンパイラー素材、その他を含む、wxWindowsのCD-ROMの配布を開始しました。

現在ではwxWindowsはGPLのもとでリリースされるようになっています。ただし、例外が1つあり、ソース・コードを添付しないでバイナリーの実行可能ファイルを配布することができます。これは、商用プロジェクトで使用するためには、賢明なオプションです。現在は、UNIX系およびMicrosoft Windows系のさまざまなOS、およびMacintosh OSで使用することができます。OS/2、その他のオペレーティング・システムへの移植は、開発中です。それでは、中身の話に移りましょう。

使用できるプラットフォーム

wxWindowsは他のほとんどのマルチプラットフォームGUIライブラリーとは異なる方法でウィジェットを使用します。これは、可能なかぎりネイティブなコントロールを使用するからです。UNIXのもとでのツリー・コントロールのような、利用できないコントロールはエミュレートされます。これにより、アプリケーションを使用するユーザーに、使い慣れたルック・アンド・フィールが提供されます。wxWindowsライブラリーは現在、以下のプラットフォームをサポートします。

  • Windows 3.1、Windows 95/98、Windows NT
  • Motif/Lesstifを備えたほとんどのUNIX
  • GTK+ を備えたほとんどのUNIX
  • Mac

UNIX/Win32および (若干の制限はありますが) BeOSのもとでは、非GUIクラスだけを含むwxBaseライブラリーも構築可能です。また、wxWindowsをDLLとしてコンパイルしていない場合にも、でき上がる実行可能ファイルは非常に小さくなります。たとえば、最小のサンプル・アプリケーションをWindowsプラットフォーム用のMicrosoft Visual C++ でコンパイルすると、400 Kバイト未満になります。また、wxWindowsの実行可能ファイル・サイズが小さいため、たいていの場合、いわゆる「DLL地獄」を避けることができます。

さて、次はマルチプラットフォームのツールに移りましょう。

アーキテクチャーから独立した型

アーキテクチャーへの依存性を避けるために、ライブラリーによって、アプリケーションのエンディアンに関してビット・スワッピングを処理する、アーキテクチャーから独立したさまざまな型およびマクロが提供されます。以下の型が提供されます。

  • wxInt32 (32ビット符号付き整数)
  • wxInt16 (16ビット符号付き整数)
  • wxInt8 (8ビット符号付き整数)
  • wxUint32 (32ビット符号なし整数)
  • wxUint16 = wxWord (16ビット符号なし整数)
  • wxUint8 = wxByte (8ビット符号なし整数)

ビット・スワッピング・マクロは整数および符号なし整数に使用可能です (下記のxxは、16または32を表し、BEはビッグ・エンディアンを表し、LEはリトル・エンディアンを表します)。

  • wxINTxx_SWAP_ON_BE()
  • wxUINTxx_SWAP_ON_BE()
  • wxINTxx_SWAP_ON_LE()
  • wxUINTxx_SWAP_ON_LE()
  • wxINTxx_SWAP_ALWAYS()
  • wxUINTxx_SWAP_ALWAYS()

次の例に示すように、その使用方法は簡単です。

32ビット符号付き整変数のバイトのスワッピング
wxInt32 old_var = 0xF1F2F3F4;
wxInt32 new_var = wxINT32_SWAP_ALWAYS( old_var )

これらのマクロのほかに、wxWindowsは、ライブラリーのコンパイルに使用されたマシンの現在のエンディアンを判別するための#define も備えています。その使用例を次に示します。

#define の使用
if ( wxBYTE_ORDER == wxLITTLE_ENDIAN )
{
    // Do stuff for little endian machine...
}
else
{
    // Do stuff for big endian machine...
}

ファイル処理

ファイル記憶の概念が異なるさまざまなプラットフォームに合うようにコーディングすることは、常に困難なことです。この問題を克服するために、wxWindowsにはマルチプラットフォーム・ファイル処理の関数が備わっています。まず最初に、コピー、除去、および名前変更などの基本的なファイル操作に関する関数を見てみましょう。

基本的なファイル操作
wxString old_report = "smithers_00.doc"
wxString new_report = "my_smithers.doc";
if ( wxCopyFile( old_report, "smithers_00.bak" ) == true )
{
    if ( wxRemoveFile( old_report ) == true )
    {
        if ( wxRenameFile( new_report, old_report ) == false )
        {
            // Doh!
        }
    }
}

異なるプラットフォーム向けにコーディングすることによって生じる別の深刻な問題として、ディレクトリー区切り文字の問題がありますが、これは、wxPathList クラスを利用することによって完全に回避することができます。wxPathList にはファイルを検索するディレクトリーのリストが含まれます。ファイルを探したい場合には、wxPathList クラスにファイル名を渡すだけで、事前定義されたディレクトリーが検索されます。

wxPathList クラス
wxPathList path_list;
// Add current working directory
path_list.Add( "." );
// Add one directory above current working directory
path_list.Add( ".." );
// Add directories from environment variable PATH to the list
path_list.AddEnvList( "PATH" );
wxString path = path_list.FindValidPath( "homer.bmp" );

wxWindowsにはそのほかに2つの便利な関数が備わっています。絶対パスからファイル名を取り去るwxFileNameFromPath() と、絶対パスからパスを取り去るwxPathOnly() です。

HTML

Vaclav SlavikのwxHTMLライブラリーは、基本的なHTMLを構文解析し、表示します。これはHTML標準を完全に実装しているわけではありませんが、オンライン・ヘルプを扱うには十分な機能を備えており、また、ハンドラーを使用して拡張することができます。HTMLを表示するには、wxHtmlWindow クラスのオブジェクトを作成してください。そして、そのメソッドを呼び出して、HTMLを実際に表示するように関連のフレームを設定し、HTMLパーサーによって生成されたメッセージを表示するように関連のステータス・バーを設定します。

wxHTML
wxHtmlWindow html_window = new wxHtmlWindow( this );
html_window->SetRelatedFrame( this, "HTML : %%s" );
html_window->SetRelatedStatusBar( 0 );

その後で、次のようにしてHTMLページをロードすることができます。

HTMLのロード
html_window->LoadPage( "burns.htm" );

あるいは、次のようにしてHTMLコードを表示できます。

HTMLの表示
html_window->SetPage( "<html><body>Hello, Monty!</body></html>" );

イメージ

wxImage クラスは、イメージ・フォーマット・ハンドラーを使用してさまざまなイメージ・ファイル・フォーマットをロードします。wxImage を拡張して独自のイメージ・フォーマット・ハンドラーを実装すると、新しいイメージ・フォーマットをロードすることができます。既存のイメージ・フォーマット・ハンドラーは、Sam LefflerのlibTIFFやIndependent JPEG GroupのJPEGなどの、よく知られたライブラリーを使用します。これらは、BMP、PNG、JPEG、GIF、PCX、PNM、およびTIFF用のハンドラーです。それぞれのイメージ・フォーマット・ハンドラーは、アプリケーション始動コード内でwxImage クラスの静的メソッドであるAddHandler() を使用することにより、アクティブにすることができます。

wxImages
bool MyApp::OnInit()
{
    wxImage::AddHandler( new wxPNGHandler );
    // more ...
}

既存のすべてのイメージ・フォーマット・ハンドラーを使用するには、上に示したAddHandler() メソッドの代わりにwxInitAllImageHandlers() 関数を呼び出してください。

異なるプラットフォームで使用するアプリケーション内でツールバー・ビットマップを使用する場合には、特別な注意が必要です。Windowsの場合にはWindowsビットマップ・フォーマットを使用しますが、Linuxのビットマップは通常はpixmapであり、これを使用した場合には条件付きコンパイルを完全に回避することはできません。次のサンプル・コードを見てください。

#if defined(__WXGTK__) || defined(__WXMOTIF__)
    #include "maggie.xpm"
#endif
// more ...
void MyApp::UseBitmap()
{
    wxBitmap bitmap( wxBITMAP( maggie ));
    // more ...
}

気がつきましたか? すべての秘密はwxBITMAP() マクロにあります。このマクロは、WindowsおよびOS/2では、maggieと呼ばれるビットマップを使用して、アプリケーション・リソースからwxBitmap オブジェクトを作成します。それ以外のすべてのプラットフォームでは、maggie_xpmと呼ばれるpixmapを使用してwxBitmap オブジェクトを作成します。

ビットマップはwxDC::DrawBitmap() を使用してデバイス・コンテキストに合わせて描画することができますが、イメージ操作の場合には、次に示すようにwxImage オブジェクトを使用しなければなりません。

イメージ操作
wxImage* p_image = new wxImage( bitmap );
// Have some fun
if ( p_image->Ok() )
{
    if ( p_image->GetHeight() > 50 && p_image->GetWidth() > 50 )
    {
        unsigned char red   = p_image->GetRed( 50, 50 );
        unsigned char green = p_image->GetGreen( 50, 50 );
        unsigned char blue  = p_image->GetBlue( 50, 50 );
        // Secure but might be slow
        p_image->SetRGB( 50, 50, red, green, blue );
        // If you want fast action use a pointer...
        unsigned char* data = p_image->GetData();
        // Manipulate the data...
    }
}

ユニコードおよび国際化対応 (i18n)

国際的な市場向けにソフトウェアを開発する場合には、英語以外の言語でアプリケーション・メッセージを表示できるようにする必要があります。しかし、広く使用されているANSIコードでは、すべての言語で使用されている記号を扱うことはできません。(たとえば、中国語を表示することはできません。) また、ANSIとユニコードの両方に合わせてコーディングすると、次の例に示すように、ビット複合となります。

ANSIおよびユニコード
#ifdef USE__UNICODE
    wchar_t wide_char = L'h';
    wchar_t const* wide_string = L"Hello, World!";
    int length = wcslen( wide_string );
#else
    char ansi_char = 'h';
    char const* ansi_string = "Hello, World!";
    int length = strlen( ansi_string );
#endif

wxWindowsのユニコード機能を使用すると、これを次のように簡単に書くことができます。

wxT() マクロとwxCharおよびwxString
wxChar wx_char = wxT( '*' );
wxString wx_string = wxT( "Hello, World!" );
int length = wx_string.Len();

wxT() マクロとwxChar およびwxString クラスは、すべてを扱うことができます。ライブラリーは、この方法を内部的に使用して、すべてのメッセージに対応します。現在、チェコ語、デンマーク語、ドイツ語、フランス語、イタリア語、およびロシア語への翻訳が可能ですが、ローカライズ版のライブラリーをコンパイルし、wxLocale クラスから支援を受けて使用することができます。

デバッグ

このライブラリーは、アプリケーションのデバッグを支援するためのさまざまなクラス、関数、およびマクロを備えています。このライブラリーをデバッグ・モードでコンパイルする場合には、wxObject クラス (wxWindowsにおけるほとんどのクラスに対応する基本クラス) 用のnew およびdelete 演算子は、ヒープに割り振られたオブジェクトに関する追加情報を保管するように再定義されています。この情報を利用して、wxDebugContext クラスによってオブジェクト割り振り、メモリー・リーク、上書き、および下書きに関する詳しい情報を入手することができます。

// Start logging for Dump() call
wxDebugContext::SetCheckpoint();
wxString *thing = new wxString;
wxDate* date = new wxDate;
// non-object allocation
char *ordinaryNonObject = new char[1000];
// more ...
// Print number of object and non-object allocations
wxDebugContext::Dump();
// Print allocation statistics
wxDebugContext::PrintStatistics();

wxDebugContext::Dump() を呼び出すと、割り振りのリストを含むウィンドウがポップアップします。下の例には、wxWindowsで提供されるmemcheckサンプルを使用して私が作成したリストが示されています。

wxDebugContext::Dump() の呼び出し

13:32:45: ----- Memory dump of memcheck at Tue Dec 26 13:32:45 2000 -----
13:32:45: ..\..\..\samples\memcheck\memcheck.cpp(88): non-object data at $DD3DC0, size 4
13:32:45: ..\..\..\samples\memcheck\memcheck.cpp(89): wxDate at $DD40D0, size 24
13:32:45: ..\..\..\samples\memcheck\memcheck.cpp(92): non-object data at $DD4118, size 1000

wxDebugContext::PrintStatistics() を呼び出すと、下記の統計が表示されます。

wxDebugContext::PrintStatistics()の呼び出し
13:32:45: ----- Memory statistics of memcheck at Tue Dec 26 13:32:45 2000 -----
13:32:45: 1 objects of class wxDate, total size 24
13:32:45: 5 objects of class nonobject, total size 4256
13:32:45: 
13:32:45: Number of object items: 1
13:32:45: Number of non-object items: 5
13:32:45: Total allocated size: 4280

MFCアプリケーションのLinuxへの移植

wxWindowsライブラリーを使用すると、MFCアプリケーションをLinuxその他のオペレーティング・システムに移植することができます。次のコードを見ると分かるように、wxWindowsのストリング・クラスwxString は、MFCのストリング・クラスCString に似たところがあります。

wxString
wxString s1 = "Hello, World!";
wxString s2 = "Hello";
if ( s1.IsEmpty() == false )
{
    s2.Empty();
    s2 = s1.Left( 5 );
    int pos = s1.Find( ',' );
    s2 += s1.Mid( pos, 2 );
    s2 += s1.Right( 6 );
}

wxWindowsのイベント・システムもMFCによく似ています。MFCでは、メッセージ・マップによってイベント・ハンドラー・メソッドがイベント・システムにマップされます。wxWindowsでは、メッセージ・マップに相当するものがイベント・テーブルと呼ばれます。イベント・テーブル・マクロとMFCのメッセージ・マッピングとでは、わずかな違いがあります。主要な相違点は、下のソース・コードで示されています。

ヘッダー・ファイルのためのMFCコード
class CButtonCtrl : public COleControl
{
// Implementation
protected:
    LRESULT OnOcmCommand( WPARAM wParam, LPARAM lParam );
    DECLARE_MESSAGE_MAP()
};
実装ファイルのためのMFCコード
BEGIN_MESSAGE_MAP( CButtonCtrl, COleControl )
    //{{AFX_MSG_MAP( CButtonCtrl )
    ON_MESSAGE( OCM_COMMAND, OnOcmCommand )
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()
ヘッダー・ファイルのためのwxWindowsコード
class MyButton : public wxButton
{
    void OnButton( wxMouseEvent& event )
private:
    DECLARE_EVENT_TABLE()
};
実装ファイルのためのwxWindowsコード
BEGIN_EVENT_TABLE( MyButton, wxButton )
    EVT_BUTTON( -1, MyButton::OnButton )
END_EVENT_TABLE()

これを見てお分かりのように、さほどの違いはありません。メーリング・リストによると、既存のMFCアプリケーションをwxWindowsに正常に移植できた人が、すでに何人もいます (それらの人々は、喜んで読者の助けになってくれます:)。

標準C++

wxWindowsはまだ標準C++ 技法 (std::string、STL、またはネームスペース) を使用していません。そのようにすると、wxWindowsでコンパイルが行えるプラットフォームの数が大幅に減ってしまうためです。(標準C++ の最新機能を完全にサポートするコンパイラーは、ごくわずかです。) しかし、wxWindowsの開発チームは、標準C++ がより広くサポートされるようになるのに合わせて、標準C++ のサポートをライブラリーに組み込む予定です。彼らが行っている作業の一部を見てみましょう。

標準C++ におけるセキュアなダウン・キャスト
class A {
    virtual void foo() {};
};
class B : public A {};
A* p_A = new B();
B* p_B = dynamic_cast<B*>( p_A );

ここで問題がある場合には、p_B にゼロ・ポインターが入ります。wxWindowsでは、ランタイムの型情報用にマクロ・ベースのシステムが使用されますが、上記の標準C++ コードの場合、次のようなwxDynamicCast() マクロを使用する必要があります。

標準C++ の場合のwxDynamicCast() マクロ
B* p_B = wxDynamicCast( p_A, B );

キャストが失敗すると、p_B にゼロ・ポインターが入ります。新しいキャスト構文をサポートするような実装では、このマクロはdynamic_cast<> に拡張されます。しかし残念なことに、このマクロはポインターにだけ使用することができ、参照に使用することはできません。wxDynamicCast() マクロのほかに、wxStaticCast() マクロとwxConstCast() マクロもあります。

wxWindowsのストリング・クラスwxString は、標準ストリング・クラスのメソッドのうちの90%を提供します。例をいくつか示します。

wxWindowsのwxString
wxString s1 = "Hello, World!";
wxString s2 = "Hello";
s2.erase();
for ( size_t i = 0; i< s1.length(); ++i )
    s2 += s1[i];
if ( s1.compare( s2 ) == 0 ) {
    // Strings are equal
}

ここでtypedefwxStringstd::string とすると、wxWindowsと標準C++ の両方に合わせてコーディングすることができます。

ドキュメンテーション

wxWindowsのドキュメンテーションは、現時点では完全とは言えません。wxString のような「古い」クラスについては十分に文書化されていますが、wxGrid のような最近になって実装されたクラスや、wxGLCanvas のようなあいまいなクラスについては、改善の余地があります。主要なドキュメンテーションは、ライブラリーとその概念、アルファベット順のクラス・リファレンス、プログラミング戦略、トピックの概要、およびwxHTMLとwxPythonに関する注意を簡単に紹介するもので、HTML、WinHelp、MS HTMLヘルプ、およびPDFの形で使用することができます (参考文献を参照)。

wxWindowsを初めて使用する場合には、トピックの概要から始めるようにしてください。これには、デバッグ、イベント処理、印刷などの共通トピックに関する多くの基本的な情報とコード・サンプルが記載されています。主要ドキュメンテーションでは、技術的な注意およびチュートリアルも少し含まれていて、wxWindowsの学習方法に関する比較的共通の疑問からコンパイラー特定の疑問まで、広い範囲のトピックについての情報が提供されます。また、サポートされるプラットフォームに関するインストールおよびリリース情報を含む、多くのプレーン・テキスト・ファイルも提供されます。wxWindowsディストリビューションは、ドキュメンテーションとともに、約50のサンプル・アプリケーションも提供します。

サポート

ライブラリーを使用しているときに問題が生じ、ドキュメンテーションにその解決法が示されていない場合には、どのようにしたら良いのでしょうか? 心配は要りません。一般に、メーリング・リストを使用する無料サポートと、商用サポートの、2つのサポート・オプションが用意されています。残念なことに、すぐに回答を得たい場合には、おそらく、商用サポートを使用したほうが良いでしょう。中核的な開発者たちは常にメーリング・リストに目を通していますが、忙しすぎてすぐには返事を出せないことがよくあります。しかし、普通は、1日程度で回答が得られると期待できます。(異例な、あるいは複雑なことを質問した場合には、質問を再掲示する前に少なくとも2日は待つ必要があります。) 最新のソースには、SourceforgeのCVSソース・コード・データベースでアクセスすることができます (参考文献を参照)。

まとめ

以上で、wxWindowsがどのようなものであるのか、また、マルチプラットフォーム開発にどのように役立つのか、よく分かっていただけたと思います。しかし、もちろん、これだけで十分というわけではありません。たとえば、現在のwxStudioプロジェクトがあります。これは、wxWindowsを使用するIDEのようなMicrosoft Visual Studioを開発中です。また、wxCVSプロジェクトは、CVSシステム用のマルチプラットフォーム・グラフィカル・インターフェースとなる予定です。また、wxDesignerは、Robert Roeblingによって開発された、wxWindowsダイアログを組み立てるためのRADツールです。wxWindowsコミュニティーは成長途上ですので、次に見るときにはマルチプラットフォーム・プロジェクトが出番を待っていることでしょう。

ここに記載したすべての商品名は、それぞれの所有者の商標または登録商標です。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux
ArticleID=231487
ArticleTitle=wxWindowsの概要
publish-date=02012001