删除文章

确定要删除这篇文章吗?

取消
确定

QTableWidget整行高亮去虚线,样式定制

     阅读(29)  2020-10-15 02:56:12

很常见的一种需求,但是很可惜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的需求都是 很有必要的,也容易扩充一些新的功能。

文章评论

Keep it simple,stupid
文章数
348
今日访问
1119
今日IP数
545
最近评论

在家赚钱: 在家赚钱 <a href="http://www.265250.com/" >在家赚钱</a> 已阅,感谢站长分享!
liangzi: 不错 谢谢分享
tujiaw: registerThreadInactive:如果当前没有激活的线程,就去激活线程,让等待的线程去执行任务。
hgzzx: 佩服佩服。 请教:registerThreadInactive的作用是什么?
xuehaoyun: 很不错,来围观一下
tujiaw: 抱歉csdn code服务关闭了,这个代码我也找不到了
回到顶部