Combo Widget Mapper Beispiel

Das Combo Widget Mapper-Beispiel zeigt, wie man einen benutzerdefinierten Delegaten verwendet, um Informationen aus einem Modell auf bestimmte Widgets in einem Formular zuzuordnen.

Wir erstellen eine Klasse Window mit einer fast identischen Benutzeroberfläche, mit der Ausnahme, dass wir anstelle eines Drehfelds, in das das Alter jeder Person eingegeben werden kann, ein Kombinationsfeld bereitstellen, mit dem die Adressen als "Privat", "Arbeit" oder "Sonstiges" klassifiziert werden können.

Definition der Fensterklasse

Die Klasse bietet einen Konstruktor, einen Slot, um die Schaltflächen auf dem neuesten Stand zu halten, und eine private Funktion, um das Modell einzurichten:

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;
};

Neben dem Objekt QDataWidgetMapper und den Steuerelementen, die für die Benutzeroberfläche verwendet werden, verwenden wir ein QStandardItemModel, um unsere Daten zu speichern, und ein QStringListModel, um Informationen über die Adresstypen zu speichern, die auf die Daten jeder Person angewendet werden können.

Implementierung der Fensterklasse

Der Konstruktor der Klasse Window kann in drei Teilen erklärt werden. Im ersten Teil werden die Widgets eingerichtet, die für die Benutzeroberfläche verwendet werden:

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);

Beachten Sie, dass wir die Abbildung des Kombinationsfeldes auf die gleiche Weise wie für andere Widgets einrichten, aber dass wir ihm sein eigenes Modell zuweisen, damit es Daten aus seinem eigenen Modell, dem typeModel, anzeigt und nicht aus dem Modell, das Daten über jede Person enthält.

Als Nächstes richten wir den Widget-Mapper ein, der jedes Eingabe-Widget mit einer Spalte in dem durch den Aufruf von setModel() angegebenen Modell verknüpft:

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

Für das Kombinationsfeld übergeben wir ein zusätzliches Argument, um dem Widget-Mapper mitzuteilen, welche Eigenschaft mit Werten aus dem Modell verknüpft werden soll. Als Ergebnis kann der Benutzer ein Element aus der Combobox auswählen, und der entsprechende Wert, der in der Eigenschaft currentIndex des Widgets gespeichert ist, wird im Modell gespeichert.

Der Rest des Konstruktors richtet Verbindungen und Layouts ein:

    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();
}

Das Modell wird in der Funktion setupModel() des Fensters initialisiert. Hier erstellen wir ein Standardmodell mit 5 Zeilen und 3 Spalten. In jede Zeile fügen wir einen Namen, eine Adresse und einen Wert ein, der die Art der Adresse angibt. Die Adresstypen werden in einem Stringlistenmodell gespeichert.

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);
    }
}

Wenn wir jede Zeile in das Modell einfügen, speichern wir wie einen Datensatz in einer Datenbank Werte, die den Elementen in typeModel für den Adresstyp jeder Person entsprechen. Wenn der Widget-Mapper diese Werte aus der letzten Spalte jeder Zeile liest, muss er sie als Verweise auf Werte in typeModel verwenden, wie im folgenden Diagramm dargestellt. An dieser Stelle kommt der Delegat zum Einsatz.

Der Vollständigkeit halber zeigen wir die Implementierung des updateButtons() Slots:

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

Zusammenfassung und weiterführende Literatur

Die Verwendung eines separaten Modells für das Kombinationsfeld bietet ein Menü mit Auswahlmöglichkeiten, die von den im Hauptmodell gespeicherten Daten getrennt sind. Die Verwendung eines benannten Mappings, das die Eigenschaft currentIndex des Kombinationsfeldes mit einer Spalte im Modell verknüpft, ermöglicht es uns, einen Nachschlagewert im Modell zu speichern.

Wenn wir jedoch das Modell außerhalb des Kontexts des Widget-Mappers lesen, müssen wir über typeModel Bescheid wissen, um diese Nachschlagewerte sinnvoll nutzen zu können. Es wäre nützlich, sowohl die Daten als auch die Auswahlmöglichkeiten von typeModel an einem Ort zu speichern. Dies wird durch das SQL Widget Mapper Beispiel abgedeckt.

Beispielprojekt @ code.qt.io

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.