嵌入式技术
概要
使用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 #includeclass 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 #includeclass 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 #includeclass 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") <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);
}
}
}
最终呈现结果:

编辑:黄飞
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
Qt4图形设计与嵌入式开发
2013-05-14 0
-
基于ARM的嵌入式开发
2009-10-04 905
-
嵌入式开发
2011-12-20 3369
-
嵌入式开发要学什么嵌入式开发的一些入门教材推荐
2019-01-10 1403
-
使用VB编写上位机与嵌入式LINUX下位机的网络通信程序免费下载
2019-08-16 744
-
嵌入式开发的产品有哪些_嵌入式开发的流程
2020-08-31 10906
-
最详细编写上位机教程
2021-04-27 14016
-
嵌入式LINUX的Qt开发入门教程
2021-08-04 1068
-
嵌入式开发(一):嵌入式开发新手入门
2021-10-14 3286
-
嵌入式开发资料免费分享
2021-10-21 1422
-
Qt嵌入式开发笔记
2021-11-03 750
-
单片机开发和嵌入式开发的区别
2023-04-14 2446
-
基于QT的简单的上位机
2023-05-08 451
-
手把手教你编写一个上位机
2023-05-08 387
全部0条评论
快来发表一下你的评论吧 !
×
20
完善资料,
赚取积分