TriState QAction в QMenu - PullRequest
       44

TriState QAction в QMenu

0 голосов
/ 17 декабря 2018

Мне нужен проверяемый 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.Но, в отличие от обычного QAction, TriState не закроет меню при взаимодействии.Как это можно сделать?

Другая проблема - это другое расположение (визуальное представление) моего действия TriState.Как это можно сделать более похожим по сравнению с обычным QAction?(На самом деле, это кажется очень сложным вопросом.)

1 Ответ

0 голосов
/ 17 декабря 2018

Пусть действие знает свое меню, добавив эту строку в ваш main:

triStateAction->setMenu(&menu);

В TriStateAction классе, добавьте слот, чтобы поймать флажок stateChanged сигнал, и закройте меню оттуда:

private slots:
    void checkBoxStateChanged(int)
    {
        if (menu() != nullptr)
        {
            menu()->close();
        }
    }

Не забудьте подключить слот, в TriStateAction конструктор:

connect(mChkBox, &QCheckBox::stateChanged, this, &TriStateAction::checkBoxStateChanged);
...