Qt最新事情-QtでWebKitを使ってみよう

第3回 Qtの基本プログラミング~オブジェクトモデル

この記事を読むのに必要な時間:およそ 6 分

1.子ウィジェットのメモリ解放の自動化

親オウィジェットのメモリ解放時にオブジェクトツリーを辿って,その配下(親子関係の繋がりのあるウィジェット)の全ウィジェットのメモリ解放を自動的に行なっています。

デストラクタでのウィジェットのメモリ解放が不要となり,メモリ解放の確実性が高まります。後から参照するウィジェットの他には,メンバー変数でオブジェクトを抱えておく必要がなくなり,コードがすっきりします。

QTimerクラスなどのQObjectを継承した非GUIクラスも親ウィジェットを指定してインスタンス生成して,メモリ解放を連動させられます。QObjectを継承していないクラスについては,通常のC++のインスタンスの扱いと同じようにしてメモリ解放をします。

2.オブジェクトツリー内のオブジェクト検索

以下のようにして,オブジェクトツリー内のオブジェクトを検索し,ウィジットを操作できます。

QLabel* label = colorChooser->findChild<QLabel*>("redLabel");
QList<QLabel*> labels = colorChooser->findChildren<QLabel*>();
// ここでラベルのプロパティを変更する

ここで,QLabelのインスタンスには,以下のようにてオブジェクト名が付けられているものとしています。

redLabel->setObjectName("redLabel");

3 親ウィジェットの表示/非表示に応じて,配下のウィジェットを表示/非表示する。

show()を呼び出して親ウィジェットを表示状態にしたときに,その配下のウィジェットを自動的に表示します。hide()を呼び出すと非表示にします。

4 親ウィジェットの有効化/無効化に応じて,配下のウィジェットを有効化/無効化する。

setEnabled(true)を呼び出して親ウィジェットを有効化したときに,その配下のウィジェットを自動的に有効化します。setEnabled(false)を呼び出すと無効化します。

表示/非表示と有効化/無効化は,それぞれ三値状態で管理されているので,子ウィジェットが明示的にhide()やsetEnabled(false)を呼び出していると,親ウィジェットのshow()やsetEnabled(true)の呼び出しに,子ウィジェットは追従しなくなります。

子ウィジェットの自動メモリ解放に関連して,暗黙の共有クラスについても触れておきます。Qtでは,文字列,フォント,ピックスマップなどのリソースやコレクションクラスは,リファレンスカウント付きのクラスとして実装されていて,値ベースでデータを扱えるようにしています。関数の戻り値としてQStringやQPixmapのインスタンスを返しても文字列やイメージ領域の本体はコピーされません。コレクションクラスについても同様です。共有リソースに変更が行われようとするときに,データが実際にコピーされて変更が行われ,リファレンスカウントも変更されます。そして,リファレンスカウントが0になったときに,Qtライブラリーが自動的にメモリ領域を解放します。一般に,値ベースでデータを扱えるとコードが簡潔で明瞭になり,メモリ解放も確実にできて安定性が向上します。

表2 暗黙の共有クラス

QBitArray               QKeySequence            QSet
QBitmap                 QLinkedList             QSqlField
QBrush                  QList                   QSqlQuery
QByteArray              QLocale                 QSqlRecord
QCache                  QMap                    QStack
QCursor                 QMultiHash              QString
QDir                    QMultiMap               QStringList
QFileInfo               QPainterPath            QTextBoundaryFinder
QFont                   QPalette                QTextCursor
QFontInfo               QPen                    QTextDocumentFragment
QFontMetrics            QPicture                QTextFormat
QFontMetricsF           QPixmap                 QUrl
QGLColormap             QPolygon                QVariant
QGradient               QPolygonF               QVector
QHash                   QQueue                  QX11Info
QIcon                   QRegExp
QImage                  QRegion

オブジェクトプロパティ

QObjectの継承クラスに任意のプロパティを持たせることができ,オブジェクトにどのようなプロパティがあるかを検索して,プロパティの参照と変更ができます。

リスト2 ウィジェットのプロパティ定義

class Person : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QString name  READ name WRITE setName);
    Q_PROPERTY(int age READ age WRITE setAge);

public:
    explicit Person(QObject* parent = 0);

    QString name() const;
    int age() const;

public slots:
    void setName(const QString& name);
    void setAge(int age);
...
};

リスト3 プロパティ宣言

Q_PROPERTY(type name
           READ getFunction
           [WRITE setFunction]
           [RESET resetFunction]
           [DESIGNABLE bool]
           [SCRIPTABLE bool]
           [STORED bool]
           [USER bool])

リスト2では,nameとageの2つのプロパティを宣言しています。アクセッサに対してQ_PROPERTYマクロでプロパティ宣言を記述すると,property()メソッドを使ってプロパティ名でプロパティにアクセスできるようになります。READアクセッサは必須で,プロパティ名とREADアクセッサ名は異なっても構いません。実際にプロパティにアクセスするコードは次のようになります。

リスト4 プロパティにアクセスする例

QListIterator<PersonPtr> it(personList);
while (it.hasNext()) {
    PersonPtr p = it.next();
    QVariant name = p->property("name");
    QVariant age = p->property("age");
    QVariant weight = p->property("weight");

    qDebug() << (name.isValid() ? name.toString() : "----")
             << (age.isValid() ? age.toInt() : -1 )
             << (weight.isValid() ? weight.toInt() : -1 );
    if ( age.isValid() )
        p->setProperty("age", p->property("age").toInt() * 2 );
}

weightプロパティは宣言されていないので,通常は未定義になりますが,実行中にsetProperty()で未定義のプロパティに値を設定するとその時点でプロパティが定義されます。これをダイナミックプロパティと呼びます。

QVariantは,コピー可能な任意のオブジェクトをひとつ抱える機能を持つクラスです。C++の組込み型とQtのクラスは扱えるようになっていて,Qtのタイプシステムによってユーザ定義型も扱えます。

著者プロフィール

杉田研治(すぎたけんじ)

1955年生まれ。東京都出身。株式会社SRAに勤務。プログラマ。

仕事のほとんどをMac OS XとKubuntu KDE 4でQtと供に過ごす。