QRowTable表格控制項(五)-重寫表頭排序、支持第三次單擊恢復預設排序

来源:https://www.cnblogs.com/swarmbees/archive/2019/09/14/11519796.html
-Advertisement-
Play Games

[TOC] 原文鏈接: "QRowTable表格控制項(五) 重寫表頭排序、支持第三次單擊恢復預設排序" 一、原生表格 開發客戶端程式的方式月來源多了,現在很流行的libcef、electron等等都可以作為快速開發客戶端軟體的方案,但是如果需要一個號的用戶體驗,還是離不開原生化的開發,雖然慢,但是性 ...


目錄

原文鏈接:QRowTable表格控制項(五)-重寫表頭排序、支持第三次單擊恢復預設排序

一、原生表格

開發客戶端程式的方式月來源多了,現在很流行的libcef、electron等等都可以作為快速開發客戶端軟體的方案,但是如果需要一個好的用戶體驗,還是離不開原生化的開發,雖然慢,但是性能好啊。

說到原生化開發,那對應的UI庫相對較多,流行的就有Qt、soui、duilib、還有老掉牙的MFC和其他一些第三方公司開源維護的directUI庫等等。網上找到一篇整理的文章,有興趣的同學可以參考C++界面庫

目前C++客戶端使用最廣泛的就是UI框架就是Qt,它不僅包含了GUI控制項,更多的其實是一種解決方案,使用過Qt的同學都比較清楚,Qt的安裝動態庫有幾十個之多,可是如果你只想使用Qt的GUi模塊的話,就只需要包含3個動態庫即可,他們分別是核心模塊QtCore、Gui模塊QtGui和QtWidget。

當我們將Qt作為我們的開發SDK時,大多數時候原生的控制項+qss美化就可以完成我們的需求,然而總有一些特殊情況,比如產品經理腦殘的時候、或者說是業務場景傻逼了,總是需要完成一些奇奇怪怪交互,那麼我們就需要重寫原生的控制項實現方式。

今天就來說一個案例--表格控制項列排序方式。

對於某一些特殊的場景下,我們的表格展示的數據可能需要排序,這樣的表格控制項Qt已經給我們提供好了,只需要我們從寫一些類和介面即可。前邊已經寫了4篇關於表格控制項的功能,分別是QRowTable表格控制項-支持hover整行、checked整行、指定列排序等QRowTable表格控制項(二)-紅漲綠跌QRowTable表格控制項(三)-效率優化之-合理使用QStandardItemQRowTable表格控制項(四)-效率優化之-優化數據源,感興趣的同學可以去看看。

不幸的是Qt自帶的表格排序功能,即是我們沖寫完所有介面依然不能滿足負責的業務需求--表格表頭連續3點三次是一個迴圈,什麼意思呢?

傳統表格排序

Qt自帶的表格排序行為是這樣的,預設情況是不排序的,我們可以通過介面開啟排序,或者通過介面設置不排序,當我們啟用排序規則後,假設說我們的表格點擊點擊一下是降序,點擊第二下就是升序,再次點擊是又會恢復到降序規則,這樣是不是還挺完美呢!

這個時候產品有話說了,點擊第三次時,需要設置程式為不排序。

程式員:卧槽。。。。你說什麼。。。。聽不到。。。。

新的排序規則

在傳統表格排序的基礎上做一下調整

  1. 可以支持某些列不允許排序
  2. 3次連續單擊為一個迴圈,也就是降序-升序-無序這樣3個狀態迴圈

不得不說產品的腦洞還是很大的。既然產品都說想要這個功能了,那麼有時間還是得考慮下。跟產品溝通良久後,有瞭如下安排,雖然這個功能對用戶來說不是一個特別需要的功能,但是當我們的軟體功能穩定後,迭代沒有那麼著急的時候,是不是可以考慮研究下這個而功能呢。

然後也就有了本篇文章

雖然重寫了Qt本身的邏輯,沒想到還是可以實現的!!!

二、效果展示

按照慣例先上圖,看看是不是同學們想要的功能。

三、實現方式

新的表格排序有2個點需要我們去思考,分別是某些列排序、排序交互修改,下麵我們分開來去實現

1、排序列定製

Qt預設提供了可排序介面,但是開啟後我們所有的列都支持排序了,這個時候我們就需要研究Qt的源碼,看看Qt的排序是怎麼觸發的,然後在合理的時機去加上我們不支持排序的邏輯

博主這裡找到的做法是重寫QHaderView這個類,並重寫實現了滑鼠按下並抬起的介面,在這個介面中判斷我們業務層是不是允許排序。

重寫後的邏輯是這樣的

  1. 如果不允許排序,我們先調用Qt原有的介面禁用所有列排序功能

  2. 調用父類的滑鼠抬起函數

  3. 如果不允許排序,需要調用Qt原有的介面啟用所有列排序功能

以上邏輯的步驟2是原有的邏輯,步驟1和步驟3分別是在進行業務邏輯判斷後進行的邏輯調整,達到我們禁用某些列排序的功能

void QRowHeader::mouseReleaseEvent(QMouseEvent * event)
{
    int column = logicalIndexAt(event->pos().x());
    if (m_Indicator.contains(column) 
        && m_Indicator[column] == false
        && qAbs(event->x() - m_pPressPos.x()) < QApplication::startDragDistance()/*非拖拽*/)
    {
        setSectionsClickable(false);
        QHeaderView::mouseReleaseEvent(event);
        setSectionsClickable(true);
    }
    
    QHeaderView::mouseReleaseEvent(event);
    ...

如上代碼,m_Indicator結構中存儲了我們想要定製的是否允許排序的列,只需要對外暴露一個修改介面即可,代碼是不是還很簡單呢。

void QRowHeader::SetSortEnable(int logicalIndex, bool enable)
{
    m_Indicator[logicalIndex] = enable;
}

這樣禁用某些列排序的功能就是實現了。

禁用某些列排序這個功能相對來說好實現一些,畢竟重寫的邏輯不是特別複雜,下麵我們來看下怎麼修改排序交互邏輯。

2、排序交互修改

有了前面的問題處理思路,這個功能依然如此,我們先跟Qt源碼,看看已有的排序交互邏輯實現怎麼實現的,然後在合理的實際去重置某些變數的值,達到重寫交互邏輯。

博主這裡跟蹤完Qt預設的排序實現方式後,發現重寫這個功能還是有一定難度的,首先數據排序是一塊,另一塊是一旦啟用排序後,排序箭頭的繪製這塊也需要去重寫。

什麼意思呢?

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

既然這條路子是走不通了,那麼我們只能取巧,換其他方式。

終於、皇天不負有心人被博主想到一個好辦法,代碼量依然還是很少。

回到我們最開始的需求,我們其實就是想讓第三次點擊時,只是一個特殊的操作,然後把第四點擊當做第一次單擊即可。

有了這個想法後,那麼就來乾吧,既然還是重寫滑鼠抬起函數,想盡一切辦法監控連續的第三次單擊,把他處理成非排序狀態,然後在下一次單擊時,走正常的排序邏輯。

void QRowHeader::mouseReleaseEvent(QMouseEvent * event)
{
    ...
    QHeaderView::mouseReleaseEvent(event);

    column = logicalIndexAt(event->pos().x());
    static bool nextNoSort = false;
    static int prevColumn = -1;
    if (nextNoSort && prevColumn == column
        && qAbs(event->x() - m_pPressPos.x()) < QApplication::startDragDistance())
    {
        emit RestoreSort();//恢復預設排序
    }

    if (nextNoSort != true
        && prevColumn == column
        && sectionsClickable()
        && sortIndicatorOrder() == Qt::DescendingOrder)
    {
        if (qAbs(event->x() - m_pPressPos.x()) < QApplication::startDragDistance())
        {
            nextNoSort = true;
            prevColumn = column;
        }
        else
        {
            nextNoSort = false;
        }
    }
    else
    {
        if (nextNoSort && qAbs(event->x() - m_pPressPos.x()) >= QApplication::startDragDistance())
        {
            nextNoSort = true;
        }
        else
        {
            nextNoSort = false;
            prevColumn = column;
        }
    }
    ...
}

好了,代碼以上。不過這裡重點還是要說下為什麼這麼乾!

首先需要調用父類的mouseReleaseEvent函數,否則拖拽會有問題,而且必須調用這個函數才可以讓記憶體數據正常。

然後我們記錄了一系列記憶體狀態,判斷是不是需要恢復排序狀態,當條件滿足時發出RestoreSort信號,外部程式只需要接收這個信號,然後恢復預設排序即可。

恢復預設排序

void QRowTable::RestoreSort()
{
    m_pFilter->SetCompareType(QFilterModel::CT_NULL);
    m_pFilter->invalidate();
    m_pHHeader->setSortIndicator(-1, Qt::DescendingOrder);
}

四、相關文章

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

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

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

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

  5. Qt之表格控制項螞蟻線

  6. QRowTable表格控制項-支持hover整行、checked整行、指定列排序等

  7. QRowTable表格控制項(二)-紅漲綠跌

  8. QRowTable表格控制項(三)-效率優化之-合理使用QStandardItem

  9. QRowTable表格控制項(四)-效率優化之-優化數據源

  10. C++界面庫


值得一看的優秀文章:

  1. 財聯社-產品展示
  2. 廣聯達-產品展示
  3. Qt定製控制項列表
  4. 牛逼哄哄的Qt庫





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














很重要--轉載聲明

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

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



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一:基礎演算法題5道 1.阿姆斯特朗數 如果一個n位正整數等於其各位數字的n次方之和,則稱該數為阿姆斯特朗數。判斷用戶輸入的數字是否為阿姆斯特朗數。 (1)題目分析:這裡要先得到該數是多少位的,然後再把每一位的數字截取出來,把各位數字的n次方之和和該數一起判斷即可。(2)演算法分析:python中有le ...
  • [TOC] 序言:上一章我們初步介紹了一下Docker的概念,那麼這次我們著手於Docker的使用,瞭解一下常見的Docker的操作命令。此外不管學習什麼東西,我們不但要瞭解縱向的知識體系,最好能加上橫向的擴展,進行類比,Docker的命令風格和Git有著種種相似。好了廢話不多說,我們開始Docke ...
  • 按照上邊的執行流程圖,我們可以看出一個SpringMVC整體的一個執行輪廓,下麵我們具體來分析下 首先伺服器接收到一個請求,匹配並調用了我們的前端控制器(DispatcherServlet)也叫中央處理器的請求路徑,在web.xml文件中配置,我們來看下配置文件 因為DispatcherServle ...
  • [TOC] 1. 引用的定義 C++新增加了引用的概念: 引用可以看作一個已定義變數的別名 引用的語法 2. 引用的本質 引用在C++中的內部實現是一個常量指針 C++編譯器在編譯過程中使用常量指針作為引用的內部實現,因此引用所占用的記憶體大小和指針相同 從使用的角度,引用只是一個別名,C++為了實用 ...
  • 效果如下: 實現代碼; ...
  • [TOC] 題目 "P3958 乳酪" 思路 並查集。將乳酪的下錶面設為$0$號,輸入空洞位置時判斷該空洞如果與下錶面相切或相交就和到一個集合里,最後找到與上錶面相切或相交的空洞判斷與$0$號是否在一個集合里。 $Code$ ...
  • Eureka服務治理 下麵請聽第一個話題,母。。。咳咳,拿錯書了。 Eureka簡介 eureka是什麼呢? 簡單來說呢,當我的微服務應用多了起來,一個一個寫死再程式里是件很不優雅的事情,而且同一服務可能會多個實例存在,來對服務分流,就是負載均衡。 所以,我們需要一個位置來存放服務的訪問列表,以供消 ...
  • [TOC] 控制流程之for迴圈 基本語法 while可以迴圈一切事物 for 迴圈提供了一種手段,不依賴索引取值 for+break for+continue for+else for迴圈不被break終止就執行else後面的代碼,否則就不執行 for迴圈列印lodaing 數字類型內置方法 整型 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...