原文連接:QRowTable表格控件-支持hover整行、checked整行、局部列排序等瀏覽器
老公和老婆晚上回家,路旁忽然跳出三個持刀蒙面大漢:「綁架!你倆能夠走一個,回家等消息。」ide
老公一把將老婆推開:「老婆快走!」待老婆走遠後,三個蒙面人摘下面具:「尼瑪如今找你打個麻將這麼費勁?」函數
五分鐘後老公致電老婆:"往卡里打五千塊,別報警,他們說關我一晚上明早放人。"十分鐘後老公從卡里取走五千塊戰鬥到天明。測試
第二天老公回家,老婆撲上來含淚說:「關鍵時候才能看出老公對個人好,老公之後我啥都聽你的!字體
看完笑話,咱們進入正題。this
本篇文章咱們帶來的是一個表格的簡單使用,主要是把表格的hover、checked進行了從新定製,支持用戶本身去設置相關顏色,而且能夠對指定列進行放大縮小等。spa
爲何會寫這篇文章呢?博主本身使用Qt也好幾年了,對於Qt的使用算是比較有心得了吧。最近在作表格的一些相關東西,發現網上的不少文章講的不是特別好,所以將本身作的一個簡單事例作一分享,但願能幫到有須要的同窗。插件
本篇文章咱們主要對錶格的如下內容進行了封裝,內容比較有限,有深度定製需求的同窗能夠加我QQ詳談。設計
以下圖所示,一個簡單的gif效果展現。
配色時博主本身隨便搞的,配色只能說很通常,你們主要看效果和實現思路。
使用過QTableView或者瞭解控件的同窗應該都很清楚,表格是一個很強大的控件,支持咱們作各類各樣的功能,博主以前也想過幾篇相關的文章,都是講述表格控件的。
固然了表格控件的使用遠遠不止於此,後續有時間和精力我會陸續推出更多有用好玩兒的功能。
本篇文章的功能實現也比較簡單,寫這個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;
視圖獲取數據的接口就是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函數都已經展現出來了,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。
首先須要搞清楚,重寫視圖須要完成哪些工做,才能更好的準備定位每一個函數的意思。
有了以上目標以後,咱們逐個問題解決。
針對以上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); } } }
一、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中放數據相似,代碼太長就不放出來了。
以上就是本篇文章的全部內容了,一個簡易的整行hover、整行checked的表格
![]() |
![]() |
很重要--轉載聲明