0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

Rice嵌入式开发技术分享 来源:Rice 嵌入式开发技术分享 作者:Rice 嵌入式开发技 2022-10-31 12:27 次阅读

概要

使用Qt编写上位机是一个非常不错的选择,简单说一下作者的看法:

①Qt采用的是C++,所以在某种程度上与嵌入式设备数据类型兼容,所以嵌入式设备与上位机间的协议定义数据结构等都可以相互套用,

②Qt是跨平台的,所以代码开发一次,多平台运行。

③Qt学习成本低,网上资料很多,基本你遇到的问题,网上都能找到。

对于嵌入式开发者来说,会写上位机可以提高开发效率,比如可以开发抓包工具,日志数据分析,升级(网络升级,串口升级等)

说到升级,那么就有些场景,比如批量升级,某台升级等需求。有这些需求那么就要有对应的UI呈现给用户。所以Qt的自定义委托在这种场景显的尤为重要。

32d2d19a-580b-11ed-b468-dac502259ad0.png

Qt模型视图中的委托

Qt模型视图采用类MVC框架,那什么是MVC框架?

M--模型:负责组织数据

V--试图:负责显示数据

C--控制:负责用户输入

3304feb8-580b-11ed-b468-dac502259ad0.png

Qt模型视图设计:①视图中集成了处理用户输入的功能,②视图将用户输入作为内部独立的子功能实现

332c57ec-580b-11ed-b468-dac502259ad0.png

模型视图中的委托:①委托是视图中处理用户输入的部件。②视图可以设置委托对象用于用户输入。③委托对象负责创建和显示用户输入上下文。

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

准备工作:下载Qt工具,然后创建一个基类为QMainWindow的工程,并且带ui的。

设计一个ui,一个CheckBox控件和TableView控件

33432710-580b-11ed-b468-dac502259ad0.png

自定义表格中单选框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控件,选择提升为:

3377fcec-580b-11ed-b468-dac502259ad0.png

填写对应类名,类的头文件相对路径:

34078f88-580b-11ed-b468-dac502259ad0.png

点击添加后,然后点击提升按钮,就完成了控件的提升

在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);
}
}
}

最终呈现结果:

32d2d19a-580b-11ed-b468-dac502259ad0.png

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5068

    文章

    19008

    浏览量

    302995
  • ui
    ui
    +关注

    关注

    0

    文章

    204

    浏览量

    21339
  • 上位机
    +关注

    关注

    27

    文章

    930

    浏览量

    54723
  • Qt
    Qt
    +关注

    关注

    1

    文章

    301

    浏览量

    37817
收藏 人收藏

    评论

    相关推荐

    HarmonyOS开发实例:【自定义Emitter】

    使用[Emitter]实现事件的订阅和发布,使用[自定义弹窗]设置广告信息。
    的头像 发表于 04-14 11:37 969次阅读
    HarmonyOS开发实例:【<b class='flag-5'>自定义</b>Emitter】

    OpenHarmony应用开发之自定义弹窗

    , `getApplicationVersion is fail`) } } ... ... 以上是应用升级所需的数据结构及部分数据获取。 弹窗具体实现 自定义弹窗的实现就是在原页面
    发表于 09-06 14:40

    OpenHarmony自定义组件介绍

    见的容器组件上。 二、页面和自定义组件生命周期 在开始之前,我们先明确自定义组件和页面的关系: ● 自定义组件:@Component装饰的UI单元,可以组合多个系统组件
    发表于 09-25 15:36

    1602自定义字符

    1602液晶能够显示自定义字符,能够根据读者的具体情况显示自定义字符。
    发表于 01-20 15:43 1次下载

    Qt自定义窗口部件的创建

    通过对一个已经存在的Qt窗口部件进行子类化或者直接对QWidget进行子类化,就可以创建自定义窗口部件。以下直接对已有的Qt窗口部件进行子类化
    发表于 09-09 09:00 2412次阅读

    如何在LabVIEW中实现自定义控件

    本文档的主要内容详细介绍的是如何在LabVIEW中实现自定义控件。
    发表于 01-14 17:17 48次下载
    如何在LabVIEW中<b class='flag-5'>实现</b><b class='flag-5'>自定义</b>控件

    基于HAL库的USB自定义HID设备实现

    基于HAL库的USB自定义HID设备实现基于HAL库的USB自定义HID设备实现准备工作CubeMX配置代码实现基于HAL库的USB
    发表于 12-28 20:04 13次下载
    基于HAL库的USB<b class='flag-5'>自定义</b>HID设备<b class='flag-5'>实现</b>

    三种自定义弹窗UI组件封装的实现

    鸿蒙已经提供了全局 UI 方法自定义弹窗,本文是基于基础的自定义弹窗来实现提示消息弹窗、确认弹窗、输入弹窗的 UI 组件封装。
    的头像 发表于 03-30 09:28 3092次阅读

    自定义视图组件教程案例

    自定义组件 1.自定义组件-particles(粒子效果) 2.自定义组件- pulse(脉冲button效果) 3.自定义组件-progress(progress效果) 4.
    发表于 04-08 10:48 14次下载

    ArkUI如何自定义弹窗(eTS)

    自定义弹窗其实也是比较简单的,通过CustomDialogController类就可以显示自定义弹窗。
    的头像 发表于 08-31 08:24 2124次阅读

    自定义特性能做什么?

    今天跟大家分享的主题是基于自定义特性实现DataGridView全自动生成。
    的头像 发表于 02-22 16:20 788次阅读
    <b class='flag-5'>自定义</b>特性能做什么?

    labview自定义控件

    labview自定义精美控件
    发表于 05-15 16:46 17次下载

    Omniverse 中文课程系列 3:实战练习如何成为自定义 UI 界面大师

    Omniverse 为 3D 工具构建漂亮的自定义 UI 界面 学习目标 如果您是虚拟世界的构建者和创作者,那么您一定不能错过亲身体验 NVIDIA Omniverse 套件中的 Omni.ui 工具及框架
    的头像 发表于 06-09 20:45 556次阅读
    Omniverse 中文课程系列 3:实战练习如何成为<b class='flag-5'>自定义</b> <b class='flag-5'>UI</b> 界面大师

    自定义算子开发

    一个完整的自定义算子应用过程包括注册算子、算子实现、含自定义算子模型转换和运行含自定义op模型四个阶段。在大多数情况下,您的模型应该可以通过使用hb_mapper工具完成转换并顺利部署
    的头像 发表于 04-07 16:11 2737次阅读
    <b class='flag-5'>自定义</b>算子开发

    labview超快自定义控件制作和普通自定义控件制作

    labview超快自定义控件制作和普通自定义控件制作
    发表于 08-21 10:32 12次下载