文章标题 原创 翻译 转载 文章内容 很常见的一种需求,但是很可惜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的需求都是 很有必要的,也容易扩充一些新的功能。 文章类别 Python Mobile Android Java Shell Life Database Bug Windows IOS Tools Boost Node.js Mac Product Tips C/C++ Golang Javascript React Qt MQ MongoDB Design Web Linux LLM ChatGPT RAG AI 提交