概要
使用Qt編寫上位機(jī)是一個(gè)非常不錯(cuò)的選擇,簡單說一下作者的看法:
①Q(mào)t采用的是C++,所以在某種程度上與嵌入式設(shè)備數(shù)據(jù)類型兼容,所以嵌入式設(shè)備與上位機(jī)間的協(xié)議定義數(shù)據(jù)結(jié)構(gòu)等都可以相互套用,
②Qt是跨平臺(tái)的,所以代碼開發(fā)一次,多平臺(tái)運(yùn)行。
③Qt學(xué)習(xí)成本低,網(wǎng)上資料很多,基本你遇到的問題,網(wǎng)上都能找到。
對(duì)于嵌入式開發(fā)者來說,會(huì)寫上位機(jī)可以提高開發(fā)效率,比如可以開發(fā)抓包工具,日志數(shù)據(jù)分析,升級(jí)(網(wǎng)絡(luò)升級(jí),串口升級(jí)等)
說到升級(jí),那么就有些場景,比如批量升級(jí),某臺(tái)升級(jí)等需求。有這些需求那么就要有對(duì)應(yīng)的UI呈現(xiàn)給用戶。所以Qt的自定義委托在這種場景顯的尤為重要。

Qt模型視圖中的委托
Qt模型視圖采用類MVC框架,那什么是MVC框架?
M--模型:負(fù)責(zé)組織數(shù)據(jù)
V--試圖:負(fù)責(zé)顯示數(shù)據(jù)
C--控制:負(fù)責(zé)用戶輸入

Qt模型視圖設(shè)計(jì):①視圖中集成了處理用戶輸入的功能,②視圖將用戶輸入作為內(nèi)部獨(dú)立的子功能實(shí)現(xiàn)

模型視圖中的委托:①委托是視圖中處理用戶輸入的部件。②視圖可以設(shè)置委托對(duì)象用于用戶輸入。③委托對(duì)象負(fù)責(zé)創(chuàng)建和顯示用戶輸入上下文。
Qt 自定義委托--實(shí)現(xiàn)批量升級(jí)UI
準(zhǔn)備工作:下載Qt工具,然后創(chuàng)建一個(gè)基類為QMainWindow的工程,并且?guī)i的。
設(shè)計(jì)一個(gè)ui,一個(gè)CheckBox控件和TableView控件

自定義表格中單選框CheckBox委托 -- 創(chuàng)建QRiceButtonDelegate類繼承QItemDelegate
重寫paint方法和editorEvent方法,其中paint用于繪制,editorEvent用于處理用戶輸入
單選框其實(shí)使用按鈕項(xiàng)樣式(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())//如果數(shù)據(jù)類型為bool型,才繪制單選寬
{
QStyleOptionButtoncheckBox;
checkBox.state=index.data().toBool()?QStyle::State_On:QStyle::State_Off;//繪制后的默認(rèn)狀態(tài)
checkBox.state|=QStyle::State_Enabled;
checkBox.rect=option.rect;
checkBox.rect.setX(option.rect.x()+option.rect.width()/2-6);//設(shè)置在表格中的顯示位置
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);//更新模型數(shù)據(jù)
}
}
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
自定義表格中進(jìn)度條ProgressBar委托 -- 創(chuàng)建QRiceProgressBarDelegate類繼承QItemDelegate
重寫paint方法和editorEvent方法,其中paint用于繪制,editorEvent用于處理用戶輸入
進(jìn)度條其實(shí)采用進(jìn)度條項(xiàng)樣式(QStyleOptionProgressBar)繪制。
QRiceProgressBarDelegate源文件
voidQRiceProgressBarDelegate::paint(QPainter*painter,constQStyleOptionViewItem&option,constQModelIndex&index)const
{
intprogress=index.data(Qt::DisplayRole).toInt();
QStyleOptionProgressBarprogressBar;
progressBar.minimum=0;//設(shè)置進(jìn)度條最小值
progressBar.maximum=100;//設(shè)置進(jìn)度條最大值
progressBar.progress=progress;//設(shè)置繪制后的數(shù)值
progressBar.rect=option.rect.adjusted(4,4,-4,-4);//設(shè)置進(jìn)度條的大小
progressBar.textVisible=true;//設(shè)置進(jìn)度條顯示數(shù)值
progressBar.textAlignment=Qt::AlignCenter;//設(shè)置進(jìn)度條數(shù)值顯示位置
progressBar.text=QString("%1%").arg(progress);//設(shè)置進(jìn)度條數(shù)值顯示
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委托 -- 創(chuàng)建QRiceButtonDelegate類繼承QItemDelegate
重寫paint方法和editorEvent方法,其中paint用于繪制,editorEvent用于處理用戶輸入
按鈕其實(shí)按鈕項(xiàng)樣式(QStyleOptionButton)繪制。
QRiceButtonDelegate源文件
voidQRiceButtonDelegate::paint(QPainter*painter,constQStyleOptionViewItem&option,constQModelIndex&index)const
{
QStyleOptionButton*buttonStyle=buttonDelegate.value(index);
if(!buttonStyle)
{
buttonStyle=newQStyleOptionButton();//創(chuàng)建按鈕項(xiàng)樣式
buttonStyle->text="Update";//設(shè)置按鈕中顯示的內(nèi)容
buttonStyle->state|=QStyle::State_Enabled;//設(shè)置按鈕中的狀態(tài)
(const_cast(this))->buttonDelegate.insert(index,buttonStyle);
}
buttonStyle->rect=option.rect.adjusted(4,4,-4,-4);//設(shè)置按鈕的大小
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)//按鈕按下,設(shè)置按鈕的狀態(tài)
{
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)//按鈕松開,設(shè)置按鈕的狀態(tài)
{
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()));//松開彈出消息框,顯示對(duì)應(yīng)行號(hào)
}
}
}
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
,>
創(chuàng)建一個(gè)自定義QRiceTableView類繼承QTableView類
構(gòu)造方法實(shí)現(xiàn):①創(chuàng)建QStandardItemModel模型。②創(chuàng)建單選框委托到視圖中。③創(chuàng)建進(jìn)度條委托到視圖第五列中。④創(chuàng)建按鈕委托到視圖第六列中。⑤設(shè)置表格視圖的頭部。
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<setHorizontalHeaderLabels(tableHeaders);
}
,>(
在QRiceTableView中實(shí)現(xiàn)用戶使用方法:
| 方法 | 說明 |
|---|---|
| int QRiceTableGetRow(void); | 獲取列表行數(shù) |
| int QRiceTableGetColumn(void); | 獲取列表列數(shù) |
| void QRiceTableAddItem(int row, struct tableItemInfo *info); | 增加一行 |
| void QRiceTableSetProgress(int row, int Progress); | 設(shè)置某行的進(jìn)度條 |
| void QRiceTableSetSelect(int row, bool select); | 單選框狀態(tài)設(shè)置 |
| bool QRiceTableGetSelect(int row); | 單選框狀態(tài)獲取 |
| QString QRiceTableGetString(int row, int column); | 獲取某行某列的數(shù)據(jù) |
在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(rowrowCount())
{
QModelIndexindex=tableItemModel->index(row,4);
tableItemModel->setData(index,Progress,Qt::DisplayRole);
}
}
voidQRiceTableView::QRiceTableSetSelect(introw,boolselect)
{
if(rowrowCount())
{
QModelIndexindex=tableItemModel->index(row,0);
tableItemModel->setData(index,select,Qt::DisplayRole);
}
}
boolQRiceTableView::QRiceTableGetSelect(introw)
{
if(rowrowCount())
{
QModelIndexindex=tableItemModel->index(row,0);
returnindex.data(Qt::DisplayRole).toBool();
}
returnfalse;
}
QStringQRiceTableView::QRiceTableGetString(introw,intcolumn)
{
if(rowrowCount()
&&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控件,選擇提升為:

填寫對(duì)應(yīng)類名,類的頭文件相對(duì)路徑:

點(diǎn)擊添加后,然后點(diǎn)擊提升按鈕,就完成了控件的提升
在mainwindow.cpp中增加測試用例:
在構(gòu)造方法中,創(chuàng)建兩條數(shù)據(jù),并且啟動(dòng)一個(gè)定時(shí)器刷新進(jìn)度條:
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("公務(wù)員");
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);
}
界面中全選框的實(shí)現(xiàn):
voidMainWindow::on_allCheckBox_clicked()
{
for(introw=0;rowtableView->QRiceTableGetRow();row++)
{
if(ui->allCheckBox->checkState()==Qt::Checked)
{
ui->tableView->QRiceTableSetSelect(row,true);
}
else
{
ui->tableView->QRiceTableSetSelect(row,false);
}
}
}
最終呈現(xiàn)結(jié)果:

-
嵌入式
+關(guān)注
關(guān)注
5198文章
20445瀏覽量
333994 -
ui
+關(guān)注
關(guān)注
0文章
209瀏覽量
22389 -
上位機(jī)
+關(guān)注
關(guān)注
27文章
1002瀏覽量
57049 -
Qt
+關(guān)注
關(guān)注
2文章
320瀏覽量
40874
發(fā)布評(píng)論請(qǐng)先 登錄
HarmonyOS應(yīng)用自定義鍵盤解決方案
OpenHarmony應(yīng)用開發(fā)之自定義彈窗
OpenHarmony自定義組件介紹
Qt自定義窗口部件的創(chuàng)建
如何在LabVIEW中實(shí)現(xiàn)自定義控件
基于HAL庫的USB自定義HID設(shè)備實(shí)現(xiàn)
三種自定義彈窗UI組件封裝的實(shí)現(xiàn)
自定義視圖組件教程案例
ArkUI如何自定義彈窗(eTS)
自定義算子開發(fā)
Qt自定義委托--實(shí)現(xiàn)批量升級(jí)UI
評(píng)論