Qt實(shí)現(xiàn)自定義矩陣布局
前言:
當(dāng)界面需要同時(shí)展示多個(gè)項(xiàng)的時(shí)候,可能需要一個(gè)矩陣來填充數(shù)據(jù),因?yàn)橥ǔ2恢罃?shù)據(jù)項(xiàng)的多少,所以支持自定義行列就顯得尤為重要,
比如可能需要在一臺(tái)電腦同時(shí)顯示多個(gè)報(bào)表的數(shù)據(jù),如果一直切換,因?yàn)闊o法比較各個(gè)報(bào)表的數(shù)據(jù),難免不夠直觀,這種時(shí)候,通過矩陣布局同步顯示一般是首選方案。
效果展示:
本次采用的技術(shù)是qt,思路是通過在矩陣上布局對(duì)應(yīng)的控件,以搭載數(shù)據(jù)的顯示,這樣子數(shù)據(jù)就可以放到對(duì)應(yīng)的承載控件上顯示。
通過行列號(hào)的設(shè)置來隨時(shí)切換布局效果,矩陣同時(shí)支持隨主界面大小的改變而改變,以適應(yīng)不同的場(chǎng)景需求。
主要實(shí)現(xiàn)代碼:
void MatrixLayoutWidget::onSetMatrixLayout(int row, int column, bool bIsResize) { ? ? QSize size = _displayWall->size(); ? ? int num = row*column; ? ? if (num == 0) ? ? { ? ? ? ? num = 1; ? ? ? ? row = 1; ? ? ? ? column = 1; ? ? } ? ? _row = row; ? ? _column = column; ? ? ? int labelSpace = 5; ? ? int labelWidth = size.width() / column; ? ? int labelHeigt = size.height() / row; ? ? ? if (!bIsResize) ? ? ? ? removeLabel(); ? ? ? for (int i = 0; i < num; i++) ? ? { ? ? ? ? if (!bIsResize) ? ? ? ? { ? ? ? ? ? ? QLabel *label = new QLabel(this); ? ? ? ? ? ? label->setAlignment(Qt::AlignCenter); ? ? ? ? ? ? label->setStyleSheet("background-color:rgb(243,243,147)"); ? ? ? ? ? ? label->resize(labelWidth - labelSpace, labelHeigt - labelSpace); ? ? ? ? ? ? _labelMap[i] = label;?? ?//注冊(cè) ? ? ? ? ? } ? ? ? ? else ? ? ? ? { ? ? ? ? ? ? QLabel *label = nullptr; ? ? ? ? ? ? auto iter = _labelMap.begin(); ? ? ? ? ? ? for (; iter != _labelMap.end(); iter++) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? label = iter.value(); ? ? ? ? ? ? ? ? label->resize(labelWidth - labelSpace, labelHeigt - labelSpace); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? ? for (int j = 0; j < column; j++) ? ? { ? ? ? ? for (int k = 0; k < row; k++) ? ? ? ? { ? ? ? ? ? ? int index = (row*j + k); ? ? ? ? ? ? QLabel *label = _labelMap[index]; ? ? ? ? ? ? label->hide(); ? ? ? ? ? ? label->move(labelWidth * j, labelHeigt * k+30); ? ? ? ? ? ? label->show(); ? ? ? ? } ? ? } ? ? _displayWall->update(); }
以上采用QMap來注冊(cè)管理對(duì)應(yīng)的承載控件,因?yàn)楹罄m(xù)需要對(duì)控件上的子控件進(jìn)行操作,所以保存了一個(gè)索引,以表示鼠標(biāo)點(diǎn)擊的是哪個(gè)承載控件。
通過這個(gè)思路,可以拓展很多功能,比如在對(duì)應(yīng)承載控件雙擊,彈出詳細(xì)的報(bào)表數(shù)據(jù),鼠標(biāo)右鍵彈出菜單,對(duì)控件上展示的報(bào)表數(shù)據(jù)進(jìn)行其他操作等。
每次擴(kuò)大行列布局的時(shí)候,目前采用先去除之前的控件,再創(chuàng)建新的,不過對(duì)于非實(shí)時(shí)獲取數(shù)據(jù)并展示的需求而已不是很友好,因?yàn)橛脩艨赡苤幌朐黾觾蓚€(gè)新的報(bào)表,卻把之前的數(shù)據(jù)清除掉了,
所以根據(jù)業(yè)務(wù)的需求,如果增加了數(shù)據(jù),可以在原先的map表基礎(chǔ)上再注冊(cè)新的label,然后重新遍歷即可。
void MatrixLayoutWidget::removeLabel() { ? ? //清除 ? ? auto iter = _labelMap.begin(); ? ? for (; iter != _labelMap.end(); iter++) ? ? { ? ? ? ? if (iter.value()) { ? ? ? ? ? ? delete iter.value(); ? ? ? ? ? ? iter.value() = nullptr; ? ? ? ? } ? ? } ? ? _labelMap.clear(); } ? void MatrixLayoutWidget::resizeEvent(QResizeEvent *event) { ? ? //重新計(jì)算QLable的大小 ? ? if (_labelMap.count() > 0) { ? ? ? ? onSetMatrixLayout(_row, _column, true); ? ? } }
通過重寫resizeEvent事件來實(shí)現(xiàn)矩陣上的控件隨窗口的大小變化而變化。只有畫布上有矩陣的時(shí)候,才去做處理,避免不必要的麻煩。
整個(gè)代碼demo邏輯很簡單,因?yàn)榭蓴U(kuò)展性比較強(qiáng),后期準(zhǔn)備增加點(diǎn)新的功能,同步到github上,比如可以在每個(gè)矩陣的label上都顯示波形,或者視頻,或者圖表。
以下是所有代碼:
//.h #ifndef MATRIXLAYOUTWIDGET_H #define MATRIXLAYOUTWIDGET_H ? #include <QWidget> #include <QPushButton> #include <QLineEdit> #include <QLabel> #include <QMap> ? class MatrixLayoutWidget : public QWidget { ? ? Q_OBJECT ? public: ? ? MatrixLayoutWidget(QWidget *parent = nullptr); ? ? ~MatrixLayoutWidget(); ? private: ? ? void removeLabel(); ? ? virtual void resizeEvent(QResizeEvent *event) override; ? protected slots: ? ? void onSetMatrixLayout(int row, int column, bool bIsResize=false); ? ? void onMatrixLayoutDivision(); ? private: ? ? QPushButton?? ??? ?*_1x1Btn; ? ? QPushButton?? ??? ?*_2x2Btn; ? ? QPushButton?? ??? ?*_3x3Btn; ? ? QPushButton?? ??? ?*_editBtn; ? ? QLineEdit?? ??? ?*_rowEdit; ? ? QLineEdit?? ??? ?*_columnEdit; ? ? QFrame *_displayWall; ? ? QMap<quint16, QLabel *> _labelMap; ? ? int _row;?? ??? ?//行 ? ? int _column;?? ?//列 }; #endif // MATRIXLAYOUTWIDGET_H ? ? ? //cpp #include "matrixlayoutwidget.h" #include <QHBoxLayout> #include <QVBoxLayout> #include <QMessageBox> ? MatrixLayoutWidget::MatrixLayoutWidget(QWidget *parent) ? ? : QWidget(parent) { ? ? int controlW = 180; ? ? int controlH = 25; ? ? ? _1x1Btn = new QPushButton; ? ? _2x2Btn = new QPushButton; ? ? _3x3Btn = new QPushButton; ? ? _rowEdit = new QLineEdit; ? ? _columnEdit = new QLineEdit; ? ? _editBtn = new QPushButton; ? ? ? _1x1Btn->setObjectName("btn"); ? ? _2x2Btn->setObjectName("btn"); ? ? _3x3Btn->setObjectName("btn"); ? ? _editBtn->setObjectName("btn"); ? ? ? _1x1Btn->setFixedSize(controlW / 3, controlH); ? ? _1x1Btn->setText("1X1"); ? ? _2x2Btn->setFixedSize(controlW/3, controlH); ? ? _2x2Btn->setText("2X2"); ? ? _3x3Btn->setFixedSize(controlW / 3, controlH); ? ? _3x3Btn->setText("3X3"); ? ? _rowEdit->setFixedSize(controlW / 2, controlH); ? ? _columnEdit->setFixedSize(controlW / 2, controlH); ? ? _editBtn->setFixedSize(controlW / 3, controlH); ? ? _editBtn->setText("Custom"); ? ? // ? ? QHBoxLayout *editLayout = new QHBoxLayout; ? ? editLayout->setMargin(0); ? ? editLayout->setSpacing(0); ? ? editLayout->addWidget(new QLabel("Row:")); ? ? editLayout->addWidget(_rowEdit); ? ? editLayout->addWidget(new QLabel("X")); ? ? editLayout->addWidget(new QLabel("Column:")); ? ? editLayout->addWidget(_columnEdit); ? ? editLayout->addWidget(_editBtn); ? ? ? // ? ? QHBoxLayout *hlayout = new QHBoxLayout; ? ? hlayout->setMargin(0); ? ? hlayout->setSpacing(10); ? ? hlayout->addWidget(_1x1Btn); ? ? hlayout->addWidget(_2x2Btn); ? ? hlayout->addWidget(_3x3Btn); ? ? hlayout->addLayout(editLayout); ? ? ? _displayWall = new QFrame; ? ? _displayWall->setStyleSheet("background-color:rgb(122,125,118)"); ? ? _displayWall->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); ? ? QVBoxLayout *vhlayout = new QVBoxLayout; ? ? vhlayout->setMargin(0); ? ? vhlayout->setSpacing(5); ? ? vhlayout->addLayout(hlayout); ? ? vhlayout->addWidget(_displayWall); ? ? ? connect(_1x1Btn, SIGNAL(clicked()), this, SLOT(onMatrixLayoutDivision())); ? ? connect(_2x2Btn, SIGNAL(clicked()), this, SLOT(onMatrixLayoutDivision())); ? ? connect(_3x3Btn, SIGNAL(clicked()), this, SLOT(onMatrixLayoutDivision())); ? ? connect(_editBtn, SIGNAL(clicked()), this, SLOT(onMatrixLayoutDivision())); ? ? ? this->setLayout(vhlayout); ? ? this->setMinimumSize(400,300); ? ? onSetMatrixLayout(1, 1); } ? MatrixLayoutWidget::~MatrixLayoutWidget() { ? ? removeLabel(); } ? ? void MatrixLayoutWidget::onSetMatrixLayout(int row, int column, bool bIsResize) { ? ? QSize size = _displayWall->size(); ? ? int num = row*column; ? ? if (num == 0) ? ? { ? ? ? ? num = 1; ? ? ? ? row = 1; ? ? ? ? column = 1; ? ? } ? ? _row = row; ? ? _column = column; ? ? ? int labelSpace = 5; ? ? int labelWidth = size.width() / column; ? ? int labelHeigt = size.height() / row; ? ? ? if (!bIsResize) ? ? ? ? removeLabel(); ? ? ? for (int i = 0; i < num; i++) ? ? { ? ? ? ? if (!bIsResize) ? ? ? ? { ? ? ? ? ? ? QLabel *label = new QLabel(this); ? ? ? ? ? ? label->setAlignment(Qt::AlignCenter); ? ? ? ? ? ? label->setStyleSheet("background-color:rgb(243,243,147)"); ? ? ? ? ? ? label->resize(labelWidth - labelSpace, labelHeigt - labelSpace); ? ? ? ? ? ? _labelMap[i] = label;?? ?//注冊(cè) ? ? ? ? ? } ? ? ? ? else ? ? ? ? { ? ? ? ? ? ? QLabel *label = nullptr; ? ? ? ? ? ? auto iter = _labelMap.begin(); ? ? ? ? ? ? for (; iter != _labelMap.end(); iter++) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? label = iter.value(); ? ? ? ? ? ? ? ? label->resize(labelWidth - labelSpace, labelHeigt - labelSpace); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? ? for (int j = 0; j < column; j++) ? ? { ? ? ? ? for (int k = 0; k < row; k++) ? ? ? ? { ? ? ? ? ? ? int index = (k + row*j); ? ? ? ? ? ? QLabel *label = _labelMap[index]; ? ? ? ? ? ? label->hide(); ? ? ? ? ? ? label->move(labelWidth * j, labelHeigt * k+30); ? ? ? ? ? ? label->show(); ? ? ? ? } ? ? } ? ? _displayWall->update(); } ? void MatrixLayoutWidget::onMatrixLayoutDivision() { ? ? if (sender() == _1x1Btn) ? ? { ? ? ? ? _row = 1; ? ? ? ? _column = 1; ? ? } ? ? else if (sender() == _2x2Btn) ? ? { ? ? ? ? _row = 2; ? ? ? ? _column = 2; ? ? } ? ? else if (sender() == _3x3Btn) ? ? { ? ? ? ? _row = 3; ? ? ? ? _column = 3; ? ? } ? ? else if (sender() == _editBtn) ? ? { ? ? ? ? _row = _rowEdit->text().toInt(); ? ? ? ? _column = _columnEdit->text().toInt(); ? ? ? ? if (_row == 0 || _column == 0) { ? ? ? ? ? ? QMessageBox::critical(this, tr("warn"), "Row or Column Is Zero", ? ? ? ? ? ? ? ? QMessageBox::Ok); ? ? ? ? ? ? return; ? ? ? ? } ? ? } ? ? ? onSetMatrixLayout(_row, _column, false); } ? ? void MatrixLayoutWidget::removeLabel() { ? ? //清除 ? ? auto iter = _labelMap.begin(); ? ? for (; iter != _labelMap.end(); iter++) ? ? { ? ? ? ? if (iter.value()) { ? ? ? ? ? ? delete iter.value(); ? ? ? ? ? ? iter.value() = nullptr; ? ? ? ? } ? ? } ? ? _labelMap.clear(); } ? void MatrixLayoutWidget::resizeEvent(QResizeEvent *event) { ? ? //重新計(jì)算QLable的大小 ? ? if (_labelMap.count() > 0) { ? ? ? ? onSetMatrixLayout(_row, _column, true); ? ? } }
界面采用代碼繪制,比起qt設(shè)計(jì)師拖拽而已,比較方便調(diào)整,因?yàn)樵O(shè)計(jì)師一打破布局,再調(diào)整就很麻煩,而且也不方便復(fù)用,所以個(gè)人感覺還是代碼繪制比較舒服。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C語言中的運(yùn)算符優(yōu)先級(jí)和結(jié)合性一覽表
這篇文章主要介紹了C語言中的運(yùn)算符優(yōu)先級(jí)和結(jié)合性一覽表,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02C++語法詳解之封裝、構(gòu)造函數(shù)、析構(gòu)函數(shù)
這篇文章主要介紹了C++語法詳解之封裝、構(gòu)造函數(shù)、析構(gòu)函數(shù)的相關(guān)知識(shí),通過實(shí)例代碼給大家詳細(xì)介紹,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03C語言數(shù)據(jù)結(jié)構(gòu)之動(dòng)態(tài)分配實(shí)現(xiàn)串
這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu)之動(dòng)態(tài)分配實(shí)現(xiàn)串的相關(guān)資料,希望通過本文能幫助到大家,讓大家實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)中動(dòng)態(tài)分配實(shí)現(xiàn)串的實(shí)例,需要的朋友可以參考下2017-10-10C語言中網(wǎng)絡(luò)地址與二進(jìn)制數(shù)之間轉(zhuǎn)換的函數(shù)小結(jié)
這篇文章主要介紹了C語言中網(wǎng)絡(luò)地址與二進(jìn)制數(shù)之間轉(zhuǎn)換的函數(shù)小結(jié),是C語言入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09排列組合總結(jié):將結(jié)果進(jìn)行輸出的實(shí)現(xiàn)方法
本篇文章關(guān)于排列組合的總結(jié),對(duì)結(jié)果進(jìn)行輸出做了介紹。需要的朋友參考下2013-05-05C++設(shè)計(jì)與實(shí)現(xiàn)ORM系統(tǒng)實(shí)例詳解
這篇文章主要為大家介紹了C++設(shè)計(jì)與實(shí)現(xiàn)ORM系統(tǒng)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09C/C++?Qt?TabWidget?實(shí)現(xiàn)多窗體創(chuàng)建詳解
TabWidget組件配合自定義Dialog組件,可實(shí)現(xiàn)一個(gè)復(fù)雜的多窗體分頁結(jié)構(gòu)。這篇文章就主要介紹了如何通過TabWidget實(shí)現(xiàn)多窗體的創(chuàng)建,感興趣的小伙伴可以了解一下2021-12-12