组合小部件映射器示例

组合小部件映射器示例演示了如何使用自定义代理将模型信息映射到表单上的特定小部件。

我们创建了一个具有几乎相同用户界面的 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 类的构造函数可以分为三个部分。在第一部分中,我们设置了用于用户界面的控件

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

总结和进一步阅读

使用独立的模型为组合框提供一组选项菜单,这些选项与主模型中存储的数据是分开的。通过使用命名映射,将组合框的《code translate="no">currentIndex`》属性与模型中的列相关联,我们可以有效地在模型中存储查找值。

然而,当我们不在小部件映射的上下文中读取模型时,我们需要了解《code translate="no">typeModel`才能理解这些查找值。能够将“typeModel”所持有数据和选项存储在一个地方会很有用。这可以通过《a href="qtsql-sqlwidgetmapper-example.html" translate="no">SQL小部件映射示例》》来实现。

示例项目 @ code.qt.io

© 2024 Qt公司有限公司。包含在此处的文档贡献的版权归其各自的所有者。提供的文档受自由软件基金会发布的《a href="http://www.gnu.org/licenses/fdl.html">GNU自由文档许可协议第1.3版》的条款许可。Qt及其 respective标志是芬兰以及/或其他国家的The Qt Company Limited的商标。所有其他商标均为其各自所有者的财产。