QMenu 中的 TriState QAction
TriState QAction in QMenu
我需要一个可检查的 QAction
,它除了已检查和未检查的模式外,还具有部分检查的选项。这基本上已经是 QCheckBox 提供的,但不幸的是,QAction 没有提供。
作为第一次尝试,我通过实现自定义 QWidgetAction
.
提出了以下方法
TriState.h
#pragma once
#include <QWidgetAction>
#include <QCheckBox>
#include <QLabel>
#include <QFrame>
#include <QHBoxLayout>
class TriStateAction : public QWidgetAction {
Q_OBJECT
public:
TriStateAction(QWidget* parent=nullptr) : QWidgetAction(parent) {
mChkBox = new QCheckBox;
mChkBox->setTristate(true);
auto widget = new QFrame;
widget->setLayout(new QHBoxLayout);
widget->layout()->addWidget(mChkBox);
widget->layout()->addWidget(new QLabel("TriState"));
setDefaultWidget(widget);
connect(mChkBox, &QCheckBox::stateChanged, this, &QWidgetAction::changed);
}
void setCheckState(Qt::CheckState checkState) {
mChkBox->setCheckState(checkState);
}
Qt::CheckState checkState() const {
return mChkBox->checkState();
}
private:
QCheckBox* mChkBox{ nullptr };
};
有了这个简单的 TestRunner:
main.cpp
#include <QApplication>
#include <QMenu>
#include <QAction>
#include "TriStateAction.h"
int main(int argc, char** args) {
QApplication app(argc, args);
auto label=new QLabel("Test");
label->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
label->connect(label, &QLabel::customContextMenuRequested, [&](const QPoint& point) {
QMenu menu(label);
auto globalPoint = label->mapToGlobal(point);
auto triStateAction = new TriStateAction();
auto normalAction = new QAction("Check");
normalAction->setCheckable(true);
normalAction->setChecked(true);
menu.addAction(triStateAction);
menu.addAction(normalAction);
menu.exec(globalPoint);
});
label->show();
app.exec();
}
现在,上下文菜单弹出,我可以愉快地选中、取消选中和部分选中我的 TriState Action。但是,与普通的 QAction 不同,TriState 不会在交互时关闭菜单。这可怎么办?
另一个问题是我的 TriState Action 的不同布局(视觉表示)。与普通的 QAction 相比,如何让它更相似? (实际上,这似乎是一个非常难的问题。)
让 action 知道它的菜单,在你的 main
:
中添加这一行
triStateAction->setMenu(&menu);
在 TriStateAction
class 中,添加一个插槽来捕获复选框 stateChanged
信号,然后从那里关闭菜单:
private slots:
void checkBoxStateChanged(int)
{
if (menu() != nullptr)
{
menu()->close();
}
}
别忘了连接插槽,在TriStateAction
构造函数中:
connect(mChkBox, &QCheckBox::stateChanged, this, &TriStateAction::checkBoxStateChanged);
我需要一个可检查的 QAction
,它除了已检查和未检查的模式外,还具有部分检查的选项。这基本上已经是 QCheckBox 提供的,但不幸的是,QAction 没有提供。
作为第一次尝试,我通过实现自定义 QWidgetAction
.
TriState.h
#pragma once
#include <QWidgetAction>
#include <QCheckBox>
#include <QLabel>
#include <QFrame>
#include <QHBoxLayout>
class TriStateAction : public QWidgetAction {
Q_OBJECT
public:
TriStateAction(QWidget* parent=nullptr) : QWidgetAction(parent) {
mChkBox = new QCheckBox;
mChkBox->setTristate(true);
auto widget = new QFrame;
widget->setLayout(new QHBoxLayout);
widget->layout()->addWidget(mChkBox);
widget->layout()->addWidget(new QLabel("TriState"));
setDefaultWidget(widget);
connect(mChkBox, &QCheckBox::stateChanged, this, &QWidgetAction::changed);
}
void setCheckState(Qt::CheckState checkState) {
mChkBox->setCheckState(checkState);
}
Qt::CheckState checkState() const {
return mChkBox->checkState();
}
private:
QCheckBox* mChkBox{ nullptr };
};
有了这个简单的 TestRunner:
main.cpp
#include <QApplication>
#include <QMenu>
#include <QAction>
#include "TriStateAction.h"
int main(int argc, char** args) {
QApplication app(argc, args);
auto label=new QLabel("Test");
label->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
label->connect(label, &QLabel::customContextMenuRequested, [&](const QPoint& point) {
QMenu menu(label);
auto globalPoint = label->mapToGlobal(point);
auto triStateAction = new TriStateAction();
auto normalAction = new QAction("Check");
normalAction->setCheckable(true);
normalAction->setChecked(true);
menu.addAction(triStateAction);
menu.addAction(normalAction);
menu.exec(globalPoint);
});
label->show();
app.exec();
}
现在,上下文菜单弹出,我可以愉快地选中、取消选中和部分选中我的 TriState Action。但是,与普通的 QAction 不同,TriState 不会在交互时关闭菜单。这可怎么办?
另一个问题是我的 TriState Action 的不同布局(视觉表示)。与普通的 QAction 相比,如何让它更相似? (实际上,这似乎是一个非常难的问题。)
让 action 知道它的菜单,在你的 main
:
triStateAction->setMenu(&menu);
在 TriStateAction
class 中,添加一个插槽来捕获复选框 stateChanged
信号,然后从那里关闭菜单:
private slots:
void checkBoxStateChanged(int)
{
if (menu() != nullptr)
{
menu()->close();
}
}
别忘了连接插槽,在TriStateAction
构造函数中:
connect(mChkBox, &QCheckBox::stateChanged, this, &TriStateAction::checkBoxStateChanged);