wxWidgets が port ごとにいろいろ微妙な件について。

wxWidgets 使うと、どの環境でも同じソースコードで動くから幸せ。 のはずなんだが、実際そううまくはいかなくて、 あっちでは動くけどこっちでは動かないことがわりとある。 というか、中の人修正よろ。 バージョンは wxWidget 2.8.10、 port は wxGTK と wxMac が主な対象。


1. wxBitmap の深度指定
wxBitmap(wxImage& image, int depth = -1) 形式のコンストラクタで、 wxMSW では depth を 24 のように指定しても動作するらしい (そういうサンプルを見たことがある) が、 wxGTK では depth == -1 に (つまり省略) しなければ動かない。 詳しいことはシラン。

2. wxDC::Blit の転送先範囲
wxGTK では wxDC::Blit での転送矩形が、描画エリアを越えていても転送できる。 つまり例えば (100 x 100) のキャンバスに width = 200 のようなソース DC から の転送は行える。はみ出た部分は無視されるようだ。 wxMac では ASSERT() にひっかかるため、 結局転送範囲がはみ出ないように指定すること。

3. wxUpdateUIEvent (EVT_UPDATE_UI)
wxMac では wxITEM_NORMAL なアイテムに EVT_UPDATE_UI を指定すると ASSERT が起きて使えないようだ。 てかこれ、バグだと思うんだけど。

4. wxSizeEvent (EVT_SIZE)
wxGTK ではウィンドウ作成時 (だと思うんだけど、細かいタイミングは調べてない) に EVT_SIZE イベントが飛んでくるが、 wxMac ではこのイベントは飛んでこない。 Windows の MFC でも同様のイベントは飛んでくるらしいので、 それを前提にプログラムを書いていると wxMac では動作しない。
…ではなくて、 wxMac ではコントロールを Sizer に貼り付ける時点で、 コントロールが 1x1 以上の大きさを持っておかなければならないらしい。 以下のような形式でコントロールを Sizer にセットする書式は サンプルを含めて広く使われていると思うので、 このケースを考えると少なくともコンストラクタでサイズを持つ必要があることになる (し、持っておくべきだと思う)。
sizer->Add(new Control(...));
wxGTK、wxMSW ではサイズ 0x0 のコントロールを貼り付けても EVT_SIZE が 飛んでくるのでそこで改めてサイズ変更を行うことが出来るが、 wxMac ではサイズ 0x0 のコントロールを貼り付けると、以後 EVT_SIZE が 飛んでこないので (というかコントロール自体がなかったことになっている?)、 サイズは 0x0 のまま変更出来なくなってしまう。 コンストラクタで決定したサイズを後から変えることは (前述のように EVT_SIZE さえ飛んでくれば) 可能なので、 ダミーでもよいかも知れないので 1x1 以上のサイズをセットしておくこと。

5. wxDialog で Show()
以下のコードのように wxDialog を継承したクラスのコンストラクタで、 (基本クラス wxWindow の) Show() を実行してしまっても wxGTK/wxMSW ではダイアログは問題なく動作する (してしまう)が、 wxMac ではダイアログが正しく動作しない。 Show() を使うのが誤りなので、動作しない wxMac のほうがおそらく正しそうだが、 wxGTK/wxMSW ではこう書いてあっても動作してしまうため誤りに気付かない。
class MyDialog : public wxDialog
{
 public:
    MyDialog() {
        /* コントロールを置いて */

        Show();	/* ← 誤り */
    };
};

MyDialog *dialog = new MyDialog();
dialog->ShowModal();

6. サイザーとパネル
wxGTK、wxMac ではウィンドウというかフレームに直接サイザーを置いても問題ないが、 wxMSW では wxPanel を敷いて、その上にサイザーを置かないと、 デフォルト背景色より濃い何か下地のような色(?)が見えてしまう。
MyFrame::MyFrame(...)
{
#if 0
    /* 誤。ただし wxGTK、wxMac では問題なく見える */
    wxBoxSizer *topsizer = new wxBoxSizer(...);
    wxSomeCtrl *ctrl = new wxSomeCtrl(this, wxID_ANY, ...);
    topsizer->Add(ctrl);
    SetSizer(topsizer);
    :
#else
    /* 正。wxMSW でも問題なく見える */
    wxPanel *panel = new wxPanel(this, wxID_ANY);
    wxBoxSizer *topsizer = new wxBoxSizer(...);
    wxSomeCtrl *ctrl = new wxSomeCtrl(panel, wxID_ANY, ...);
    topsizer->Add(ctrl);
    panel->SetSizer(topsizer);
	:
#endif
}

7. wxFileName
wxFileName は一見便利だが、 用意されてるほとんどのメンバが信頼性が低いので、 基本的に避けたほうがいいような気がする。 誰か正しい使い方教えてくだしあ。
  1. wxFileName::Assign() は最後のディレクトリコンポーネントが必ずファイルとみなされてしまうため、 ディレクトリパスを設定することが出来なかった気がする。
  2. wxFileName::IsDirReadable() は wxMSW でファイルに対しても真を返すことがあったような気がする。 代わりにグローバル関数の ::wxDirExists() を使うべき。

8. wxTextFont::IsFixedWidth()
wxTextFont::IsFixedWidth() は wxMSW で固定幅フォントでも偽を返すことがあるらしい。 詳細未確認。

変更履歴
2010-04-13
初稿。
2010-10-25
4. EVT_SIZE について少し分かったので訂正。
2010-12-02
5. wxDialog::Show() を追加。
2012-06-21
6. サイザーとパネルを追加。
2013-02-02
7, 8 を追加。

$Id: wxwidgets.php,v 1.6 2013/02/02 06:05:44 isaki Exp $
isaki@NetBSD.org