コンボウィジェットマッパーの例

コンボウィジェットマッパーの例では、カスタムデリゲートを使ってモデルからフォーム上の特定のウィジェットに情報をマッピングする方法を示します。

各人の年齢を入力できるようにスピンボックスを提供する代わりに、住所を "自宅"、"職場"、"その他" に分類できるようにコンボボックスを提供することを除いて、ほぼ同じユーザインタフェースを持つWindow クラスを作成します。

ウィンドウクラスの定義

このクラスはコンストラクター、ボタンを最新の状態に保つスロット、モデルをセットアップするプライベート関数を提供します:

class Window : public QWidget
{
    Q_OBJECT

public:
    Window(QWidget *parent = nullptr);

private slots:
    void updateButtons(int row);

private:
    void setupModel();

    QLabel *nameLabel;
    QLabel *addressLabel;
    QLabel *typeLabel;
    QLineEdit *nameEdit;
    QTextEdit *addressEdit;
    QComboBox *typeComboBox;
    QPushButton *nextButton;
    QPushButton *previousButton;

    QStandardItemModel *model;
    QStringListModel *typeModel;
    QDataWidgetMapper *mapper;
};

QDataWidgetMapper オブジェクトとユーザーインターフェイスを構成するためのコントロールに加えて、データを保持するためにQStandardItemModel 、各人のデータに適用できる住所の種類に関する情報を保持するためにQStringListModel

ウィンドウ・クラスの実装

Window クラスのコンストラクタは3つの部分に分けて説明できる。最初の部分では、ユーザー・インターフェースに使用するウィジェットを設定します:

Window::Window(QWidget *parent)
    : QWidget(parent)
{
    setupModel();

    nameLabel = new QLabel(tr("Na&me:"));
    nameEdit = new QLineEdit();
    addressLabel = new QLabel(tr("&Address:"));
    addressEdit = new QTextEdit();
    typeLabel = new QLabel(tr("&Type:"));
    typeComboBox = new QComboBox();
    nextButton = new QPushButton(tr("&Next"));
    previousButton = new QPushButton(tr("&Previous"));

    nameLabel->setBuddy(nameEdit);
    addressLabel->setBuddy(addressEdit);
    typeLabel->setBuddy(typeComboBox);

    typeComboBox->setModel(typeModel);

コンボボックスのマッピングは他のウィジェットと同じように設定しますが、独自のモデルを適用して、各人のデータを含むモデルからではなく、独自のモデルであるtypeModel からのデータを表示するようにしていることに注意してください。

次に、ウィジェット・マッパーをセットアップし、各入力ウィジェットをsetModel() の呼び出しで指定されたモデルの列に関連付けます:

    mapper = new QDataWidgetMapper(this);
    mapper->setModel(model);
    mapper->addMapping(nameEdit, 0);
    mapper->addMapping(addressEdit, 1);
    mapper->addMapping(typeComboBox, 2, "currentIndex");

コンボボックスについては、モデルからの値に関連付けるプロパティをウィジェットマッパーに伝えるために、追加の引数を渡します。その結果、ユーザはコンボボックスから項目を選択でき、ウィジェットのcurrentIndex プロパティに格納された対応する値がモデルに格納されます。

コンストラクタの残りの部分では、接続とレイアウトを設定します:

    connect(previousButton, &QAbstractButton::clicked,
            mapper, &QDataWidgetMapper::toPrevious);
    connect(nextButton, &QAbstractButton::clicked,
            mapper, &QDataWidgetMapper::toNext);
    connect(mapper, &QDataWidgetMapper::currentIndexChanged,
            this, &Window::updateButtons);

    QGridLayout *layout = new QGridLayout();
    layout->addWidget(nameLabel, 0, 0, 1, 1);
    layout->addWidget(nameEdit, 0, 1, 1, 1);
    layout->addWidget(previousButton, 0, 2, 1, 1);
    layout->addWidget(addressLabel, 1, 0, 1, 1);
    layout->addWidget(addressEdit, 1, 1, 2, 1);
    layout->addWidget(nextButton, 1, 2, 1, 1);
    layout->addWidget(typeLabel, 3, 0, 1, 1);
    layout->addWidget(typeComboBox, 3, 1, 1, 1);
    setLayout(layout);

    setWindowTitle(tr("Delegate Widget Mapper"));
    mapper->toFirst();
}

モデルはウィンドウのsetupModel() 関数で初期化されます。ここでは、5行3列の標準モデルを作成します。各行には、名前、住所、住所のタイプを示す値を挿入する。住所のタイプは、文字列リストモデルに格納されます。

void Window::setupModel()
{
    QStringList items;
    items << tr("Home") << tr("Work") << tr("Other");
    typeModel = new QStringListModel(items, this);

    model = new QStandardItemModel(5, 3, this);
    QStringList names;
    names << "Alice" << "Bob" << "Carol" << "Donald" << "Emma";
    QStringList addresses;
    addresses << "<qt>123 Main Street<br/>Market Town</qt>"
              << "<qt>PO Box 32<br/>Mail Handling Service"
                 "<br/>Service City</qt>"
              << "<qt>The Lighthouse<br/>Remote Island</qt>"
              << "<qt>47338 Park Avenue<br/>Big City</qt>"
              << "<qt>Research Station<br/>Base Camp<br/>Big Mountain</qt>";

    QStringList types;
    types << "0" << "1" << "2" << "0" << "2";

    for (int row = 0; row < 5; ++row) {
      QStandardItem *item = new QStandardItem(names[row]);
      model->setItem(row, 0, item);
      item = new QStandardItem(addresses[row]);
      model->setItem(row, 1, item);
      item = new QStandardItem(types[row]);
      model->setItem(row, 2, item);
    }
}

各行をモデルに挿入すると、データベースのレコードのように、typeModel の各人の住所タイプの項目に対応する値が格納されます。ウィジェットマッパーが各行の最後の列からこれらの値を読み取るとき、次の図に示すように、typeModel の値への参照として使用する必要があります。ここで、デリゲートが使用されます。

念のため、updateButtons() スロットの実装を示します:

void Window::updateButtons(int row)
{
    previousButton->setEnabled(row > 0);
    nextButton->setEnabled(row < model->rowCount() - 1);
}

まとめと参考文献

コンボボックスに別のモデルを使用することで、メインモデルに格納されたデータとは別の選択肢のメニューが提供されます。コンボボックスのcurrentIndex プロパティをモデルのカラムに関連付ける名前付きマッピングを使用することで、ルックアップ値を効果的にモデルに格納することができます。

しかし、ウィジェットマッパーのコンテキスト外でモデルを読み取る場合、これらのルックアップ値を理解するために、typeModel について知る必要があります。typeModel によって保持されるデータと選択肢の両方を1つの場所に格納できると便利です。これはSQL Widget Mapper Exampleでカバーされています。

サンプルプロジェクト @ code.qt.io

©2024 The Qt Company Ltd. 本書に含まれるドキュメントの著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。