概要
使用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()
{
}
voidQRiceCheckBoxDelegate::paint(QPainter*painter,constQStyleOptionViewItem&option,constQModelIndex&index)const
{
if(QVariant::Bool==index.data(Qt::DisplayRole).type())//如果数据类型为bool型,才绘制单选宽
{
QStyleOptionButtoncheckBox;
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);
}
}
boolQRiceCheckBoxDelegate::editorEvent(QEvent*event,QAbstractItemModel*model,constQStyleOptionViewItem&option,constQModelIndex&index)
{
boolret=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);
}
returnret;
}
*>
QRiceButtonDelegate头文件
#ifndefQRICECHECKBOXDELEGATE_H
#defineQRICECHECKBOXDELEGATE_H
#include
classQRiceCheckBoxDelegate:publicQItemDelegate
{
Q_OBJECT
public:
explicitQRiceCheckBoxDelegate(QObject*parent=nullptr);
~QRiceCheckBoxDelegate();
voidpaint(QPainter*painter,constQStyleOptionViewItem&option,constQModelIndex&index)const;
booleditorEvent(QEvent*event,QAbstractItemModel*model,constQStyleOptionViewItem&option,constQModelIndex&index);
signals:
};
#endif//QRICECHECKBOXDELEGATE_H
自定义表格中进度条ProgressBar委托 -- 创建QRiceProgressBarDelegate类继承QItemDelegate
重写paint方法和editorEvent方法,其中paint用于绘制,editorEvent用于处理用户输入
进度条其实采用进度条项样式(QStyleOptionProgressBar)绘制。
QRiceProgressBarDelegate源文件
voidQRiceProgressBarDelegate::paint(QPainter*painter,constQStyleOptionViewItem&option,constQModelIndex&index)const
{
intprogress=index.data(Qt::DisplayRole).toInt();
QStyleOptionProgressBarprogressBar;
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);//绘制
}
boolQRiceProgressBarDelegate::editorEvent(QEvent*event,QAbstractItemModel*model,constQStyleOptionViewItem&option,constQModelIndex&index)
{
boolret=true;
if(QEvent::MouseButtonDblClick!=event->type())
{
ret=QItemDelegate::editorEvent(event,model,option,index);
}
returnret;
}
QRiceProgressBarDelegate头文件
#ifndefQRICEPROGRESSBARDELEGATE_H
#defineQRICEPROGRESSBARDELEGATE_H
#include
classQRiceProgressBarDelegate:publicQItemDelegate
{
Q_OBJECT
public:
explicitQRiceProgressBarDelegate(QObject*parent=nullptr);
~QRiceProgressBarDelegate();
voidpaint(QPainter*painter,constQStyleOptionViewItem&option,constQModelIndex&index)const;
booleditorEvent(QEvent*event,QAbstractItemModel*model,constQStyleOptionViewItem&option,constQModelIndex&index);
signals:
};
#endif//QRICEPROGRESSBARDELEGATE_H
自定义表格中按纽Button委托 -- 创建QRiceButtonDelegate类继承QItemDelegate
重写paint方法和editorEvent方法,其中paint用于绘制,editorEvent用于处理用户输入
按钮其实按钮项样式(QStyleOptionButton)绘制。
QRiceButtonDelegate源文件
voidQRiceButtonDelegate::paint(QPainter*painter,constQStyleOptionViewItem&option,constQModelIndex&index)const
{
QStyleOptionButton*buttonStyle=buttonDelegate.value(index);
if(!buttonStyle)
{
buttonStyle=newQStyleOptionButton();//创建按钮项样式
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);//绘制
}
boolQRiceButtonDelegate::editorEvent(QEvent*event,QAbstractItemModel*model,constQStyleOptionViewItem&option,constQModelIndex&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("btn1column%1").arg(index.row()));//松开弹出消息框,显示对应行号
}
}
}
returntrue;
}
voidQRiceButtonDelegate::showMsg(QStringstr)
{
QMessageBoxmsg;
msg.setText(str);
msg.exec();
}
QRiceButtonDelegate头文件
#ifndefQRICEBUTTONDELEGATE_H
#defineQRICEBUTTONDELEGATE_H
#include
classQRiceButtonDelegate:publicQItemDelegate
{
Q_OBJECT
public:
explicitQRiceButtonDelegate(QObject*parent=nullptr);
~QRiceButtonDelegate();
voidpaint(QPainter*painter,constQStyleOptionViewItem&option,constQModelIndex&index)const;
booleditorEvent(QEvent*event,QAbstractItemModel*model,constQStyleOptionViewItem&option,constQModelIndex&index);
signals:
private:
voidshowMsg(QStringstr);
private:
typedefQMapcollButtons;
collButtonsbuttonDelegate;
};
#endif//QRICEBUTTONDELEGATE_H
,>
创建一个自定义QRiceTableView类继承QTableView类
构造方法实现:①创建QStandardItemModel模型。②创建单选框委托到视图中。③创建进度条委托到视图第五列中。④创建按钮委托到视图第六列中。⑤设置表格视图的头部。
QRiceTableView::QRiceTableView(QWidget*parent):
QTableView(parent)
{
horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
tableItemModel=newQStandardItemModel();
setModel(tableItemModel);
tableCheckBoxDelegate=newQRiceCheckBoxDelegate(this);
setItemDelegate(tableCheckBoxDelegate);
tableProgressBarDelegate=newQRiceProgressBarDelegate(this);
setItemDelegateForColumn(4,tableProgressBarDelegate);
tableButtonDelegate=newQRiceButtonDelegate(this);
setItemDelegateForColumn(5,tableButtonDelegate);
QStringListtableHeaders;
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中方法代码:
intQRiceTableView::QRiceTableGetRow(void)
{
returntableItemModel->rowCount();
}
intQRiceTableView::QRiceTableGetColumn(void)
{
returntableItemModel->columnCount();
}
voidQRiceTableView::QRiceTableAddItem(introw,structtableItemInfo*info)
{
QStandardItem*otaDeviceListStandardItem=tableItemModel->invisibleRootItem();
QStandardItem*checkBox=newQStandardItem();
QStandardItem*name=newQStandardItem();
QStandardItem*age=newQStandardItem();
QStandardItem*work=newQStandardItem();
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);
}
voidQRiceTableView::QRiceTableSetProgress(introw,intProgress)
{
if(row< tableItemModel->rowCount())
{
QModelIndexindex=tableItemModel->index(row,4);
tableItemModel->setData(index,Progress,Qt::DisplayRole);
}
}
voidQRiceTableView::QRiceTableSetSelect(introw,boolselect)
{
if(row< tableItemModel->rowCount())
{
QModelIndexindex=tableItemModel->index(row,0);
tableItemModel->setData(index,select,Qt::DisplayRole);
}
}
boolQRiceTableView::QRiceTableGetSelect(introw)
{
if(row< tableItemModel->rowCount())
{
QModelIndexindex=tableItemModel->index(row,0);
returnindex.data(Qt::DisplayRole).toBool();
}
returnfalse;
}
QStringQRiceTableView::QRiceTableGetString(introw,intcolumn)
{
if(row< tableItemModel->rowCount()
&&column>0&&column< (tableItemModel->columnCount()-2))
{
QModelIndexindex=tableItemModel->index(row,column);
returnindex.data(Qt::DisplayRole).toString();
}
return"";
}
QRiceTableView头文件:
#ifndefQRICETABLEVIEW_H
#defineQRICETABLEVIEW_H
#include
#include
#include"qricecheckboxdelegate.h"
#include"qriceprogressbardelegate.h"
#include"qricebuttondelegate.h"
classQRiceTableView:publicQTableView
{
Q_OBJECT
public:
structtableItemInfo
{
QStringname;
QStringage;
QStringwork;
};
public:
explicitQRiceTableView(QWidget*parent=nullptr);
~QRiceTableView();
signals:
public:
intQRiceTableGetRow(void);
intQRiceTableGetColumn(void);
voidQRiceTableAddItem(introw,structtableItemInfo*info);
voidQRiceTableSetProgress(introw,intProgress);
voidQRiceTableSetSelect(introw,boolselect);
boolQRiceTableGetSelect(introw);
QStringQRiceTableGetString(introw,intcolumn);
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(newUi::MainWindow)
{
ui->setupUi(this);
setWindowTitle(tr("RiceDelegate"));
structQRiceTableView::tableItemInfoinfo;
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=newQTimer(this);
connect(timer,&QTimer::timeout,[=](){
staticintProgress1=0;
staticintProgress2=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);
}
界面中全选框的实现:
voidMainWindow::on_allCheckBox_clicked()
{
for(introw=0;row< ui->tableView->QRiceTableGetRow();row++)
{
if(ui->allCheckBox->checkState()==Qt::Checked)
{
ui->tableView->QRiceTableSetSelect(row,true);
}
else
{
ui->tableView->QRiceTableSetSelect(row,false);
}
}
}
最终呈现结果:

-
嵌入式
+关注
关注
5186文章
20146浏览量
328780 -
ui
+关注
关注
0文章
208浏览量
22236 -
上位机
+关注
关注
27文章
994浏览量
56711 -
Qt
+关注
关注
2文章
318浏览量
40295
发布评论请先 登录
HarmonyOS应用自定义键盘解决方案
OpenHarmony应用开发之自定义弹窗
OpenHarmony自定义组件介绍
Qt自定义窗口部件的创建
基于HAL库的USB自定义HID设备实现
三种自定义弹窗UI组件封装的实现
自定义视图组件教程案例
自定义算子开发

Qt自定义委托--实现批量升级UI
评论