我认为原因是您没有在小部件上启用鼠标跟踪,因此无法通知父菜单鼠标光标更改其位置。
我建议添加到你的构造函数中MyWidget
类这一行:
setMousetracking(true);
Edit #1:
我发现了一个丑陋的技巧,但它似乎有效:
// You WidgetAction class
class MyWidgetAction : public QWidgetAction
{
public:
MyWidgetAction(QObject *parent = nullptr);
QWidget* createWidget(QWidget* parent) override {
w = new MyWidget(parent);
return w;
}
void highlight(bool hl) { w->set_highlighted(hl); }
private:
MyWidget *w;
};
// In your code
QMenu *menu = ui->menuBar->addMenu("The Menu");
menu->addAction("Standard QAction 1");
menu->addAction("Standard QAction 2");
menu->addMenu("submenu")->addAction("subaction1");
QWidgetAction *a = new MyWidgetAction();
a->setText("My action 1");
a->setParent(menu); // Needed for the trick
menu->addAction(a);
menu->addAction("Standard QAction 3");
menu->addAction("Standard QAction 4");
// The ugly trick
connect(menu, &QMenu::hovered, this, [menu](QAction *act){
QList<MyWidgetAction*> lCustomActions = menu->findChildren<MyWidgetAction*>();
for (MyWidgetAction *mwa : lCustomActions){
mwa->highlight(mwa == act);
}
});
我看到hovered
信号始终正确发送,因此我将其连接到 lambda 以检查每个自定义WidgetAction
如果它是当前悬停的项目并在这种情况下手动突出显示。
Edit #2:
为了避免在我的第一次编辑中 lambda 中出现 for 循环,您还可以创建一个事件过滤器来管理鼠标移动时的突出显示:
class WidgetActionFilterObject : public QObject
{
Q_OBJECT
public:
explicit WidgetActionFilterObject(QObject *parent = nullptr);
protected:
bool eventFilter(QObject *obj, QEvent *evt) override {
if (evt->type() == QEvent::Type::MouseMove){
QMouseEvent *mouse_evt = static_cast<QMouseEvent*>(evt);
QAction *a = static_cast<QMenu*>(obj)->actionAt(mouse_evt->pos());
MyWidgetAction *mwa = dynamic_cast<MyWidgetAction*>(a);
if (mwa){
if (last_wa && mwa != last_wa){
last_wa->highlight(false);
}
mwa->highlight(true);
last_wa = mwa;
} else {
if (last_wa){
last_wa->highlight(false);
last_wa = nullptr;
}
}
}
return QObject::eventFilter(obj, evt);
}
private:
MyWidgetAction *last_wa = nullptr;
};
然后你唯一要做的就是安装一个事件过滤器 https://doc.qt.io/qt-5/eventsandfilters.html#event-filters在包含您的自定义的每个菜单上WidgetAction
:
menu->installEventFilter(new WidgetActionFilterObject(this));
并且您将获得相同的结果,而无需在每个上循环hovered
signal.