【问题标题】:Qt event filter hides the widgetQt 事件过滤器隐藏小部件
【发布时间】:2015-04-06 08:27:20
【问题描述】:

我有一个父小部件,我必须在其中放置一个自定义小部件(比如QFrame)。在该自定义小部件内,我必须放置一些子小部件(源自QPushButton)。我希望子小部件在正常情况下具有一定的背景,并且在悬停时具有另一个背景。这是我的代码:

//parent widget code, where the QFrame derived widget is initialized
QFrameDerivedWidget *qFrameWidget = new QFrameDerivedWidget(this, someString);

这是QFrameDerivedWidget 头文件:

//QFrameDerivedWidget header file
class QFrameDerivedWidget: public QFrame
{
    Q_OBJECT

public:
    QFrameDerivedWidget(QWidget *aParent,
                         std::string someValue);
    bool eventFilter(QObject *obj, QEvent *event);
}

这是QFrameDerivedWidget的实现文件,ChildWidget类是内联定义和声明的:

class ChildWidget: public QPushButton
{
Q_Object
public:
    ChildWidget(std::string aText, QWidget *aParent);

};

ChildWidget::ChildWidget(std::string aText, QWidget *aParent):
                               QPushButton(QString::fromStdString(aText),aParent)
{
    this->setFixedHeight(30);
    this->setMouseTracking(true);
    this->setCursor(Qt::PointingHandCursor);
    /* ---other custom styling--- */
}

bool QFrameDerivedWidget::eventFilter(QObject *obj, QEvent *event)
{
    // this never prints out anything, even though it should for any mouseenter, mouseleave, click, etc event on it
    qDebug() << obj->metaObject()->className() << endl;

    if (obj->metaObject()->className() == "ChildWidget")
    {
        //including this line throws a 'missing QObject missing macro error' as well
        ChildWidget *option = qobject_cast<ChildWidget* >(obj);
        if (event->type() == QEvent::Enter)
        {
            option->setStyleSheet("---");

        }
        if (event->type() == QEvent::Leave)
        {
            option->setStyleSheet("---");
        }
        return QWidget::eventFilter(obj, event);
    }
    else
    {
        // pass the event on to the parent class
        return QWidget::eventFilter(obj, event);
    }
}

QFrameDerivedWidget::QFrameDerivedWidget(QWidget *aParent,
                     std::string someVal): fParent(aParent)
{
    initUI();
}

QFrameDerivedWidget::initUI()
{
    this->setParent(fParent);
    this->setAttribute(Qt::WA_Hover);
    this->setMouseTracking(true);
    QWidget *dd = new QWidget(this);
    QVBoxLayout *layout = new QVBoxLayout();
    dd->setLayout(layout);
    for (int i = 0; i < fValues.size(); i++)
    {
        ChildWidget *button = new ChildWidget(fValues[i],dd);
        button->addEventFilter(this);
        layout->addWidget(button);
    }
}

这个想法是,每当我将鼠标悬停在QFrameDerivedWidget 上并输入任何ChildWidget 时,它的背景颜色都应该改变。此外,我在eventFilter 中设置了qDebug() 语句。它目前不起作用,ChildWidget 按钮不可见,但它们在那里,因为当我将鼠标悬停在它们应该在的位置时,光标会变成指针。

我做错了什么,我该如何让它发挥作用?

【问题讨论】:

  • obj-&gt;metaObject()-&gt;className() == "ChildWidget" 可以替换为qobject_cast&lt;ChildWidget *&gt;(obj) != nullptr

标签: c++ qt qwidget qobject


【解决方案1】:
  1. 您忘记在ChildWidget 声明中添加Q_OBJECT
  2. 您需要跟踪鼠标 (setMouseTracking(true))
  3. 您需要将setAttribute(Qt::WA_Hover) 设置为您的小部件
  4. 请确保您确实需要在事件过滤器中使用return true;,而不是返回QWidget::eventFilter(obj, event);。您无需过滤掉悬停事件。

【讨论】:

  • ChildWidget 已经派生自 QPushButton,其中包含内置宏。为什么我需要再做一次?我试过这样做,我仍然得到错误..
  • @Cupidvogel 你可以阅读关于Q_OBJECT 宏的Qt 文档。而且我认为您没有错误,而是警告。如果没有 SSCCE,我无法帮助您。
  • 当然。如果您提供完整的标题 + 显示代码,您将如何安装事件过滤器,那就太好了。
  • 好吧,我将ChildWidget 的内联定义移动到一个新的类和实现文件中,添加了QObject 宏,并将ChildWidgetQFrameDerivedWidget 的鼠标跟踪设置为true。尽管QObject macro needed 错误不会出现,但它仍然无法正常工作。但是悬停事件颜色变化,或者应该适用于任何事件的正常 qDebug() 不起作用。
  • 我忘了一件事,我现在在 for 循环中添加了button-&gt;installEventFilter(this),我一举创建了ChildWidget 按钮。现在的问题是按钮根本不可见。当我将鼠标悬停在应该是ChildWidget 按钮的QFrameDerivedWidget 上时,我看到光标转动指针(我为它们使用了setCursor(Qt::PointingHandCursor),但按钮不可见。我之前在另一个场景中遇到过这个问题也是。我该如何解决这个问题?