各行业网站建设方案书,连锁销售官网,莱芜论坛话题,网站实例1. Qt 模型视图代理
Qt 模型视图代理#xff0c;也可以称为 MVD 模式 模型(model)、视图(view)、代理(delegate)主要用来显示编辑数据 1.1 模型
模型 (Model) 是视图与原始数据之间的接口 原始数据可以是#xff1a;数据库的一个数据表、内存中的一个 StringList#xff…1. Qt 模型视图代理
Qt 模型视图代理也可以称为 MVD 模式 模型(model)、视图(view)、代理(delegate)主要用来显示编辑数据 1.1 模型
模型 (Model) 是视图与原始数据之间的接口 原始数据可以是数据库的一个数据表、内存中的一个 StringList磁盘文件结构等QAbstractItemModel 是所有模型的祖宗类其它 model 类都派生于它 1.2 视图
视图 (View) 是显示和编辑数据的界面组件 主要的视图组件有 QListView、QTreeView 和 QTableViewQListWidget、QTreeWidget 和 QTableWidget 是视图类的简化版 它们不使用数据模型而是将数据直接存储在组件的每个项里 QAbstractItemView 是所有视图的祖宗类其它 view 类都派生于它 1.3 代理
代理 (Delegate) 为视图组件提供数据编辑器 如在表格组件中编辑一个单元格的数据时缺省是使用一个 QLineEdit 编辑框代理负责从数据模型获取相应的数据然后显示在编辑器里修改数据后又将其保存到数据模型中
2. QTableView 应用 tableView.proQT core gui// 使用 QAxObject 需添加下行
// The QAxObject class provides a QObject that wraps a COM object.
greaterThan(QT_MAJOR_VERSION, 4): QT widgets axcontainer2.1 widget.ui 2.2 主窗口
2.2.1 widget.h
#ifndef WIDGET_H
#define WIDGET_H#include QWidget
#include QStandardItemModel
#include QItemSelectionModel
#include cintspindelegate.h
#include cfloatspindelegate.h
#include ccomboboxdelegate.hQT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);~Widget();private slots:void on_btnOpenExcel_clicked();void on_btnReshowData_clicked();void OnCurrentChanged(const QModelIndex current, const QModelIndex previous);void on_btnAppendLast_clicked();void on_btnAppend_clicked();void on_btnDeleteSelectedLine_clicked();private:Ui::Widget *ui;QStandardItemModel *m_pItemModel; // 数据模型QItemSelectionModel *m_pSelectionModel; // Item 选择模型CIntSpinDelegate m_intSpinDelegate; // 整型数 spinbox 代理CFloatSpinDelegate m_floatSpinDelegate; // 浮点数 spinbox 代理CComboBoxDelegate m_comboBoxDelegate; // combobox 代理
};
#endif // WIDGET_H2.2.2 widget.cpp
#include widget.h
#include ui_widget.h
#include QAxObject
#include QFileDialog
#include QStandardPathsstatic const int COLUMN_COUNT 7;Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui-setupUi(this);showMaximized();m_pItemModel new QStandardItemModel(1, COLUMN_COUNT, this);m_pSelectionModel new QItemSelectionModel(m_pItemModel); // Item 选择模型// 选择当前单元格变化时的信号与槽connect(m_pSelectionModel, QItemSelectionModel::currentChanged, this, Widget::OnCurrentChanged);ui-tableView-setModel(m_pItemModel); // 设置数据模型ui-tableView-setSelectionModel(m_pSelectionModel); // 设置选择模型ui-tableView-setSelectionMode(QAbstractItemView::ExtendedSelection);ui-tableView-setSelectionBehavior(QAbstractItemView::SelectItems);// 给第 345 列设置自定义代理组件ui-tableView-setItemDelegateForColumn(3, m_floatSpinDelegate);ui-tableView-setItemDelegateForColumn(4, m_intSpinDelegate);ui-tableView-setItemDelegateForColumn(5, m_comboBoxDelegate);
}Widget::~Widget() {delete ui;
}// 打开 excel
void Widget::on_btnOpenExcel_clicked() {QAxObject *excel new QAxObject(this);excel-setControl(Excel.Application);excel-setProperty(Visible, false); // 显示窗体看效果选择 ture 将会看到 excel 表格被打开excel-setProperty(DisplayAlerts, true);QAxObject *workbooks excel-querySubObject(WorkBooks); // 获取工作簿(excel文件)集合QString str QFileDialog::getOpenFileName(this, u8打开excel,D:/MyQtCreatorProject/9_2_tableView,u8Excel 文件(*.xls *.xlsx));// 打开刚才选定的 excelworkbooks-dynamicCall(Open(const QString), str);QAxObject *workbook excel-querySubObject(ActiveWorkBook);QAxObject *worksheet workbook-querySubObject(WorkSheets(int),1);QAxObject *usedRange worksheet-querySubObject(UsedRange); // 获取表格中的数据范围QVariant var usedRange-dynamicCall(Value); // 将所有的数据读取到 QVariant 容器中保存QListQListQVariant excel_list; // 用于将 QVariant 转换为 Qlist 的二维数组QVariantList varRows var.toList();if (varRows.isEmpty()) {return;}const int row_count varRows.size();QVariantList rowData;for (int i 0; i row_count; i) {rowData varRows[i].toList();excel_list.push_back(rowData);}// 将每一行的内容放到 contentListQListQStringList contentList;for (int i 0; i row_count; i) {QListQVariant curList excel_list.at(i);int curRowCount curList.size();QStringList oneLineStrlist;for (int j 0; j curRowCount; j) {QString content curList.at(j).toString();oneLineStrlist content;}contentList oneLineStrlist;}workbook-dynamicCall(Close(Boolean), false);excel-dynamicCall(Quit(void));delete excel;// 解析 contentList填充 tableViewint rowCounts contentList.size();QStandardItem *aItem;// 遍历行for (int i 0; i rowCounts; i) {QStringList tmpList contentList[i];if(i 0) {// 设置表头m_pItemModel-setHorizontalHeaderLabels(tmpList);} else {int j;for (j 0; j COLUMN_COUNT - 1; j) {// 不包含最后一列aItem new QStandardItem(tmpList.at(j));m_pItemModel-setItem(i-1, j, aItem); // 为模型的某个行列位置设置 Item}// 设置最后一列aItem new QStandardItem(contentList[0].at(j)); // 获取最后一列的指针aItem-setCheckable(true); // 设置可以使用 check 控件if (tmpList.at(j) 0)aItem-setCheckState(Qt::Unchecked); // 根据数据设置 check 状态elseaItem-setCheckState(Qt::Checked);m_pItemModel-setItem(i-1 , j, aItem); // 设置最后一列}}
}// 选择单元格变化时的响应
void Widget::OnCurrentChanged(const QModelIndex current, const QModelIndex previous) {Q_UNUSED(previous);if (current.isValid()) { // 当前模型索引有效ui-textEdit-clear();ui-textEdit-append(QString::asprintf(u8当前单元格%d行%d列,current.row(),current.column())); // 显示模型索引的行和列号QStandardItem *aItem;aItem m_pItemModel-itemFromIndex(current); // 从模型索引获得 itemui-textEdit-append(u8单元格内容 aItem-text()); // 显示 item 的文字内容}
}// 在表格最后一行添加
void Widget::on_btnAppendLast_clicked() {QListQStandardItem* aItemList;QStandardItem *aItem;for (int i 0; i COLUMN_COUNT - 1; i) { // 不包含最后 1 列aItem new QStandardItem(u8自定义);aItemList aItem;}// 获取最后一列的表头文字QString str m_pItemModel-headerData(m_pItemModel-columnCount()-1, Qt::Horizontal, Qt::DisplayRole).toString();aItem new QStandardItem(str);aItem-setCheckable(true);aItemListaItem; // 添加到容器m_pItemModel-insertRow(m_pItemModel-rowCount(), aItemList); // 插入一行需要每个 Cell 的 ItemQModelIndex curIndex m_pItemModel-index(m_pItemModel-rowCount()-1, 0); // 创建最后一行的 ModelIndex// 如果之前点击了表格清空选择项m_pSelectionModel-clearSelection();// 设置刚插入的行为当前选择行m_pSelectionModel-setCurrentIndex(curIndex, QItemSelectionModel::Select);
}void Widget::on_btnAppend_clicked() {QListQStandardItem* aItemList;QStandardItem *aItem;for(int i 0; i COLUMN_COUNT-1; i) {aItem new QStandardItem(u8自定义);aItemList aItem;}// 获取表头文字QString str m_pItemModel-headerData(m_pItemModel-columnCount()-1, Qt::Horizontal, Qt::DisplayRole).toString();aItem new QStandardItem(str);aItem-setCheckable(true);aItemListaItem;QModelIndex curIndex m_pSelectionModel-currentIndex(); // 获取当前选中项的模型索引m_pItemModel-insertRow(curIndex.row(), aItemList); // 在当前行的前面插入一行m_pSelectionModel-clearSelection(); // 清除已有选择m_pSelectionModel-setCurrentIndex(curIndex, QItemSelectionModel::Select);
}// 删除选择的行
void Widget::on_btnDeleteSelectedLine_clicked() {QModelIndex curIndex m_pSelectionModel-currentIndex(); // 获取当前选择单元格的模型索引if (curIndex.row() m_pItemModel-rowCount() - 1) { // 如果是最后一行m_pItemModel-removeRow(curIndex.row()); // 删除最后一行} else {m_pItemModel-removeRow(curIndex.row()); // 删除一行并重新设置当前选择行m_pSelectionModel-setCurrentIndex(curIndex, QItemSelectionModel::Select);}
}// 将 tableView 的数据显示在 textEdit
void Widget::on_btnReshowData_clicked() {ui-textEdit-clear(); // 清空QStandardItem *aItem;QString str;// 获取表头文字int i, j;for (i 0; i m_pItemModel-columnCount(); i) {aItem m_pItemModel-horizontalHeaderItem(i); // 获取表头的一个项数据str str aItem-text() \t; // 用 tab 间隔文字}ui-textEdit-append(str); // 添加为文本框的一行//获取数据区的每行for (i 0; i m_pItemModel-rowCount(); i) {str ;for (j 0; jm_pItemModel-columnCount()-1; j) {aItem m_pItemModel-item(i,j);str str aItem-text() QString::asprintf(\t); //以 tab 分隔}aItem m_pItemModel-item(i, j); // 最后一行if (aItem-checkState() Qt::Checked)str str 1;elsestr str 0;ui-textEdit-append(str);}
}2.3 整型数 spinbox 代理
2.3.1 cintspindelegate.h
#ifndef CINTSPINDELEGATE_H
#define CINTSPINDELEGATE_H#include QStyledItemDelegateclass CIntSpinDelegate : public QStyledItemDelegate {Q_OBJECT
public:CIntSpinDelegate(QObject *parent0);// 自定义代理组件必须继承以下 4 个函数// 创建编辑组件QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem option,const QModelIndex index) const Q_DECL_OVERRIDE;// 从数据模型获取数据显示到代理组件中void setEditorData(QWidget *editor, const QModelIndex index) const Q_DECL_OVERRIDE;// 将代理组件的数据保存到数据模型中void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex index) const Q_DECL_OVERRIDE;// 更新代理编辑组件的大小void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem option,const QModelIndex index) const Q_DECL_OVERRIDE;
};#endif // CINTSPINDELEGATE_H2.3.2 cintspindelegate.cpp
#include cintspindelegate.h
#include QSpinBoxCIntSpinDelegate::CIntSpinDelegate(QObject *parent) : QStyledItemDelegate(parent) {}QWidget *CIntSpinDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem option, const QModelIndex index) const {// 创建代理编辑组件Q_UNUSED(option);Q_UNUSED(index);QSpinBox *editor new QSpinBox(parent); // 创建一个 QSpinBoxeditor-setFrame(false); // 设置为无边框editor-setMinimum(0);editor-setMaximum(120);return editor; // 返回此编辑器
}void CIntSpinDelegate::setEditorData(QWidget *editor, const QModelIndex index) const {// 从数据模型获取数据显示到代理组件中// 获取数据模型的模型索引指向的单元的数据int value index.model()-data(index, Qt::EditRole).toInt();QSpinBox *spinBox static_castQSpinBox*(editor); // 强制类型转换spinBox-setValue(value); // 设置编辑器的数值
}void CIntSpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex index) const {// 将代理组件的数据保存到数据模型中QSpinBox *spinBox static_castQSpinBox*(editor); // 强制类型转换spinBox-interpretText(); // 解释数据如果数据被修改后就触发信号int value spinBox-value(); // 获取 spinBox 的值model-setData(index, value, Qt::EditRole); //更新到数据模型
}void CIntSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem option, const QModelIndex index) const {// 设置组件大小Q_UNUSED(index);editor-setGeometry(option.rect);
}2.4 浮点数 spinbox 代理
2.4.1 cfloatspindelegate.h
#ifndef CFLOATSPINDELEGATE_H
#define CFLOATSPINDELEGATE_H#include QObject
#include QWidget
#include QStyledItemDelegateclass CFloatSpinDelegate : public QStyledItemDelegate {Q_OBJECT
public:CFloatSpinDelegate(QObject *parent0);// 自定义代理组件必须继承以下4个函数// 创建编辑组件QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem option,const QModelIndex index) const Q_DECL_OVERRIDE;void setEditorData(QWidget *editor, const QModelIndex index) const Q_DECL_OVERRIDE;void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex index) const Q_DECL_OVERRIDE;void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem option,const QModelIndex index) const Q_DECL_OVERRIDE;
};#endif // CFLOATSPINDELEGATE_H2.4.2 cfloatspindelegate.cpp
#include cfloatspindelegate.h
#include QDoubleSpinBoxCFloatSpinDelegate::CFloatSpinDelegate(QObject *parent):QStyledItemDelegate(parent) {}QWidget *CFloatSpinDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem option, const QModelIndex index) const {Q_UNUSED(option);Q_UNUSED(index);QDoubleSpinBox *editor new QDoubleSpinBox(parent);editor-setFrame(false);editor-setMinimum(0);editor-setDecimals(2);editor-setMaximum(100);return editor;
}void CFloatSpinDelegate::setEditorData(QWidget *editor, const QModelIndex index) const {float value index.model()-data(index, Qt::EditRole).toFloat();QDoubleSpinBox *spinBox static_castQDoubleSpinBox*(editor);spinBox-setValue(value);
}void CFloatSpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex index) const {QDoubleSpinBox *spinBox static_castQDoubleSpinBox*(editor);spinBox-interpretText();float value spinBox-value();QString str QString::asprintf(%.2f, value);model-setData(index, str, Qt::EditRole);
}void CFloatSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem option, const QModelIndex index) const {editor-setGeometry(option.rect);
}2.5 combobox 代理
2.5.1 ccomboboxdelegate.h
#ifndef CCOMBOBOXDELEGATE_H
#define CCOMBOBOXDELEGATE_H#include QItemDelegateclass CComboBoxDelegate : public QItemDelegate {Q_OBJECTpublic:CComboBoxDelegate(QObject *parent0);// 自定义代理组件必须继承以下4个函数QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem option,const QModelIndex index) const Q_DECL_OVERRIDE;void setEditorData(QWidget *editor, const QModelIndex index) const Q_DECL_OVERRIDE;void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex index) const Q_DECL_OVERRIDE;void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem option,const QModelIndex index) const Q_DECL_OVERRIDE;
};#endif // CCOMBOBOXDELEGATE_H2.5.2 ccomboboxdelegate.cpp
#include ccomboboxdelegate.h
#include QComboBoxCComboBoxDelegate::CComboBoxDelegate(QObject *parent) : QItemDelegate(parent) {}QWidget *CComboBoxDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem option, const QModelIndex index) const {QComboBox *editor new QComboBox(parent);editor-addItem(u8优);editor-addItem(u8良);editor-addItem(u8一般);return editor;
}void CComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex index) const {QString str index.model()-data(index, Qt::EditRole).toString();QComboBox *comboBox static_castQComboBox*(editor);comboBox-setCurrentText(str);
}void CComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex index) const {QComboBox *comboBox static_castQComboBox*(editor);QString str comboBox-currentText();model-setData(index, str, Qt::EditRole);
}void CComboBoxDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem option, const QModelIndex index) const {editor-setGeometry(option.rect);
}3. QListView 应用 3.1 widget.h
#ifndef WIDGET_H
#define WIDGET_H#include QWidget
#include QStringListModel
#include QMenuQT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);~Widget();private:void initMenu();private slots:void on_btnAddItem_clicked();void on_btnDeleteItem_clicked();void on_btnInsert_clicked();void on_btnClearAllData_clicked();void on_btnReshow_clicked();void on_showRightMenu(const QPoint pos);void OnActionDelete();// 链接 listview 的 clicked 信号void on_listView_clicked(const QModelIndex index);private:Ui::Widget *ui;QStringListModel* m_pStringListModel;QMenu *m_pMenu;
};
#endif // WIDGET_H3.2 widget.cpp
#include widget.h
#include ui_widget.h
#include QMenuWidget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui-setupUi(this);this-setWindowTitle(u8QListView使用教程);QStringList strList;strList u8北京 u8上海 u8深圳 u8广东 u8南京 u8苏州 u8西安;// 创建数据模型m_pStringListModel new QStringListModel(this);// 为模型设置 StringList会导入 StringList 的内容m_pStringListModel-setStringList(strList);// 为 listView 设置数据模型ui-listView-setModel(m_pStringListModel);// 设置 listview 编辑属性// 双击与选择//ui-listView-setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);initMenu();// listview 右键菜单ui-listView-setContextMenuPolicy(Qt::CustomContextMenu);connect(ui-listView, QListView::customContextMenuRequested, this, Widget::on_showRightMenu);
}Widget::~Widget() {delete ui;
}// 添加 item
void Widget::on_btnAddItem_clicked() {// 在尾部插入一空行, 不添加就把最后一行给替换了m_pStringListModel-insertRow(m_pStringListModel-rowCount());// 获取最后一行QModelIndex index m_pStringListModel-index(m_pStringListModel-rowCount() - 1, 0);m_pStringListModel-setData(index,new item, Qt::DisplayRole); // 设置显示文字// 设置新添加的行选中ui-listView-setCurrentIndex(index);
}// 删除选中的项
void Widget::on_btnDeleteItem_clicked() {// 获取当前选中的 modelIndexQModelIndex index ui-listView-currentIndex();// 删除当前行m_pStringListModel-removeRow(index.row());
}// 插入一项
void Widget::on_btnInsert_clicked() {// 获取选中 model IndexQModelIndex indexui-listView-currentIndex();// 在当前行的前面插入一行m_pStringListModel-insertRow(index.row());m_pStringListModel-setData(index, inserted item, Qt::DisplayRole);ui-listView-setCurrentIndex(index);
}// 回显 listview数据
void Widget::on_btnReshow_clicked() {// 获取数据模型的 StringListQStringList tmpList m_pStringListModel-stringList();ui-textEdit-clear(); // 文本框清空for (int i 0; i tmpList.count(); i) {// 显示数据模型的 StringList()返回的内容ui-textEdit-append(tmpList.at(i));}
}// 清除所有数据
void Widget::on_btnClearAllData_clicked() {m_pStringListModel-removeRows(0, m_pStringListModel-rowCount());
}void Widget::initMenu() {m_pMenu new QMenu(ui-listView);QAction *pAc1 new QAction(u8删除, ui-listView);QAction *pAc2 new QAction(u8插入, ui-listView);QAction *pAc3 new QAction(u8置顶, ui-listView);QAction *pAc4 new QAction(u8排到最后, ui-listView);m_pMenu-addAction(pAc1);m_pMenu-addAction(pAc2);m_pMenu-addAction(pAc3);m_pMenu-addAction(pAc4);// 注意在 exec 前链接信号槽因为 exec 会阻塞主线程// 如果 connect 写在 exec 代码之后信号槽将无法链接connect(pAc1, QAction::triggered, this, Widget::OnActionDelete);
}void Widget::on_showRightMenu(const QPoint pos) {if (!((ui-listView-selectionModel()-selectedIndexes()).empty())) {m_pMenu-exec(QCursor::pos()); // 在当前鼠标位置显示}
}void Widget::OnActionDelete() {// 获取当前 modelIndexQModelIndex index ui-listView-currentIndex();// 删除当前行m_pStringListModel-removeRow(index.row());
}void Widget::on_listView_clicked(const QModelIndex index) {ui-textEdit-clear(); // 文本框清空// 显示 QModelIndex 的行、列号ui-textEdit-append(QString::asprintf(u8当前项:row%d, column%d,index.row(), index.column()));
}