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

原文連接:QRowTable表格控件-支持hover整行、checked整行、局部列排序等瀏覽器

1、開心一刻

老公和老婆晚上回家,路旁忽然跳出三個持刀蒙面大漢:「綁架!你倆能夠走一個,回家等消息。」ide

老公一把將老婆推開:「老婆快走!」待老婆走遠後,三個蒙面人摘下面具:「尼瑪如今找你打個麻將這麼費勁?」函數

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

第二天老公回家,老婆撲上來含淚說:「關鍵時候才能看出老公對個人好,老公之後我啥都聽你的!字體

2、嘴一嘴

看完笑話,咱們進入正題。this

本篇文章咱們帶來的是一個表格的簡單使用,主要是把表格的hover、checked進行了從新定製,支持用戶本身去設置相關顏色,而且能夠對指定列進行放大縮小等。spa

爲何會寫這篇文章呢?博主本身使用Qt也好幾年了,對於Qt的使用算是比較有心得了吧。最近在作表格的一些相關東西,發現網上的不少文章講的不是特別好,所以將本身作的一個簡單事例作一分享,但願能幫到有須要的同窗。插件

本篇文章咱們主要對錶格的如下內容進行了封裝,內容比較有限,有深度定製需求的同窗能夠加我QQ詳談。設計

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

3、效果展現

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

配色時博主本身隨便搞的,配色只能說很通常,你們主要看效果和實現思路。

4、淺談實現

使用過QTableView或者瞭解控件的同窗應該都很清楚,表格是一個很強大的控件,支持咱們作各類各樣的功能,博主以前也想過幾篇相關的文章,都是講述表格控件的。

  1. Qt實現表格控件-支持多級列表頭、多級行表頭、單元格合併、字體設置等

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

  3. 屬性瀏覽器控件QtTreePropertyBrowser編譯成動態庫(設計師插件)

  4. 超級實用的屬性瀏覽器控件--QtTreePropertyBrowser

  5. Qt之表格控件螞蟻線

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

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

以下圖所示,是整個工程目錄結構,這裏主要重寫了數據源model和view

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

5、自定義數據源

所謂數據源,其實主要就是給view提供數據的地方,這裏咱們取了一個巧,數據源直接繼承自QStandarItemModel,這樣的話數據的存儲和獲取大部分的工做都不須要咱們去關心,由於QStandarItemModel這個類已經作的很完善。

這裏咱們主要從寫了兩個接口

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

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

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

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

6、自定義視圖

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

首先須要搞清楚,重寫視圖須要完成哪些工做,才能更好的準備定位每一個函數的意思。

一、目的

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

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

二、問題分析

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

一、鼠標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();
    }
}

二、取消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);

以上這個辦法也是不得已爲之,若是你們有更好的辦法,歡迎評論區留言

三、點擊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);//不能多選

四、 指定列排序

首先須要搞清楚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);
        }
    }
}

7、測試

一、view配置

QRowTable w;

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

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

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

w.SetHoverColor(Qt::red);

二、model配置

QRowModel * model = w.GetModel();

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

數據添加就跟咱們平時往QStandardItemModel中放數據相似,代碼太長就不放出來了。

8、相關文章

  1. Qt實現表格控件-支持多級列表頭、多級行表頭、單元格合併、字體設置等

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

  3. 屬性瀏覽器控件QtTreePropertyBrowser編譯成動態庫(設計師插件)

  4. 超級實用的屬性瀏覽器控件--QtTreePropertyBrowser

  5. Qt之表格控件螞蟻線

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





若是您以爲文章不錯,不妨給個 打賞,寫做不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!!














很重要--轉載聲明

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

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

相關文章
相關標籤/搜索