相关文章推荐
强健的碗  ·  Gateway or machine is ...·  4 周前    · 
坏坏的铁板烧  ·  python ...·  9 月前    · 

QTableView实现鼠标悬浮(hover)行高亮显示

需要实现QTableview鼠标悬浮时当前行高亮显示。但是实现的过程中发现一开始的方案不能用,必须捕捉鼠标的move事件通过Delegate自己绘制背景实现。一开始想通过重载Delegate里面的editorEvent捕捉。后面发现鼠标的move事件可以捕捉的到,但是leave事件获取不到,这样就会造成鼠标移出表格始终又一行高亮。后面只能通过继承QTableview捕捉到鼠标事件,然后通过delegate绘制的方法实现。

在Qt4中可以直接设置item的悬停(hover)事件,如下所示:

QTableView::item:hover {
    background-color: rgba(200,200,220,255);

然后在tableview的属性中设置selectionMode和selectionBehavior的属性为每次选中一行。

ui.TableView->setSelectionBehavior(QAbstractItemView::SelectRows);
	ui.TableView->setSelectionMode(QAbstractItemView::SingleSelection);

结果发现在Qt5中样式表设置的样式不能生效。所以只能另找方案。

解决方案确定

在stackoverflow上面查了有人提供了下面的方案:

  1. You can use delegates to draw the row background…
    You will need to set the row to highlight in the delegate and based on that, do the highlighting.
  2. Catch the signal of current row. Iterate over the items in that row and set background for each item.

翻译一下就是捕捉当前鼠标悬浮(hover)行的信号,使用委托绘制行背景

  1. 绘制背景
    绘制背景的话只能通过重载QStyledItemDelegate里面的paint函数进行选中行的背景绘制。
  2. 捕捉当前鼠标悬浮的信号
    在获取鼠标hover的信号的过程中遇到了一些问题。一开始希望通过QStyledItemDelegate里面的editorEvent,捕获里面event的动作获取悬浮信号。
bool CRoomMemDelegate::editorEvent(QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index)
	if (event->type() == QEvent::MouseMove)//鼠标移动事件
	    m_selectionRow = index.row();
	else if(event->type() == QEvent::leave)//离开事件
	     m_selectionRow = -1;
	return false;

如上尝试了通过m_selectionRow 保存当前悬停的行,然后在paint函数里面进行绘制背景。不过调试中发现mousemove动作可以捕获的到,但是leave事件得不到。所以会导致无论如何都会有一行被选中。

为了能够捕捉到鼠标的事件,子类话了QTableview,然后通过信号告诉QStyledItemDelegate鼠标的move/leave的动作。这个信号把悬停的当前行的信息发送出去。QStyledItemDelegate获取到hoving的行,保存当前行的信息并触发paint的动作进行绘制。具体的操作代码如下:

//1: Tableview :
void TableView::mouseMoveEvent(QMouseEvent *event)
    QModelIndex index = indexAt(event->pos());
    emit hoverIndexChanged(index);
//2.connect signal and slot
    connect(this,SIGNAL(hoverIndexChanged(const QModelIndex&)),delegate_,SLOT(onHoverIndexChanged(const QModelIndex&)));
//3.onHoverIndexChanged
void TableViewDelegate::onHoverIndexChanged(const QModelIndex& index)
    hoverrow_ = index.row();
//4.in Delegate paint():
void TableViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    if(index.row() == hoverrow_)
        //HERE IS HOVER COLOR
        painter->fillRect(option.rect, kHoverItemBackgroundcColor);
        painter->fillRect(option.rect, kItemBackgroundColor);

上面的代码少了一个步骤就是触发paint绘制的动作,这个可以调用model里面的dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = …)函数刷新对应行的信息。

1、How to highlight the entire row on mouse hover in QTableWidget: Qt5
2、QTableView How can I highlight the entire row for mouse hover?

//setMouseTracking(true); this->setAttribute(Qt::WA_Hover, true);//开启悬停事件 this->installEventFilter(this); /. ​ Qt style sheet, 简写就是qss, Qt样式表,不需要用C++代码控件进重载,就可以修改控件外观,美化界面,类似于前端的css, 但是没有css功能强大.​ 例如下面QLabel的样式设置除了以上样式外,还有很多,qss千变万化,可以写出各种花里胡哨的样式。 1、要想实现mouseMoveEvent,则需要在构造函数中添加setMouseTrack(true),直接得到监听事件。若是setMouseTrack(false),只有鼠标按下才会有mouseMove监听事件响应。 2、使用setMouseTracking(true)对鼠标监控(mouseMoveEvent(QMouseEvent *event)),如果WidgetA有个子窗体WidgetB会占据WidgetA的绝大部分空间,那么当鼠标移动到WidgetB上时,WidgetA就会失去对鼠标的监控。 QTableView/QTableWidget 实现hover效果 在网上看到一些实现这个效果都是通过鼠标事件判断悬浮在哪一实现的,这里提供另一种思路。 在Qt的模型/视图/代理框架里面,关于item的绘制是交给代理实现的,默认的QStyledItemDelegate的paint会去调用 virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const; 这个虚函数,初始化一些 通过效果图可以看到,当某一个item处于选中但不活跃状态就没法出现hover的样式了。2023/1/8日更新,首先当item处于。状态的item及那一的每一个item进绘制即可。这样的好处时可以通过stylesheet来控制。时就是选中但不活跃的状态,此时我们的鼠标在移动到item上面那么它的状态为。所以我们只要想办法去掉。状态同时出现时会优先展示。但是它展示出来的还是。 QHoverEvent类包含描述鼠标事件的参数。 当鼠标光标移入,移出窗口小部件或在窗口小部件内时,并且窗口小部件具有Qt :: WA_Hover属性,就会发生鼠标事件。 函数pos()给出当前光标位置,而oldPos()给出旧鼠标位置。 事件QEvent :: HoverEnter和QEvent :: HoverLeave与事件QEvent :: Enter和QEvent :: Leave之间有一些相似之处。 但是,它们略有不同,因为我们在HoverEnter和HoverLeave的事件处理程序