目次

Qt tips

QDialogで表示したダイアログを閉じたときの挙動

OSのクローズボタンを押したとき:QWidget::closeEvent()が呼ばれる。 ESCキーを押したとき:QDialog::reject()→QDialog::done®の順番に呼ばれる。

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 <QDialog>
#include "ui_MyDialog.h"

class LibMyDialog : public QDialog, public Ui::MyDialog
{
public:
    LibMyDialog(QWidget *parent = 0) : QDialog(parent) {
        setupUi(this);
        ....
    }
    ....
};

のように多重継承を使って実装するが、汎用ウィジェットとしてライブラリ化しようとした時、この書き方だとui_MyDialog.hに依存する事になり大変美しくない。 代わりに

#include <QDialog>
 
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コッチ(・∀・)コイ!!