当鼠标悬停在QPushButton上时,如何发出信号?

11

最近,我想让 QPushButton 在鼠标指针进入时发射一个信号。我该怎么办?

我知道 QPushButton 已经有一些预定义的信号,例如 clicked(), pressed(), destroy() 等等。但是没有像 hover()、enter() 这样的信号。

我查看了一些相关信息:有人说这可以通过 CSS 完成。但我不理解。你能给我一些建议吗?谢谢!


如果您可以解释当鼠标悬停时想要做什么,那么拦截此类事件可能就不是必要的。例如,如果您想要更改按钮的外观,可以使用样式表来实现。 - Arnold Spence
谢谢。我想要这样做:如果有两个组件,当鼠标指针悬停在其中一个上时,另一个将不可见... - Mr.Tu
1
好的,既然您想根据鼠标与另一个按钮的交互来影响一个按钮,那么您确实需要拦截此事件。 - Arnold Spence
5个回答

14

虽然@Exa已经回答了这个问题,但我想展示另一个解决方案,它不需要子类化QPushButton,并且在使用时非常灵活!(这正是我在我的项目中所需要的)

步骤1/2:重写eventFilter.

LoginWindow.h:

// LoginWindow is where you placed your QPushButton 
//(= most probably your application windows)

class LoginWindow: public QWidget
{
public:
      bool eventFilter(QObject *obj, QEvent *event);
..
};

LoginWindow.cpp:

bool LoginWindow::eventFilter(QObject *obj, QEvent *event)
{
    // This function repeatedly call for those QObjects
    // which have installed eventFilter (Step 2)

    if (obj == (QObject*)targetPushButton) {
        if (event->type() == QEvent::Enter)
        {
        // Whatever you want to do when mouse goes over targetPushButton
        }
        return true;
    }else {
        // pass the event on to the parent class
        return QWidget::eventFilter(obj, event);
    }
}

步骤2/2:在目标小部件上安装eventFilter。

LoginWindow::LoginWindow()
{
    ...
    targetPushButton->installEventFilter(this);
    ...
}

这是一个非常好的答案。但出于某种奇怪的原因,当我在QToolButton上应用此逻辑(用于在悬停时显示一些自定义文本弹出窗口)时,按钮变得不可见,尽管在它应该存在的位置悬停会正常显示弹出窗口,甚至光标也会像预期的那样变成指针,因为我已经为按钮设置了这样的属性! - SexyBeast
太好了!我不想为每个我想检测悬停事件的小部件创建一个新类! - BuvinJ
3
我想我找到了原因。在“eventFilter”函数中,不要使用“return true”,而是使用“return QWidget::eventFilter(obj, event);”。同时也不需要else条件语句。我这样做后,按钮消失的情况就解决了。 - Volomike
几天前找到了它.. :) - SexyBeast
@Volomike 感谢您的回复!如果没有添加它,那么PushButton的整个逻辑就没有意义了! - mrg95
感谢 @Volomike 修复了消失的问题。 - PaddleStroke

11

你可以使用QWidget::enterEvent(QEvent *event)实现此功能。

当该事件发生时,你可以重写此事件并发送自定义的信号。

首先,你需要为此小部件启用鼠标跟踪(例如,在构造函数中使用setMouseTracking(true))。

头文件:

class my_button
{
    // ...

protected:
    virtual void enterEvent( QEvent* e );

public Q_SIGNALS:
    void hovered();

    // ...
};

源文件:

void my_button::enterEvent( QEvent* e )
{
    Q_EMIT hovered();

    // don't forget to forward the event
    QWidget::enterEvent( e );
}

您使用按钮的位置:

connect( one_of_my_button, SIGNAL(hovered()), this, SLOT(do_something_when_button_hovered()) );

首先,谢谢。我认为这有点复杂,因为我只使用了一个这样的按钮,还有其他方法吗? - Mr.Tu

3
请确保在public关键字后添加“:”。
public: Q_SIGNALS:
    void hovered();

1

如果我没记错的话,您需要为按钮启用鼠标跟踪(Qt文档),并重写QWidget::onEnter()QWidget::onLeave()方法。

您需要创建一个自定义按钮类,继承自QPushButton。您可以在自定义类中定义mouseEnter和mouseLeave信号,并从您需要重写的onEnter()onLeave()方法中发出它们。


1
是的,你必须在你的自定义按钮类中实现onEnter()和onLeave()函数。请参考@Exa的答案获取代码示例。附言:如果您发现答案有用,请点赞。 - Dirk

1
QT使用"event" enterEvent处理鼠标悬停(请参阅https://doc.qt.io/qt-5/qevent.html中的“QEvent::Enter”)。这不涉及信号/槽功能(请参阅https://doc.qt.io/qt-5/signalsandslots.html),而是涉及事件(请参阅https://doc.qt.io/qt-5/eventsandfilters.html)。 我们在QWidget类(https://doc.qt.io/qt-5/qwidget.html)中找到enterEvent作为受保护的方法,该类是QPushButton类(https://doc.qt.io/qt-5/qpushbutton.html)的基类。 因此,您需要做的是:创建一个从QPushButton派生的新类,并覆盖QPushButton从QWidget继承的受保护方法"enterEvent"。

创建新类:
QT Creator - 文件 - 新建文件或项目...
文件和类 - C++
C++ 类
选择...
基类 - 自定义 - QPushButton
下一步
为您的新类定义一个名称,例如 MyPushButton

在 mypushbutton.h 中:

#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H

#include <QPushButton>

class MyPushButton: public QPushButton
{
    Q_OBJECT
public:
    using QPushButton::QPushButton;  //inherits the QPushButton constructors

signals:
    void myPushButtonMouseHover();

protected:
    void enterEvent(QEvent *event);
};

#endif // MYPUSHBUTTON_H

在我的 pushbutton.cpp 文件中:
#include "mypushbutton.h"
#include <QMessageBox>

void MyPushButton::enterEvent(QEvent *event)
{
    QMessageBox::warning(this, "Mouse hover", "Mouse hovered MyPushButton"); //popping a message box

    emit myPushButtonMouseHover();  //emitting signal 

    QPushButton::QWidget::enterEvent(event);  //calling the "natural" enterEvent

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接