概要
使用Qt编写上位机是一个非常不错的选择,简单说一下作者的看法:
①Qt采用的是C++,所以在某种程度上与嵌入式设备数据类型兼容,所以嵌入式设备与上位机间的协议定义数据结构等都可以相互套用,
②Qt是跨平台的,所以代码开发一次,多平台运行。
③Qt学习成本低,网上资料很多,基本你遇到的问题,网上都能找到。
对于嵌入式开发者来说,会写上位机可以提高开发效率,比如可以开发抓包工具,日志数据分析,升级(网络升级,串口升级等)
说到升级,那么就有些场景,比如批量升级,某台升级等需求。有这些需求那么就要有对应的UI呈现给用户。所以Qt的自定义委托在这种场景显的尤为重要。
Qt模型视图中的委托
Qt模型视图采用类MVC框架,那什么是MVC框架?
M--模型:负责组织数据
V--试图:负责显示数据
C--控制:负责用户输入
Qt模型视图设计:①视图中集成了处理用户输入的功能,②视图将用户输入作为内部独立的子功能实现
模型视图中的委托:①委托是视图中处理用户输入的部件。②视图可以设置委托对象用于用户输入。③委托对象负责创建和显示用户输入上下文。
Qt 自定义委托--实现批量升级UI
准备工作:下载Qt工具,然后创建一个基类为QMainWindow的工程,并且带ui的。
设计一个ui,一个CheckBox控件和TableView控件
自定义表格中单选框CheckBox委托 -- 创建QRiceButtonDelegate类继承QItemDelegate
重写paint方法和editorEvent方法,其中paint用于绘制,editorEvent用于处理用户输入
单选框其实使用按钮项样式(QStyleOptionButton)绘制。
QRiceButtonDelegate源文件
#include "qricecheckboxdelegate.h" #include #include #include #include #include QRiceCheckBoxDelegate::QRiceCheckBoxDelegate(QObject *parent) : QItemDelegate(parent) { } QRiceCheckBoxDelegate::~QRiceCheckBoxDelegate() { } void QRiceCheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if(QVariant::Bool == index.data(Qt::DisplayRole).type()) //如果数据类型为bool型,才绘制单选宽 { QStyleOptionButton checkBox; checkBox.state = index.data().toBool() ? QStyle::State_On : QStyle::State_Off; //绘制后的默认状态 checkBox.state |= QStyle::State_Enabled; checkBox.rect = option.rect; checkBox.rect.setX(option.rect.x() + option.rect.width()/2 - 6); //设置在表格中的显示位置 QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkBox, painter); // 绘制 } else { QItemDelegate::paint(painter, option, index); } } bool QRiceCheckBoxDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { bool ret = true; if(QVariant::Bool == index.data().type()) { QMouseEvent* mouse = dynamic_cast(event); if( (NULL != mouse) && (QEvent::MouseButtonPress == mouse->type()) && (option.rect.contains(mouse->pos())) ) { model->setData(index, !index.data().toBool(), Qt::DisplayRole); // 更新模型数据 } } else { ret = QItemDelegate::editorEvent(event, model, option, index); } return ret; } *>
QRiceButtonDelegate头文件
#ifndef QRICECHECKBOXDELEGATE_H #define QRICECHECKBOXDELEGATE_H #include class QRiceCheckBoxDelegate : public QItemDelegate { Q_OBJECT public: explicit QRiceCheckBoxDelegate(QObject *parent = nullptr); ~QRiceCheckBoxDelegate(); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index); signals: }; #endif // QRICECHECKBOXDELEGATE_H
自定义表格中进度条ProgressBar委托 -- 创建QRiceProgressBarDelegate类继承QItemDelegate
重写paint方法和editorEvent方法,其中paint用于绘制,editorEvent用于处理用户输入
进度条其实采用进度条项样式(QStyleOptionProgressBar)绘制。
QRiceProgressBarDelegate源文件
void QRiceProgressBarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { int progress = index.data(Qt::DisplayRole).toInt(); QStyleOptionProgressBar progressBar; progressBar.minimum = 0; //设置进度条最小值 progressBar.maximum = 100; //设置进度条最大值 progressBar.progress = progress; //设置绘制后的数值 progressBar.rect = option.rect.adjusted(4, 4, -4, -4); //设置进度条的大小 progressBar.textVisible = true; //设置进度条显示数值 progressBar.textAlignment = Qt::AlignCenter; //设置进度条数值显示位置 progressBar.text = QString("%1%").arg(progress); //设置进度条数值显示 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBar, painter); // 绘制 } bool QRiceProgressBarDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { bool ret = true; if(QEvent::MouseButtonDblClick != event->type()) { ret = QItemDelegate::editorEvent(event, model, option, index); } return ret; }
QRiceProgressBarDelegate头文件
#ifndef QRICEPROGRESSBARDELEGATE_H #define QRICEPROGRESSBARDELEGATE_H #include class QRiceProgressBarDelegate : public QItemDelegate { Q_OBJECT public: explicit QRiceProgressBarDelegate(QObject *parent = nullptr); ~QRiceProgressBarDelegate(); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index); signals: }; #endif // QRICEPROGRESSBARDELEGATE_H
自定义表格中按纽Button委托 -- 创建QRiceButtonDelegate类继承QItemDelegate
重写paint方法和editorEvent方法,其中paint用于绘制,editorEvent用于处理用户输入
按钮其实按钮项样式(QStyleOptionButton)绘制。
QRiceButtonDelegate源文件
void QRiceButtonDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionButton *buttonStyle = buttonDelegate.value(index); if(!buttonStyle) { buttonStyle = new QStyleOptionButton(); // 创建按钮项样式 buttonStyle->text = "Update"; // 设置按钮中显示的内容 buttonStyle->state |= QStyle::State_Enabled; // 设置按钮中的状态 (const_cast(this))->buttonDelegate.insert(index, buttonStyle); } buttonStyle->rect = option.rect.adjusted(4, 4, -4, -4); //设置按钮的大小 painter->save(); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); } painter->restore(); QApplication::style()->drawControl(QStyle::CE_PushButton, buttonStyle, painter); //绘制 } bool QRiceButtonDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { Q_UNUSED(model); Q_UNUSED(option); QMouseEvent *mouseEvent = (QMouseEvent *)event; if(event->type() == QEvent::MouseButtonPress) // 按钮按下,设置按钮的状态 { if(buttonDelegate.contains(index)) { QStyleOptionButton *buttonStyle = buttonDelegate.value(index); if(buttonStyle->rect.contains(mouseEvent->x(), mouseEvent->y())) { buttonStyle->state |= QStyle::State_Sunken; } } } if(event->type() == QEvent::MouseButtonRelease) // 按钮松开,设置按钮的状态 { if(buttonDelegate.contains(index)) { QStyleOptionButton *buttonStyle = buttonDelegate.value(index); if(buttonStyle->rect.contains(mouseEvent->x(), mouseEvent->y())) { buttonStyle->state &= (~QStyle::State_Sunken); showMsg(tr("btn1 column %1").arg(index.row())); // 松开弹出消息框,显示对应行号 } } } return true; } void QRiceButtonDelegate::showMsg(QString str) { QMessageBox msg; msg.setText(str); msg.exec(); }
QRiceButtonDelegate头文件
#ifndef QRICEBUTTONDELEGATE_H #define QRICEBUTTONDELEGATE_H #include class QRiceButtonDelegate : public QItemDelegate { Q_OBJECT public: explicit QRiceButtonDelegate(QObject *parent = nullptr); ~QRiceButtonDelegate(); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index); signals: private: void showMsg(QString str); private: typedef QMap collButtons; collButtons buttonDelegate; }; #endif // QRICEBUTTONDELEGATE_H ,>
创建一个自定义QRiceTableView类继承QTableView类
构造方法实现:①创建QStandardItemModel模型。②创建单选框委托到视图中。③创建进度条委托到视图第五列中。④创建按钮委托到视图第六列中。⑤设置表格视图的头部。
QRiceTableView::QRiceTableView(QWidget *parent) : QTableView(parent) { horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); tableItemModel = new QStandardItemModel(); setModel(tableItemModel); tableCheckBoxDelegate = new QRiceCheckBoxDelegate(this); setItemDelegate(tableCheckBoxDelegate); tableProgressBarDelegate = new QRiceProgressBarDelegate(this); setItemDelegateForColumn(4, tableProgressBarDelegate); tableButtonDelegate = new QRiceButtonDelegate(this); setItemDelegateForColumn(5, tableButtonDelegate); QStringList tableHeaders; tableHeaders << tr("Select") <"Name") << tr("Age") << tr("Work") << tr("Progress") << tr("Update"); tableItemModel->setHorizontalHeaderLabels(tableHeaders); } ,>(
在QRiceTableView中实现用户使用方法:
方法 | 说明 |
---|---|
int QRiceTableGetRow(void); | 获取列表行数 |
int QRiceTableGetColumn(void); | 获取列表列数 |
void QRiceTableAddItem(int row, struct tableItemInfo *info); | 增加一行 |
void QRiceTableSetProgress(int row, int Progress); | 设置某行的进度条 |
void QRiceTableSetSelect(int row, bool select); | 单选框状态设置 |
bool QRiceTableGetSelect(int row); | 单选框状态获取 |
QString QRiceTableGetString(int row, int column); | 获取某行某列的数据 |
在QRiceTableView中方法代码:
int QRiceTableView::QRiceTableGetRow(void) { return tableItemModel->rowCount(); } int QRiceTableView::QRiceTableGetColumn(void) { return tableItemModel->columnCount(); } void QRiceTableView::QRiceTableAddItem(int row, struct tableItemInfo *info) { QStandardItem* otaDeviceListStandardItem = tableItemModel->invisibleRootItem(); QStandardItem *checkBox = new QStandardItem(); QStandardItem *name = new QStandardItem(); QStandardItem *age = new QStandardItem(); QStandardItem *work = new QStandardItem(); checkBox->setData(false, Qt::DisplayRole); name->setData(info->name, Qt::DisplayRole); age->setData(info->age, Qt::DisplayRole); work->setData(info->work, Qt::DisplayRole); otaDeviceListStandardItem->setChild(row, 0, checkBox); otaDeviceListStandardItem->setChild(row, 1, name); otaDeviceListStandardItem->setChild(row, 2, age); otaDeviceListStandardItem->setChild(row, 3, work); } void QRiceTableView::QRiceTableSetProgress(int row, int Progress) { if(row < tableItemModel->rowCount()) { QModelIndex index = tableItemModel->index(row, 4); tableItemModel->setData(index, Progress, Qt::DisplayRole); } } void QRiceTableView::QRiceTableSetSelect(int row, bool select) { if(row < tableItemModel->rowCount()) { QModelIndex index = tableItemModel->index(row, 0); tableItemModel->setData(index, select, Qt::DisplayRole); } } bool QRiceTableView::QRiceTableGetSelect(int row) { if(row < tableItemModel->rowCount()) { QModelIndex index = tableItemModel->index(row, 0); return index.data(Qt::DisplayRole).toBool(); } return false; } QString QRiceTableView::QRiceTableGetString(int row, int column) { if(row < tableItemModel->rowCount() && column > 0 && column < (tableItemModel->columnCount() - 2)) { QModelIndex index = tableItemModel->index(row, column); return index.data(Qt::DisplayRole).toString(); } return ""; }
QRiceTableView头文件:
#ifndef QRICETABLEVIEW_H #define QRICETABLEVIEW_H #include #include #include "qricecheckboxdelegate.h" #include "qriceprogressbardelegate.h" #include "qricebuttondelegate.h" class QRiceTableView : public QTableView { Q_OBJECT public: struct tableItemInfo { QString name; QString age; QString work; }; public: explicit QRiceTableView(QWidget *parent = nullptr); ~QRiceTableView(); signals: public: int QRiceTableGetRow(void); int QRiceTableGetColumn(void); void QRiceTableAddItem(int row, struct tableItemInfo *info); void QRiceTableSetProgress(int row, int Progress); void QRiceTableSetSelect(int row, bool select); bool QRiceTableGetSelect(int row); QString QRiceTableGetString(int row, int column); private: QStandardItemModel *tableItemModel; QRiceCheckBoxDelegate *tableCheckBoxDelegate; QRiceProgressBarDelegate *tableProgressBarDelegate; QRiceButtonDelegate *tableButtonDelegate; }; #endif // QRICETABLEVIEW_H
将UI中的QTableView提升为QRiceTableView:
右击QTableView控件,选择提升为:
填写对应类名,类的头文件相对路径:
点击添加后,然后点击提升按钮,就完成了控件的提升
在mainwindow.cpp中增加测试用例:
在构造方法中,创建两条数据,并且启动一个定时器刷新进度条:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); setWindowTitle(tr("Rice Delegate")); struct QRiceTableView::tableItemInfo info; info.name = tr("RiceChen"); info.age = tr("18"); info.work = tr("程序员"); ui->tableView->QRiceTableAddItem(0, &info); info.name = tr("米饭"); info.age = tr("20"); info.work = tr("公务员"); ui->tableView->QRiceTableAddItem(1, &info); QTimer * timer = new QTimer(this); connect(timer,&QTimer::timeout,[=](){ static int Progress1 = 0; static int Progress2 = 0; ui->tableView->QRiceTableSetProgress(0, Progress1); ui->tableView->QRiceTableSetProgress(1, Progress2); Progress1 += 1; Progress2 += 2; if(Progress1 > 100) { Progress1 = 0; } if(Progress2 > 100) { Progress2 = 0; } }); timer->start(1000); }
界面中全选框的实现:
void MainWindow::on_allCheckBox_clicked() { for(int row = 0; row < ui->tableView->QRiceTableGetRow(); row++) { if(ui->allCheckBox->checkState() == Qt::Checked) { ui->tableView->QRiceTableSetSelect(row, true); } else { ui->tableView->QRiceTableSetSelect(row, false); } } }
最终呈现结果:
全部0条评论
快来发表一下你的评论吧 !