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