1. 程式人生 > 其它 >QTableWidget整行高亮去虛線,樣式定製

QTableWidget整行高亮去虛線,樣式定製

技術標籤:c/c++qtningto.com

很常見的一種需求,但是很可惜Qt沒有一種比較簡單的實現方式。在網上找了很多資料也沒有找到,實現方法比較複雜,但是經過
我的實驗,下面這種方法是可行的,而且有很多意想不到的好處。

定義介面類

儲存當前hovered行,split行是實現其他需求的可以不考慮

	class IView
	{
	public:
		virtual void setHoveredRow(int row) { row_ = row; }
		virtual void setSplitRow(int row) { splitRow_ = row; }
		int hoveredRow() const { return row_; }
		int splitRow() const { return splitRow_; }

	private:
		int row_ = -1;
		int splitRow_ = -1;
	};

表格繪製代理類delegate

這個類裡面可以實現對每個item的定製化繪製,下面split相關的實現可以不考慮

	class Delegate : public QStyledItemDelegate
	{
	public:
		Delegate(QObject *parent = 0);
		~Delegate();
		void setView(IView *view) { view_ = view; }
		void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
	private:
		IView *view_ = nullptr;
	};
	
	Delegate::Delegate(QObject *parent /* = 0 */)
		: QStyledItemDelegate(parent)
	{
	}

	Delegate::~Delegate()
	{
	}

	void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
	{
		QStyleOptionViewItem opt = option;
		// 去掉焦點虛線框
		if (opt.state & QStyle::State_HasFocus) {
			opt.state = opt.state & ~QStyle::State_HasFocus;
		}

		// hover時整行高亮
		if (index.row() == view_->hoveredRow()) {
			opt.state |= QStyle::State_MouseOver;
		} else {
			opt.state &= ~QStyle::State_MouseOver;
		}

		// 表格上部分樣式
		int splitRow = view_->splitRow();
		bool isFollower = index.row() <= splitRow;
		painter->fillRect(opt.rect, isFollower ? QColor("#0C1E1E") : QColor("#000000"));

		// 上下兩部分分隔線
		if (index.row() == splitRow) {
			QRect rect = opt.rect;
			rect.setTop(rect.top() + rect.height() - 2);
			painter->fillRect(rect, QColor("#273F3D"));
		}

		QStyledItemDelegate::paint(painter, opt, index);
	}

table的具體應用

結合上面兩個類來實現我們的需求,由於去掉了一些業務程式碼下面的類並不完整,不過不影響我們要實現的需求。

	class TableWidget : public QTableWidget, public IView
	{
		Q_OBJECT
	public:
		TableWidget(QWidget *parent = 0);
		
	protected:
		void mouseMoveEvent(QMouseEvent *event) override;
		void leaveEvent(QEvent *event) override;
	}
	
	TableWidget::TableWidget(QWidget *parent)
		: QTableWidget(parent)
	{
		// 隱藏水平垂直頭
		this->verticalHeader()->hide();
		this->horizontalHeader()->hide();
		// 去掉虛線框
		this->setShowGrid(false);
		// 單行選擇
		this->setSelectionBehavior(QAbstractItemView::SelectRows);
		this->setSelectionMode(QAbstractItemView::SingleSelection);
		// 禁止編輯
		this->setEditTriggers(QTableWidget::NoEditTriggers);
		// 關閉水平垂直滾動條,使用自定義的懸浮滾動條(為了滿足樣式需求)
		this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
		this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
		// 滑鼠跟蹤
		this->setMouseTracking(true);
		// 擴充套件最後一列
		this->horizontalHeader()->setStretchLastSection(true);
		// 支援拖拽
		this->setDragDropMode(QAbstractItemView::DragDrop);
		this->setDragEnabled(true);
		this->setAcceptDrops(true);
		// 應用基本qss樣式
		this->setProperty("qssname", "BindingTraderTable");

		Delegate *delegate = new Delegate();
		delegate->setView(this);
		this->setItemDelegate(delegate);
	}
	
	void TableWidget::mouseMoveEvent(QMouseEvent *event)
	{
		QModelIndex index = this->indexAt(event->pos());
		if (index.isValid()) {
			this->setHoveredRow(index.row());
		}
		QTableWidget::mouseMoveEvent(event);
	}
	
	void TableWidget::leaveEvent(QEvent *event)
	{
		this->setHoveredRow(-1);
		QTableWidget::leaveEvent(event);
	}

主要是通過mouseMoveEvent來設定當前hovered的行,然後delegate就可以根據當前row來繪製樣式。
雖然上面實現看起來有些複雜,但是這種分層方式是很靈活的在業務中很多對於table的需求都是
很有必要的,也容易擴充一些新的功能。