您好,登錄后才能下訂單哦!
這篇文章主要介紹QT框架中如何使用QTableView或者QTableWidget創(chuàng)建表格。,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
我們在開發(fā)過程中對(duì)于表格使用頻率還是挺高的,使用QT框架開發(fā)時(shí)候我們使用QTableView或者QTableWidget創(chuàng)建表格。
其中表格分為 表格頭與表格體:
對(duì)于簡單地表格,我們可以設(shè)置表頭來滿足我們的要求(當(dāng)然也可以隱藏表頭),不過對(duì)于定制化的表頭,我們能做的不是特別多。特別是對(duì)于復(fù)雜的表頭,使用自帶的表頭,無論怎么設(shè)置都不太可能達(dá)到需求。例如我最近接到的一個(gè)項(xiàng)目,需求是:
我們分析一下這個(gè)表格有什么特點(diǎn):
1.表頭不是簡單的一行,而是兩行。
2.表頭有單元格的合并。
3.部分表頭中間有使用漸變的分隔線且分割線不是上下充滿表格的。
如果能解決上面三個(gè)問題,我們基本都可以把這個(gè)表格做出來了。這個(gè)表頭明顯是一個(gè)比較復(fù)雜的表頭。對(duì)于只對(duì)QT提供的API或者CSS上面三個(gè)問題,沒有一個(gè)能夠解決的。
這時(shí)候可能會(huì)有老師提出解決辦法:給header 設(shè)置itemDelegate,自己在itemDelegate中重寫paintEvent,自己畫表頭。 因?yàn)槲覀兌贾?,自己畫單元格,要更靈活,滿足更多需求。但是我們平時(shí)都是對(duì)單元格進(jìn)行重繪,并不是對(duì)header的單元格進(jìn)行重繪。于是就去搜索QT的幫助文檔,驚喜的發(fā)現(xiàn)居然有設(shè)置itemdelegate的API,心里覺得有戲于是創(chuàng)建 ItemDelegate類,對(duì)header進(jìn)行設(shè)置如下
tableWidget->horizontalHorizon()->setItemDelegate(new ItemDelegate());
可是結(jié)果卻是令人失望的,沒有一點(diǎn)效果。于是反身去查找QT 關(guān)于這部分的介紹,終于找到了原因:
結(jié)果就顯而易見了,對(duì)于headerView,并不能使用ItemDelegate進(jìn)行重繪。
那么我們就要另外想辦法了,經(jīng)過分析,剛開始提出了兩種方案:
解決方案
描述 | 優(yōu)點(diǎn) | 缺點(diǎn) | |
方案一 |
| 一個(gè)QTableWidget,實(shí)現(xiàn)起來方便一些。 |
|
方案二 |
| 最終效果更好,體驗(yàn)更好。 |
|
總結(jié)一下就是:
第一種方案比較簡單,但是最終體驗(yàn)效果不太好。
第二種方案實(shí)現(xiàn)起來比較復(fù)雜,但是最終體驗(yàn)效果比較好。
本著成就客戶與自我成長的態(tài)度,最終選擇了第二種解決方案。
我們首先要做的就是創(chuàng)建一個(gè)繼承于QTableWidget的一個(gè)類,命名為TDMSummaryTableWgt。
class TDMSummaryTableWgt : public QTableWidget
然后需要在TDMSummaryTableWgt類中,聲明另外一個(gè)用于header的QTableWidget,命名為 m_frozenTableWgt;
private: QTableWidget *m_frozenTableWgt;// 使用TableWidget 作為header,并凍結(jié)
這個(gè)m_frozenTableWgt,就是作為表頭,并且固定位置,不隨著滾動(dòng)條移動(dòng)位置。
這個(gè)時(shí)候我們只需要解決兩個(gè)問題,就可以搞定表頭了:
1.表頭位置鎖定(固定、鎖死)。
2.重繪表頭。
對(duì)于第一個(gè)問題,表頭位置的固定。我們應(yīng)該從哪些方面考慮來解決?
1.從界面初始化開始,我們應(yīng)當(dāng)讓表頭m_frozenTableWgt具備: 不顯示表頭,不顯示滾動(dòng)條、設(shè)置rowcount為2行并隱藏2行后所有的元素、設(shè)置窗口層次在TDMSummaryTableWgt之前、對(duì)單元格進(jìn)行合并等要素。
這里要特別注意的是,m_frozenTableWgt與TDMSummaryTableWgt設(shè)置的列數(shù)應(yīng)該完全一致,每一列的尺寸與伸展方案也應(yīng)該完全一致。
void TDMSummaryTableWgt::initFrozenFrame() { m_frozenTableWgt = new QTableWidget(this); m_frozenTableWgt->horizontalHeader()->setVisible(false);//表頭不可見 m_frozenTableWgt->verticalHeader()->setVisible(false);//表頭不可見 m_frozenTableWgt->setShowGrid(false);//網(wǎng)格線不可見 m_frozenTableWgt->setEditTriggers(QAbstractItemView::NoEditTriggers);//設(shè)置單元格不可編輯 m_frozenTableWgt->horizontalHeader()->setStretchLastSection(true);//最后一個(gè)單元格擴(kuò)展 m_frozenTableWgt->setFocusPolicy(Qt::NoFocus);//解決選中虛框問題 m_frozenTableWgt->setFrameShape(QFrame::NoFrame);//去除邊框 尷尬 m_frozenTableWgt->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//隱藏滾動(dòng)條 m_frozenTableWgt->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);// m_frozenTableWgt->setHorizontalScrollMode(ScrollPerPixel); m_frozenTableWgt->setItemDelegate(new ItemDelegate(0));//設(shè)置繪畫代理(主要在代理中畫出來header) viewport()->stackUnder(m_frozenTableWgt);//設(shè)置窗口層次 m_frozenTableWgt->setColumnCount(10);//header10列 m_frozenTableWgt->setRowCount(2);//header2行 m_frozenTableWgt->setRowHeight(0, 42);//第一行設(shè)置高度42px m_frozenTableWgt->setRowHeight(1, 42);//第二行設(shè)置高度42px for (int row = 2; row < m_frozenTableWgt->rowCount(); ++row)//隱藏2行后的行 m_frozenTableWgt->setRowHidden(row, true); //===================設(shè)置header內(nèi)容=================// //合并單元格 m_frozenTableWgt->setSpan(0, 0, 2, 1);//老師ID m_frozenTableWgt->setSpan(0, 1, 2, 1);//老師姓名 m_frozenTableWgt->setSpan(0, 2, 2, 1);//老師姓名 m_frozenTableWgt->setSpan(0, 3, 1, 4);//最新日期(8月20) m_frozenTableWgt->setSpan(0, 7, 1, 2);//前一日(8月19) m_frozenTableWgt->setSpan(0, 9, 2, 1);//操作 m_frozenTableWgt->setItem(0, 0, new QTableWidgetItem("老師ID")); m_frozenTableWgt->setItem(0, 1, new QTableWidgetItem("老師姓名")); m_frozenTableWgt->setItem(0, 2, new QTableWidgetItem("老師姓名")); m_frozenTableWgt->setItem(0, 3, new QTableWidgetItem("8月20日")); m_frozenTableWgt->setItem(0, 7, new QTableWidgetItem("8月19日")); m_frozenTableWgt->setItem(0, 9, new QTableWidgetItem("操作")); m_frozenTableWgt->setItem(1, 3, new QTableWidgetItem("續(xù)報(bào)率")); m_frozenTableWgt->setItem(1, 4, new QTableWidgetItem("新學(xué)員續(xù)報(bào)率")); m_frozenTableWgt->setItem(1, 5, new QTableWidgetItem("續(xù)報(bào)增長人數(shù)")); m_frozenTableWgt->setItem(1, 6, new QTableWidgetItem("續(xù)報(bào)增長率")); m_frozenTableWgt->setItem(1, 7, new QTableWidgetItem("續(xù)報(bào)增長率")); m_frozenTableWgt->setItem(1, 8, new QTableWidgetItem("新學(xué)員續(xù)報(bào)率")); //連接信號(hào)槽。用于滾動(dòng)條聯(lián)動(dòng) connect(m_frozenTableWgt->verticalScrollBar(), &QAbstractSlider::valueChanged, verticalScrollBar(), &QAbstractSlider::setValue); connect(verticalScrollBar(), &QAbstractSlider::valueChanged, m_frozenTableWgt->verticalScrollBar(), &QAbstractSlider::setValue); updateFrozenTableGeometry();//更新位置 m_frozenTableWgt->show(); }
2.除了上面的考慮之外,我們就需要考慮m_frozenTableWgt與TDMSummaryTableWgt之間的聯(lián)動(dòng)問題了,主要包括表格的尺寸變化、滾動(dòng)條移動(dòng)、界面平移等問題。
我們首先要寫一個(gè)方法,來確定m_frozenTableWgt與TDMSummaryTableWgt位置。
void TDMSummaryTableWgt::updateFrozenTableGeometry() { m_frozenTableWgt->setGeometry(frameWidth(), frameWidth(), viewport()->width(), horizontalHeader()->height()); }
我們需要重寫3個(gè)上面提到問題解決方案的函數(shù),在每個(gè)方法里都要重新執(zhí)行updateFrozenTableGeometry();
protected: /** * @brief resizeEvent 重載虛函數(shù) resize事件,同時(shí)更新m_frozenTableWgt的位置 * @param event */ virtual void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; /** * @brief moveCursor 重載虛函數(shù) 鼠標(biāo)移動(dòng)事件 * @param cursorAction * @param modifiers * @return */ virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) Q_DECL_OVERRIDE; /** * @brief scrollTo TableWidget移動(dòng)事件 * @param index * @param hint */ void scrollTo (const QModelIndex & index, ScrollHint hint = EnsureVisible) Q_DECL_OVERRIDE;
對(duì)上面這三個(gè)虛函數(shù),我們需要特別注意的重點(diǎn)是moveCursor方法。這個(gè)方法里我們應(yīng)該重點(diǎn)關(guān)注鼠標(biāo)向上移動(dòng)的情景:只有當(dāng)鼠標(biāo)向上移動(dòng),并且TDMSummaryTableWgt還未顯示到第一行,并且可視區(qū)域的頂點(diǎn)應(yīng)該小于m_frozenTableWgt的第一行,才允許繼續(xù)向上移動(dòng):
QModelIndex TDMSummaryTableWgt::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers) { QModelIndex current = QTableView::moveCursor(cursorAction, modifiers); if (cursorAction == MoveUp && current.row() > 0 && visualRect(current).topLeft().y() < m_frozenTableWgt->rowHeight(1) ){ const int newValue = verticalScrollBar()->value() + visualRect(current).topLeft().y() - m_frozenTableWgt->rowHeight(0) - m_frozenTableWgt->rowHeight(1); verticalScrollBar()->setValue(newValue); } return current; }
做完上面這幾部,基本解決了第一個(gè)問題,就是將m_frozenTableWgt的固定行(凍結(jié))的功能。
要完成m_frozenTableWgtde 的樣式重繪,就是第二個(gè)要解決的問題了。
這個(gè)問題,我們要新建一個(gè)繼承于QStyledItemDelegate的代理類,我們叫ItemDelegate。并且重寫paint方法,在paint方法里繪制m_frozenTableWgt;
m_frozenTableWgt->setItemDelegate(new ItemDelegate(0));//設(shè)置繪畫代理(主要在代理中畫出來header)
class ItemDelegate : public QStyledItemDelegate { Q_OBJECT public: ItemDelegate(int type, QObject *parent=0); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; private: };
在paint方法中,根據(jù)每個(gè)單元格的背景不同進(jìn)行繪制背景
int rowIndex = index.row();//行號(hào) int colIndex = index.column();//列號(hào) if (rowIndex == 0 || rowIndex == 1)//前兩行作為header { //背景 QColor color; if (rowIndex == 0 && (colIndex == 0 || //老師ID colIndex == 1 || //老師姓名 colIndex == 2 || //課程類型 colIndex == 9)) //操作 { color.setRgb(231, 238, 251); } else if ((rowIndex == 0 && colIndex == 3) || //8月20日 (rowIndex == 1 && (colIndex == 3 || //續(xù)報(bào)率 colIndex == 4 || //新學(xué)員續(xù)報(bào)率 colIndex == 5 || //續(xù)報(bào)增長人數(shù) colIndex == 6))) //續(xù)報(bào)增長率 { color.setRgb(214, 228, 253); } else if ((rowIndex == 0 && colIndex == 7) || //8月19日 (rowIndex == 1 && (colIndex == 7 || //續(xù)報(bào)率 colIndex == 8))) //新學(xué)員續(xù)報(bào)率 { color.setRgb(203, 221, 255); } //繪制背景 painter->setPen(color); painter->setBrush(QBrush(color)); painter->drawRect(option.rect);
根據(jù)每個(gè)單元格要求繪畫是否需要右側(cè)的漸變的分隔線。
//右側(cè)spacer if ((rowIndex == 0 && (colIndex == 0 || colIndex == 1) )) { int startX = option.rect.right(); int startY = option.rect.y() + (option.rect.height() - 40) / 2; int endX = startX; int endY = startY + 40; QLinearGradient linearGradient(startX, startY, endX, endY); linearGradient.setColorAt(0, QColor(164, 188, 240, 0)); linearGradient.setColorAt(0.5, QColor(164, 188, 240, 255)); linearGradient.setColorAt(1, QColor(164, 188, 240, 0)); painter->setBrush(linearGradient); painter->drawRect(option.rect.right()- 2, startY, 2, 40); } else if (rowIndex == 1 && (colIndex == 3 || colIndex == 4 || colIndex == 5 || colIndex == 7 )) { int startX = option.rect.right(); int startY = option.rect.y() + (option.rect.height() - 28) / 2; int endX = startX; int endY = startY + 28; QLinearGradient linearGradient(startX, startY, endX, endY); linearGradient.setColorAt(0, QColor(164, 188, 240, 0)); linearGradient.setColorAt(0.5, QColor(164, 188, 240, 255)); linearGradient.setColorAt(1, QColor(164, 188, 240, 0)); painter->setBrush(linearGradient); painter->drawRect(option.rect.right()- 2, startY, 2, 28); }
最后將每個(gè)單元格的字體畫出來
//字體 painter->setPen(QColor(51, 51, 51)); QTextOption op; op.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); QFont font; font.setFamily("Microsoft YaHei"); font.setPixelSize(14); font.setBold(true); painter->setFont(font); painter->drawText(option.rect, index.data(Qt::DisplayRole).toString(), op);
這樣就解決了header里面的難題。
以上是“QT框架中如何使用QTableView或者QTableWidget創(chuàng)建表格?!边@篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。