QRowTable表格控制元件-支援hover整行、checked整行、指定列排序等
目錄
- 一、開心一刻
- 二、嘴一嘴
- 三、效果展示
- 四、淺談實現
- 五、自定義資料來源
- 1、data函式
- 2、flags函式
- 六、自定義檢視
- 1、目的
- 2、問題分析
- 七、測試
- 八、相關文章
原文連結:QRowTable表格控制元件-支援hover整行、checked整行、區域性列排序等
一、開心一刻
老公和老婆晚上回家,路旁突然跳出三個持刀蒙面大漢:“綁架!你倆可以走一個,回家等訊息。”
老公一把將老婆推開:“老婆快走!”待老婆走遠後,三個蒙面人摘下面具:“尼瑪現在找你打個麻將這麼費勁?”
五分鐘後老公致電老婆:"往卡里打五千塊,別報警,他們說關我一夜明早放人。"十分鐘後老公從卡里取走五千塊戰鬥到天明。
次日老公回家,老婆撲上來含淚說:“關鍵時候才能看出老公對我的好,老公以後我啥都聽你的!
二、嘴一嘴
看完笑話,我們進入正題。
本篇文章我們帶來的是一個表格的簡單使用,主要是把表格的hover、checked進行了重新定製,支援使用者自己去設定相關顏色,並且可以對指定列進行放大縮小等。
為什麼會寫這篇文章呢?博主自己使用Qt也好幾年了,對於Qt的使用算是比較有心得了吧。最近在做表格的一些相關東西,發現網上的很多文章講的不是特別好,因此將自己做的一個簡單事例做一分享,希望能幫到有需要的同學。
本篇文章我們主要對錶格的以下內容進行了封裝,內容比較有限,有深度定製需求的同學可以加我QQ詳談。
- hover行背景色
- checked行背景色
- 列寬是否可排序
- 列寬允許拖動範圍
- 準確定位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、目的
- hover時,把hover行通知到資料來源
- 準確的hover和取消hover狀態,這個問題確實搞了好久
- 點選item時,設定行選中色
- 指定列可排序
有了以上目標之後,我們逐個問題解決。
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的表格
如果您覺得文章不錯,不妨給個打賞,寫作不易,感謝各位的支援。您的支援是我最大的動力,謝謝!!!
很重要--轉載宣告
本站文章無特別說明,皆為原創,版權所有,轉載時請用連結的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords
如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。