====== Qt tips ====== ===== QDialogで表示したダイアログを閉じたときの挙動 ===== OSのクローズボタンを押したとき:QWidget::closeEvent()が呼ばれる。 ESCキーを押したとき:QDialog::reject()→QDialog::done(r)の順番に呼ばれる。 http://lists.trolltech.com/qt-interest/2006-06/thread00968-0.html ===== QAbstractItemView用のモデルを自作するときの注意 ===== QAbstractItemModel系を継承して読込み専用(外部のデータソースを参照してItemModelに変換するような場面を想定)のモデルを作る時は、データソースが変更されたタイミングでlayoutChanged()シグナルを発行しなければならない。多分。 さもないと、Viewが更新されなくて超ハマル。丸一日くらいハマル。 恐らく、データソースが更新された事を検知出来ないため、Viewが更新されないんだと思う。 ===== DesignerでデザインしたUIを含むウィジェットライブラリを作る方法 ===== 【追記:2009/10/15】 QUiLoaderまたはQFormBuilderを使った方がいいかも? 通常、Designerで作ったUIを含むウィジェットを使うときは #include #include "ui_MyDialog.h" class LibMyDialog : public QDialog, public Ui::MyDialog { public: LibMyDialog(QWidget *parent = 0) : QDialog(parent) { setupUi(this); .... } .... }; のように多重継承を使って実装するが、汎用ウィジェットとしてライブラリ化しようとした時、この書き方だとui_MyDialog.hに依存する事になり大変美しくない。 代わりに #include class LibMyDialog : public QDialg { class Ui_MyDialog *mUI; public: LibMyDialog(QWidget *parent = 0) : QDialog(parent) { mUI = new Ui_MyDialog; mUI->setupUI(this); .... } }; という風に書くと、いい感じになる(面倒だったので、ここではヘッダにコンストラクタ書いてるけど、実際はcpp側に実装してね)。 この書き方だとUI部品と名前が衝突する事もないし、通常のアプリでもこっちの書き方の方がいいのかも・・・? この書き方が正しいかどうかは不明。一応ちゃんと動いてはいるけど。 ===== qmakeの -unix と -win32 の違い ===== unixだとdebugビルドの場合でも、リンクされるDLLはリリース用のヤツ(ファイル名に"d"が付いてないヤツ。QtCore4.dllとか)になってしまう模様。 debugビルドなexeを実行しようとすると、assert等のデバッグ用シンボルがリリースDLLに含まれていないため、シンボルが見つからねーとエラーを吐く。emacsでgdbデバッグが出来なかったのもその為だと思われる。 でも、Qt Command Promptからだと実行もgdbも使える。謎。 c:4Qt/2009.02/qt/mkspecs/features/qt_functions.prf の isEmpty(LINKAGE) { CONFIG(debug, debug|release) { win32:LINKAGE = -l$${LIB_NAME}$${QT_LIBINFIX}d mac:LINKAGE = -l$${LIB_NAME}$${QT_LIBINFIX}_debug } ... という部分に、 unix:LINKAGE = -l$${LIB_NAME}$${QT_LIBINFIX}d を追加してやれば、unixモードでもデバッグDLLがリンクされる。 システムファイルを直接書き換えるのは美しくないが、現状これしか対策方法が見あたらない…。 スレッドやRTTI、STLまわりの扱いも違うみたいだが、詳しくは知らない。 ===== 参考リンク ===== CheckBox in QComboBox http://da-crystal.net/GCMS/blog/checkboxlist-in-qt/ ===== mocの罠? ===== 自分でslotを作る場合、マクロを使うと危険っぽい。 例えば、次のような処理内容が殆ど一緒のslotを作りたいとする。 void changeState_A(int state) { this->setState('A', state); } void changeState_B(int state) { this->setState('B', state); } void changeState_C(ins state) { this->setState('C', state); } ここで楽をしようと、クラス宣言内で public slots: #define SLOT_MAKER(name) void changeState_##name (int state) { 略 } SLOT_MAKER(A); SLOT_MAKER(B); SLOT_MAKER(C); などと書くと、SLOT_MAKERは展開されず、SLOT_MAKER(...)自体が関数と見なされてmocが生成されてしまう。 超罠。 一手間増えるが、ヘッダではslot関数名をしっかりと記述し、cppの方でマクロで関数を組み立てる分には問題ない。 ===== 続・mocの罠 ===== 既存のクラスにQ_OBJECTマクロを追加した場合は、qmakeし直す必要あり。 さもないとコンパイル時に「vtableがふがふが」という、一見意味不明なエラーでハマる事になる。 ===== QString→C文字列の変換 ===== QString str("hoge"); QByteArray byteArray(str.toAscii()); const char *cStr = byteArray.constData(); // cStr = 'hoge\0' 文字コード?そんなのキニシナイ(・∀・) ===== unistd.hのusleep, sleep関数っぽいウェイトを使いたい ===== DOS窓が開いてもいいなら、QTestのqWait, qSleepが使える。 嫌なら QTime dieTime = QTime::currentTime().addSecs(5); // 5秒後 while( QTime::currentTime() < dieTime ) QCoreApplication::processEvents(QEventLoop::AllEvents, 100); こんな感じでおk。addSecs()の代わりにaddMSecs() も使える。 ===== signalとslotを繋いだまま、一時的に特定オブジェクトのsignalの発行を止めたい ===== QObject::blockSignals(bool)を使えば実現できるぞ! connect(HogeListWidget, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(listChanged())); ... HogeListWidget->blockSignals(true); // signalアッチ(・A・)イケ!! HogeListWidget->addItem("Item 1"); // listChanged()は呼ばれない HogeListWidget->blockSignals(false); // signalコッチ(・∀・)コイ!!