概要
使用Qt編寫上位機(jī)是一個非常不錯的選擇,簡單說一下作者的看法:
①Q(mào)t采用的是C++,所以在某種程度上與嵌入式設(shè)備數(shù)據(jù)類型兼容,所以嵌入式設(shè)備與上位機(jī)間的協(xié)議定義數(shù)據(jù)結(jié)構(gòu)等都可以相互套用,
②Qt是跨平臺的,所以代碼開發(fā)一次,多平臺運行。
③Qt學(xué)習(xí)成本低,網(wǎng)上資料很多,基本你遇到的問題,網(wǎng)上都能找到。
對于嵌入式開發(fā)者來說,會寫上位機(jī)可以提高開發(fā)效率,比如可以開發(fā)抓包工具,日志數(shù)據(jù)分析,升級(網(wǎng)絡(luò)升級,串口升級等)
說到升級,那么就有些場景,比如批量升級,某臺升級等需求。有這些需求那么就要有對應(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è)計:①視圖中集成了處理用戶輸入的功能,②視圖將用戶輸入作為內(nèi)部獨立的子功能實現(xiàn)
模型視圖中的委托:①委托是視圖中處理用戶輸入的部件。②視圖可以設(shè)置委托對象用于用戶輸入。③委托對象負(fù)責(zé)創(chuàng)建和顯示用戶輸入上下文。
Qt 自定義委托--實現(xiàn)批量升級UI
準(zhǔn)備工作:下載Qt工具,然后創(chuàng)建一個基類為QMainWindow的工程,并且?guī)i的。
設(shè)計一個ui,一個CheckBox控件和TableView控件
自定義表格中單選框CheckBox委托 -- 創(chuàng)建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())?//如果數(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)度條其實采用進(jìn)度條項樣式(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用于處理用戶輸入
按鈕其實按鈕項樣式(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)建按鈕項樣式 ????????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()));???//?松開彈出消息框,顯示對應(yīng)行號 ????????????} ????????} ????} ????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)建一個自定義QRiceTableView類繼承QTableView類
構(gòu)造方法實現(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中實現(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控件,選擇提升為:
填寫對應(yīng)類名,類的頭文件相對路徑:
點擊添加后,然后點擊提升按鈕,就完成了控件的提升
在mainwindow.cpp中增加測試用例:
在構(gòu)造方法中,創(chuàng)建兩條數(shù)據(jù),并且啟動一個定時器刷新進(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); }
界面中全選框的實現(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é)果:
編輯:黃飛
?
評論
查看更多