1. 程式人生 > >QRowTable表格控制元件-支援hover整行、checked整行、指定列排序等

QRowTable表格控制元件-支援hover整行、checked整行、指定列排序等

目錄

  • 一、開心一刻
  • 二、嘴一嘴
  • 三、效果展示
  • 四、淺談實現
  • 五、自定義資料來源
    • 1、data函式
    • 2、flags函式
  • 六、自定義檢視
    • 1、目的
    • 2、問題分析
  • 七、測試
  • 八、相關文章

原文連結:QRowTable表格控制元件-支援hover整行、checked整行、區域性列排序等

一、開心一刻

老公和老婆晚上回家,路旁突然跳出三個持刀蒙面大漢:“綁架!你倆可以走一個,回家等訊息。”

老公一把將老婆推開:“老婆快走!”待老婆走遠後,三個蒙面人摘下面具:“尼瑪現在找你打個麻將這麼費勁?”

五分鐘後老公致電老婆:"往卡里打五千塊,別報警,他們說關我一夜明早放人。"十分鐘後老公從卡里取走五千塊戰鬥到天明。

次日老公回家,老婆撲上來含淚說:“關鍵時候才能看出老公對我的好,老公以後我啥都聽你的!

二、嘴一嘴

看完笑話,我們進入正題。

本篇文章我們帶來的是一個表格的簡單使用,主要是把表格的hover、checked進行了重新定製,支援使用者自己去設定相關顏色,並且可以對指定列進行放大縮小等。

為什麼會寫這篇文章呢?博主自己使用Qt也好幾年了,對於Qt的使用算是比較有心得了吧。最近在做表格的一些相關東西,發現網上的很多文章講的不是特別好,因此將自己做的一個簡單事例做一分享,希望能幫到有需要的同學。

本篇文章我們主要對錶格的以下內容進行了封裝,內容比較有限,有深度定製需求的同學可以加我QQ詳談。

  1. hover行背景色
  2. checked行背景色
  3. 列寬是否可排序
  4. 列寬允許拖動範圍
  5. 準確定位hover狀態

三、效果展示

如下圖所示,一個簡單的gif效果展示。

配色時博主自己隨便搞的,配色只能說很一般,大家主要看效果和實現思路。

四、淺談實現

使用過QTableView或者瞭解控制元件的同學應該都很清楚,表格是一個很強大的控制元件,支援我們做各種各樣的功能,博主之前也想過幾篇相關的文章,都是講述表格控制元件的。

Qt實現表格控制元件-支援多級列表頭、多級行表頭、單元格合併、字型設定等

Qt高仿Excel表格元件-支援凍結列、凍結行、內容自適應和合並單元格

屬性瀏覽器控制元件QtTreePropertyBrowser編譯成動態庫(設計師外掛)

超級實用的屬性瀏覽器控制元件--QtTreePropertyBrowser

Qt之表格控制元件螞蟻線

當然了表格控制元件的使用遠遠不止於此,後續有時間和精力我會陸續推出更多有用好玩兒的功能。

本篇文章的功能實現也比較簡單,寫這個demo我大概用了大半天的時間,程式碼量其實不多,大部分的時間主要用來設計介面和重構邏輯功能了。

如下圖所示,是整個工程目錄結構,這裡主要重寫了資料來源model和view

下面我們就分別講述model和view都幹了些什麼

五、自定義資料來源

所謂資料來源,其實主要就是給view提供資料的地方,這裡我們取了一個巧,資料來源直接繼承自QStandarItemModel,這樣的話資料的儲存和獲取大部分的工作都不需要我們去關心,因為QStandarItemModel這個類已經做的很完善。

這裡我們主要從寫了兩個介面

virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

virtual Qt::ItemFlags flags(const QModelIndex & index) const override;

1、data函式

檢視獲取資料的介面就是data,因此這個介面我們必須重寫,實現程式碼也很簡單,主要是需要大家對Qt的MVC有一個基本的認識。

QVariant QRowModel::data(const QModelIndex & index, int role /*= Qt::DisplayRole*/) const
{
    if (Qt::BackgroundRole == role)
    {
        if (index.row() == m_iHoverRow)
        {
            return m_HoverColor;
        }
    }
    else if (role == Qt::ForegroundRole)
    {
        if (index.row() == m_iHoverRow)
        {
            return m_HoverColor.lighter(255);
        }
    }

    return QStandardItemModel::data(index, role);
}

看上述程式碼,當繪製檢視的時候,hover一行時,我們需要返回自定義的顏色值,其他情況走預設處理即可,是不是很簡單。

關於checked的實現不能放在這裡,因為當item被選中的時候,item的背景色不是取自Qt::BackgroundRole,同時前景色也不是取自Qt::ForegroundRole,因此這裡處理不了。

如果非要讓checked狀態在這裡實現也是有辦法的,我們可以重寫flags函式,讓item不能被選中,這個辦法博主是試過的,沒有問題。 但是就存在一個隱,如果後期我們的item想被選中,就比較麻煩了。

基於以上設想,我們只需要這樣重寫flags函式,然後在data函式中返回checked行的背景色和前景色即可。

Qt::ItemFlags QRowModel::flags(const QModelIndex & index) const
{
    return Qt::ItemIsEnabled;
}

2、flags函式

上一小節flags函式都已經展示出來了,item處於可用狀態,這裡還需要在新增上可選中狀態,以免有其他坑

Qt::ItemFlags QRowModel::flags(const QModelIndex & index) const
{
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}

以上就是model函式的重寫了,比較簡單,下面放出model的標頭檔案

/**
* 簡介: 主要提供介面 提供hover行
*/
class QRowModel : public QStandardItemModel
{
    Q_OBJECT

public:
    explicit QRowModel(QObject * parent = 0);
    ~QRowModel();

private:
    //hover時背景色  不建議外部直接呼叫
    void SetHoverColor(const QColor & color);
    QColor GetHoverColor() const { return m_HoverColor; }

    //設定當前hover行  不建議外部直接呼叫
    void SetHoverRow(int row);
    int GetHoverRow() const { return m_iHoverRow; }

protected:
    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

    virtual Qt::ItemFlags flags(const QModelIndex & index) const override;

private:
    int m_iHoverRow = -1;//沒有hover
    QColor m_HoverColor = QColor(20, 22, 23);

    friend class QRowTable;
};

六、自定義檢視

下面講述今天的重頭戲view。

首先需要搞清楚,重寫檢視需要完成哪些工作,才能更好的準備定位每個函式的意思。

1、目的

  1. hover時,把hover行通知到資料來源
  2. 準確的hover和取消hover狀態,這個問題確實搞了好久
  3. 點選item時,設定行選中色
  4. 指定列可排序

有了以上目標之後,我們逐個問題解決。

2、問題分析

針對以上4個目的,我們逐個分析解決辦法

1、滑鼠hover到這個比較簡單,而且可以通過多種方式進行獲取。

想要拿到這個狀態,有一個很重要的屬性需要開啟:setMouseTracking(true);

a、如果我們重寫的是QTableWidget這個類,那麼可以去接收cellEntered這個訊號

b、如果重寫跟本篇文章一樣,重寫的QTableView這個類,那麼我們需要重寫mouseMoveEvent這個函式,然後通過indexAt函式獲取當前行。

void QRowTable::mouseMoveEvent(QMouseEvent * event)
{
    QTableView::mouseMoveEvent(event);

    const QModelIndex & index = indexAt(event->pos());
    int row = -1;
    if (index.isValid())
    {
        row = index.row();
    }

    if (m_pModel->GetHoverRow() != row)
    {
        m_pModel->SetHoverRow(index.row());
        viewport()->update();
    }
}

2、取消hover裝態

這個問題處理確實化了好長時間,主要還是想處理的辦法更優雅,效率高一些。

這裡為了實現不在item上時立刻取消hover狀態,主要做了2件事。

第一件事

重寫leaveEvent函式,滑鼠離開時,恢復hover行為-1

void QRowTable::leaveEvent(QEvent * e)
{
    if (m_pModel->GetHoverRow() != -1)
    {
        m_pModel->SetHoverRow(-1);
        viewport()->update();
    }
    QTableView::leaveEvent(e);
}

第二件事

重寫了QHeaderView,當滑鼠在表頭移動時,傳送MouseMove訊號,重置當前hover行為-1

void QRowHeader::mouseMoveEvent(QMouseEvent * event)
{
    emit MouseMove();

    QHeaderView::mouseMoveEvent(event);
}
auto callback = [this]{
    if (m_pModel->GetHoverRow() != -1)
    {
        m_pModel->SetHoverRow(-1);
        viewport()->update();
    }
};
connect(vHeader, &QRowHeader::MouseMove, this, callback);
connect(hHeader, &QRowHeader::MouseMove, this, callback);

以上這個辦法也是不得已為之,如果大家有更好的辦法,歡迎評論區留言

3、點選item時設定當前行高亮背景色

第一小節的最後,我們也提到了,checked正行可以放到data函式中完成,但是由於我們的item有了可選擇屬性後,當前選中的item,或者選中行的背景色和前景色都是取自以下兩個屬性,因此這裡我們只需要把這兩個屬性顏色值進行設定即可。

QPalette::Highlight
QPalette::HighlightedText

設定checked行顏色實現方式如下。

void QRowTable::SetCheckedColor(const QColor & color)
{
    m_CheckedColor = color;

    QPalette palette = this->palette();
    palette.setBrush(QPalette::Inactive, QPalette::Highlight, m_CheckedColor);
    palette.setBrush(QPalette::Inactive, QPalette::HighlightedText, m_CheckedColor.lighter(255));
    setPalette(palette);
}

如果仔細想一想,可能就會覺得有些問題,這裡我們怎麼去控制是一個單元格背景色還是整行背景色呢?

莫慌,加上以下兩個屬性即可,介面真的很簡單,啥意思我就不說了。如果實現不知道的同學,歡迎評論區留言

setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QTableView::SingleSelection);//不能多選

4、 指定列排序

首先需要搞清楚Qt自帶的排序處理邏輯,然後才可以對症下藥,這裡我也是跟了Qt自己程式碼,然後各種分析後,得出的處理方式。

Qt的程式碼分析這裡不做討論,有需要的同學私信吧。

各種程式碼跟蹤後發現,當我們設定了setSortingEnabled為true時,Qt就支援排序了,並且在排序完成後會發給我們一個sortIndicatorChanged訊號,這個訊號主要是用來顯示排序三角形的。

如果我們想不顯示排序三角形,但是隻是排序也是可以的,可以在接收這個訊號後,呼叫setSortIndicatorShown介面隱藏三角形

為什麼會這樣麻煩呢?因為樓主跟蹤Qt的程式碼了,發現如果排序了,Qt的三角形就是必須畫出來的

void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
    ...
    if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
        opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
                            ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
                            
    ...
}

是不是很刺激,Qt太強大了,啥事情都給我們搞好了。

本篇文章我們主要是實現指定列不能進行排序,因此處理函式是這麼幹的,當接收到非排序列排序訊號時,呼叫setSortingEnabled介面設定禁止排序。

void QRowTable::SortColumnChanged(int logicalIndex, Qt::SortOrder order)
{
    if (m_Indicator.contains(logicalIndex) && m_Indicator[logicalIndex] == false)
    {
        if (isSortingEnabled())
        {
            setSortingEnabled(false);
        }
    }
    else
    {
        if (isSortingEnabled() == false)
        {
            setSortingEnabled(true);
        }
    }
}

七、測試

1、view配置

QRowTable w;

//前兩列不可排序
w.SetIndicatorVisible(0, false);
w.SetIndicatorVisible(1, false);

//設定列最大寬度
w.SetColumnMinWidth(50);

//設定列最小寬度
w.SetColumnMaxWidth(150);

w.SetHoverColor(Qt::red);

2、model配置

QRowModel * model = w.GetModel();

QStringList headlist;
headlist << QStringLiteral("程式碼") << QStringLiteral("名稱") << QStringLiteral("行業") << QStringLiteral("價格") << QStringLiteral("漲跌幅") << QStringLiteral("換手率");
model->setHorizontalHeaderLabels(headlist);

資料新增就跟我們平時往QStandardItemModel中放資料類似,程式碼太長就不放出來了。

八、相關文章

Qt實現表格控制元件-支援多級列表頭、多級行表頭、單元格合併、字型設定等

Qt高仿Excel表格元件-支援凍結列、凍結行、內容自適應和合並單元格

屬性瀏覽器控制元件QtTreePropertyBrowser編譯成動態庫(設計師外掛)

超級實用的屬性瀏覽器控制元件--QtTreePropertyBrowser

Qt之表格控制元件螞蟻線

以上就是本篇文章的所有內容了,一個簡易的整行hover、整行checked的表格





如果您覺得文章不錯,不妨給個打賞,寫作不易,感謝各位的支援。您的支援是我最大的動力,謝謝!!!














很重要--轉載宣告

  1. 本站文章無特別說明,皆為原創,版權所有,轉載時請用連結的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords

  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。