亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Qt GUI圖形圖像開發(fā)之QT表格控件QTableView,QTableWidget復(fù)雜表頭(多行表頭) 及凍結(jié)、固定特定的行的詳細方法與實例

 更新時間:2020年03月12日 16:42:15   作者:漫步繁華街  
這篇文章主要介紹了Qt GUI圖形圖像開發(fā)之QT表格控件QTableView,QTableWidget復(fù)雜表頭(多行表頭) 及凍結(jié)、固定特定的行的詳細方法與實例,需要的朋友可以參考下

我們在開發(fā)過程中對于表格使用頻率還是挺高的,使用QT框架開發(fā)時候我們使用QTableView或者QTableWidget創(chuàng)建表格。

其中表格分為 表格頭與表格體:

對于簡單地表格,我們可以設(shè)置表頭來滿足我們的要求(當然也可以隱藏表頭),不過對于定制化的表頭,我們能做的不是特別多。特別是對于復(fù)雜的表頭,使用自帶的表頭,無論怎么設(shè)置都不太可能達到需求。例如我最近接到的一個項目,需求是:

我們分析一下這個表格有什么特點:

1.表頭不是簡單的一行,而是兩行。

2.表頭有單元格的合并。

3.部分表頭中間有使用漸變的分隔線且分割線不是上下充滿表格的。

如果能解決上面三個問題,我們基本都可以把這個表格做出來了。這個表頭明顯是一個比較復(fù)雜的表頭。對于只對QT提供的API或者CSS上面三個問題,沒有一個能夠解決的。

這時候可能會有老師提出解決辦法:給header 設(shè)置itemDelegate,自己在itemDelegate中重寫paintEvent,自己畫表頭。 因為我們都知道,自己畫單元格,要更靈活,滿足更多需求。但是我們平時都是對單元格進行重繪,并不是對header的單元格進行重繪。于是就去搜索QT的幫助文檔,驚喜的發(fā)現(xiàn)居然有設(shè)置itemdelegate的API,心里覺得有戲于是創(chuàng)建 ItemDelegate類,對header進行設(shè)置如下

tableWidget->horizontalHorizon()->setItemDelegate(new ItemDelegate());

可是結(jié)果卻是令人失望的,沒有一點效果。于是反身去查找QT 關(guān)于這部分的介紹,終于找到了原因:

結(jié)果就顯而易見了,對于headerView,并不能使用ItemDelegate進行重繪。

那么我們就要另外想辦法了,經(jīng)過分析,剛開始提出了兩種方案:

解決方案

  描述 優(yōu)點 缺點
方案一
  • 隱藏表頭
  • 前兩行當做表頭
  • 內(nèi)容行從第三行開始
  • 對表格設(shè)置itemDelegate,對前兩行的表頭進行重繪
一個QTableWidget,實現(xiàn)起來方便一些。
  • 當出現(xiàn)滾動條,表頭會隨著著內(nèi)容表格個移動,不符合大眾習(xí)慣。
  • 改變了內(nèi)容表格的整個原有序列,所有的行數(shù)都需要比原來大2,對所有的API進行重寫工作難不高,復(fù)雜度比較高。
方案二
  • 使用一個QTableWidget命名為m_frozonTableWgt作為表頭。
  • 使用另外一個QTableWidget作為內(nèi)容顯示的表格。
  • m_frozonTableWgt隱藏表頭、隱藏滾動條、只顯示2行的內(nèi)容表格、顯示到內(nèi)容表格上方、只占據(jù)內(nèi)容表的表頭高度、設(shè)置ItemDelegate進行重繪。
  • 內(nèi)容表格,顯示表頭,高度設(shè)置成m_frozonTableWgt前兩行的高度。
最終效果更好,體驗更好。
  • 需要對2個QTableWidget進行操作,比較麻煩。
  • 需要對表頭的QTableWidget進行鎖死(固定)。
  • 需要對2個QtableWidget進行聯(lián)動設(shè)置

總結(jié)一下就是:

第一種方案比較簡單,但是最終體驗效果不太好。

第二種方案實現(xiàn)起來比較復(fù)雜,但是最終體驗效果比較好。

本著成就客戶與自我成長的態(tài)度,最終選擇了第二種解決方案。

我們首先要做的就是創(chuàng)建一個繼承于QTableWidget的一個類,命名為TDMSummaryTableWgt。

class TDMSummaryTableWgt : public QTableWidget

然后需要在TDMSummaryTableWgt類中,聲明另外一個用于header的QTableWidget,命名為 m_frozenTableWgt;

private:
  QTableWidget *m_frozenTableWgt;// 使用TableWidget 作為header,并凍結(jié)

這個m_frozenTableWgt,就是作為表頭,并且固定位置,不隨著滾動條移動位置。

這個時候我們只需要解決兩個問題,就可以搞定表頭了:

1.表頭位置鎖定(固定、鎖死)。

2.重繪表頭。

對于第一個問題,表頭位置的固定。我們應(yīng)該從哪些方面考慮來解決?

1.從界面初始化開始,我們應(yīng)當讓表頭m_frozenTableWgt具備: 不顯示表頭,不顯示滾動條、設(shè)置rowcount為2行并隱藏2行后所有的元素、設(shè)置窗口層次在TDMSummaryTableWgt之前、對單元格進行合并等要素。

這里要特別注意的是,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);//最后一個單元格擴展
  m_frozenTableWgt->setFocusPolicy(Qt::NoFocus);//解決選中虛框問題
  m_frozenTableWgt->setFrameShape(QFrame::NoFrame);//去除邊框 尷尬
  m_frozenTableWgt->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//隱藏滾動條
  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ù)報率"));
  m_frozenTableWgt->setItem(1, 4, new QTableWidgetItem("新學(xué)員續(xù)報率"));
  m_frozenTableWgt->setItem(1, 5, new QTableWidgetItem("續(xù)報增長人數(shù)"));
  m_frozenTableWgt->setItem(1, 6, new QTableWidgetItem("續(xù)報增長率"));
  m_frozenTableWgt->setItem(1, 7, new QTableWidgetItem("續(xù)報增長率"));
  m_frozenTableWgt->setItem(1, 8, new QTableWidgetItem("新學(xué)員續(xù)報率"));
 
  //連接信號槽。用于滾動條聯(lián)動
  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)動問題了,主要包括表格的尺寸變化、滾動條移動、界面平移等問題。

我們首先要寫一個方法,來確定m_frozenTableWgt與TDMSummaryTableWgt位置。

void TDMSummaryTableWgt::updateFrozenTableGeometry()
{
  m_frozenTableWgt->setGeometry(frameWidth(),
                 frameWidth(),
                 viewport()->width(),
                 horizontalHeader()->height());
 
}

我們需要重寫3個上面提到問題解決方案的函數(shù),在每個方法里都要重新執(zhí)行updateFrozenTableGeometry();

protected:
  /**
   * @brief resizeEvent        重載虛函數(shù) resize事件,同時更新m_frozenTableWgt的位置
   * @param event
   */
  virtual void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
 
  /**
   * @brief moveCursor        重載虛函數(shù) 鼠標移動事件
   * @param cursorAction
   * @param modifiers
   * @return
   */
  virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) Q_DECL_OVERRIDE;
 
  /**
   * @brief scrollTo         TableWidget移動事件
   * @param index
   * @param hint
   */
  void scrollTo (const QModelIndex & index, ScrollHint hint = EnsureVisible) Q_DECL_OVERRIDE;

對上面這三個虛函數(shù),我們需要特別注意的重點是moveCursor方法。這個方法里我們應(yīng)該重點關(guān)注鼠標向上移動的情景:只有當鼠標向上移動,并且TDMSummaryTableWgt還未顯示到第一行,并且可視區(qū)域的頂點應(yīng)該小于m_frozenTableWgt的第一行,才允許繼續(xù)向上移動:

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;
}

做完上面這幾部,基本解決了第一個問題,就是將m_frozenTableWgt的固定行(凍結(jié))的功能。

要完成m_frozenTableWgtde 的樣式重繪,就是第二個要解決的問題了。

這個問題,我們要新建一個繼承于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ù)每個單元格的背景不同進行繪制背景

  int rowIndex = index.row();//行號
  int colIndex = index.column();//列號
  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ù)報率
                  colIndex == 4 || //新學(xué)員續(xù)報率
                  colIndex == 5 || //續(xù)報增長人數(shù)
                  colIndex == 6))) //續(xù)報增長率
    {
      color.setRgb(214, 228, 253);
    }
    else if ((rowIndex == 0 && colIndex == 7) || //8月19日
         (rowIndex == 1 && (colIndex == 7 || //續(xù)報率
                  colIndex == 8))) //新學(xué)員續(xù)報率
    {
      color.setRgb(203, 221, 255);
    }
 
    //繪制背景
    painter->setPen(color);
    painter->setBrush(QBrush(color));
    painter->drawRect(option.rect);

根據(jù)每個單元格要求繪畫是否需要右側(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);    
    }

最后將每個單元格的字體畫出來

    //字體
    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復(fù)雜表頭(多行表頭) 及凍結(jié)、固定特定的行的詳細方法與實例,更多關(guān)于Qt GUI圖形圖像開發(fā)知識請查看下面的相關(guān)鏈接

相關(guān)文章

  • 對比C語言中memccpy()函數(shù)和memcpy()函數(shù)的用法

    對比C語言中memccpy()函數(shù)和memcpy()函數(shù)的用法

    這篇文章主要介紹了對比C語言中memccpy()函數(shù)和memcpy()函數(shù)的用法,二者都是用于復(fù)制內(nèi)存內(nèi)容,注意區(qū)別,需要的朋友可以參考下
    2015-08-08
  • C語言函數(shù)棧幀的創(chuàng)建與銷毀詳解

    C語言函數(shù)棧幀的創(chuàng)建與銷毀詳解

    函數(shù)棧幀(stack frame)就是函數(shù)調(diào)用過程中在程序的調(diào)用棧(call stack)所開辟的空間,下面這篇文章主要給大家介紹了關(guān)于C語言函數(shù)棧幀的創(chuàng)建與銷毀的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-09-09
  • C++實現(xiàn)LeetCode( 69.求平方根)

    C++實現(xiàn)LeetCode( 69.求平方根)

    這篇文章主要介紹了C++實現(xiàn)LeetCode( 69.求平方根),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++動態(tài)數(shù)組類的封裝實例

    C++動態(tài)數(shù)組類的封裝實例

    這篇文章主要介紹了C++動態(tài)數(shù)組類的封裝,很重要的概念,需要的朋友可以參考下
    2014-08-08
  • C++ 約瑟夫環(huán)問題案例詳解

    C++ 約瑟夫環(huán)問題案例詳解

    這篇文章主要介紹了C++ 約瑟夫環(huán)問題案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Qt重寫QStackedWidget模擬實現(xiàn)home界面滑動效果

    Qt重寫QStackedWidget模擬實現(xiàn)home界面滑動效果

    這篇文章主要為大家詳細介紹了Qt如何通過重寫QStackedWidget模擬實現(xiàn)home界面滑動效果,文中的實現(xiàn)過程講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-11-11
  • 深入線性時間復(fù)雜度求數(shù)組中第K大數(shù)的方法詳解

    深入線性時間復(fù)雜度求數(shù)組中第K大數(shù)的方法詳解

    本篇文章是對線性時間復(fù)雜度求數(shù)組中第K大數(shù)的方法進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • C語言如何計算一個整數(shù)的位數(shù)

    C語言如何計算一個整數(shù)的位數(shù)

    這篇文章主要介紹了C語言如何計算一個整數(shù)的位數(shù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C++頭文件algorithm中的函數(shù)功能詳解

    C++頭文件algorithm中的函數(shù)功能詳解

    這篇文章主要介紹了C++頭文件algorithm中的函數(shù)功能詳解,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • C++ 11新特性之大括號初始化詳解

    C++ 11新特性之大括號初始化詳解

    這篇文章主要介紹了C++ 11新特性之大括號初始化的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價值,需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08

最新評論