界面开发框架Qt - 组合小部件映射器示例

发布时间:2026/8/15 14:19:59
界面开发框架Qt - 组合小部件映射器示例 Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写所有平台无差别运行更提供了几乎所有开发过程中需要用到的工具。如今Qt已被运用于超过70个行业、数千家企业支持数百万设备及应用。Combo Widget Mapper组合小部件映射器示例展示了如何使用自定义委托将信息从模型映射到表单上的特定小部件。在简单小部件映射器Simple Widget Mapper Example示例中我们展示了小部件映射器的基本用法将模型公开的数据与用户界面中的简单输入小部件联系起来。然而有时我们希望使用输入小部件将数据作为选项公开给用户例如QComboBox并且需要一种方法将用户的输入与存储在模型中的值关联起来。这个示例与简单部件映射器示例非常相似同样创建了一个具有几乎相同用户界面的Window类除了提供一个旋转框以便输入每个人的年龄之外还提供了一个组合框来允许他们的地址被分类为“Home”、“Work”或“Other”。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::Window(QWidget *parent) : QWidget(parent) { setupModel(); nameLabel new QLabel(tr(Name:)); 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 qt123 Main Streetbr/Market Town/qt qtPO Box 32br/Mail Handling Service br/Service City/qt qtThe Lighthousebr/Remote Island/qt qt47338 Park Avenuebr/Big City/qt qtResearch Stationbr/Base Campbr/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所持有的选项都存储在一个地方将会非常有用。