概要
使用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í),那么就有些場(chǎng)景,比如批量升級(jí),某臺(tái)升級(jí)等需求。有這些需求那么就要有對(duì)應(yīng)的UI呈現(xiàn)給用戶。所以Qt的自定義委托在這種場(chǎng)景顯的尤為重要。

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() { } void?QRiceCheckBoxDelegate::paint(QPainter?*painter,?const?QStyleOptionViewItem?&option,?const?QModelIndex?&index)?const { ????if(QVariant::Bool?==?index.data(Qt::DisplayRole).type())?//如果數(shù)據(jù)類型為bool型,才繪制單選寬? ????{ ????????QStyleOptionButton?checkBox; ????????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); ????} } 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);?//?更新模型數(shù)據(jù) ????????} ????} ????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
自定義表格中進(jìn)度條ProgressBar委托 -- 創(chuàng)建QRiceProgressBarDelegate類繼承QItemDelegate
重寫paint方法和editorEvent方法,其中paint用于繪制,editorEvent用于處理用戶輸入
進(jìn)度條其實(shí)采用進(jìn)度條項(xiàng)樣式(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;????????????????????????????????//設(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);?//?繪制
}
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委托 -- 創(chuàng)建QRiceButtonDelegate類繼承QItemDelegate
重寫paint方法和editorEvent方法,其中paint用于繪制,editorEvent用于處理用戶輸入
按鈕其實(shí)按鈕項(xiàng)樣式(QStyleOptionButton)繪制。
QRiceButtonDelegate源文件
void?QRiceButtonDelegate::paint(QPainter?*painter,?const?QStyleOptionViewItem?&option,?const?QModelIndex?&index)?const
{
????QStyleOptionButton?*buttonStyle?=?buttonDelegate.value(index);
????if(!buttonStyle)
????{
????????buttonStyle?=?new?QStyleOptionButton();??????????//?創(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);???//繪制
}
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)??????????????//?按鈕按下,設(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("btn1?column?%1").arg(index.row()));???//?松開彈出消息框,顯示對(duì)應(yīng)行號(hào)
????????????}
????????}
????}
????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
創(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?=?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?<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中方法代碼:
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?rowCount())
????{
????????QModelIndex?index?=?tableItemModel->index(row,?4);
????????tableItemModel->setData(index,?Progress,?Qt::DisplayRole);
????}
}
void?QRiceTableView::QRiceTableSetSelect(int?row,?bool?select)
{
????if(row?rowCount())
????{
????????QModelIndex?index?=?tableItemModel->index(row,?0);
????????tableItemModel->setData(index,?select,?Qt::DisplayRole);
????}
}
bool?QRiceTableView::QRiceTableGetSelect(int?row)
{
????if(row?rowCount())
????{
????????QModelIndex?index?=?tableItemModel->index(row,?0);
????????return?index.data(Qt::DisplayRole).toBool();
????}
????return?false;
}
QString?QRiceTableView::QRiceTableGetString(int?row,?int?column)
{
????if(row?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控件,選擇提升為:

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

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

編輯:黃飛
?
電子發(fā)燒友App







評(píng)論