【问题标题】:How to set visibility on widgets within a subclass of QWidgetAction如何在 QWidgetAction 的子类中设置小部件的可见性
【发布时间】:2018-06-27 05:57:43
【问题描述】:

Qt 5.6.3,eglfs Linux 平台。

我有一些从 QWidgetAction 派生的类。 QWidgetActions 都来自一个菜单,并且它们包含的小部件来自同一个菜单。包含的小部件都设置为 QWidgetAction 的默认小部件。 QWidgetAction 没有重新实现任何内容。

我认为设置 QWidgetAction 的可见性会自动设置其中包含的自定义小部件集的可见性?这不是真的吗,因为这样做肯定不会按要求显示和隐藏小部件!?我必须做其他事情才能将可见性更改传递给包含的小部件吗?我必须直接从 QWidgetAction 请求小部件,然后直接对其应用可见性(这似乎是 hack)吗?

我对 QWidgetAction 应该如何实现感兴趣。文档几乎不存在,所以我尽可能多地了解人们对它们的体验。我遇到了一些看起来像是自定义小部件的双重删除和可见性不正常的问题。

class Base : public QWidgetAction
{
    Q_OBJECT
public:
    explicit Base(QWidget* parent, QString labelText = "", QString iconPath = "", Qt::AlignmentFlag alignment = Qt::AlignHCenter) :
    QWidgetAction(parent),
    mCustomWidget(nullptr),
    mParentWidget(nullptr),
    mTextLabel(nullptr),
    mAlignment(alignment),
    mLabelText(labelText),
    mIconPath(iconPath) {}

    virtual ~Base() {}

protected:
    QWidget *mCustomWidget;

    QWidget *createTheWidgetSet(QWidget *parent)
    {
        if (mParentWidget == nullptr) {
            mParentWidget = new QWidget(parent);
            mCustomWidget = createCustomWidget(mParentWidget);

            if (mCustomWidget != nullptr) {
                if (!mLabelText.isEmpty()) {
                    mCustomWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
                }
            }

            int rightMargin = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);

            QBoxLayout* layout = new QBoxLayout(QBoxLayout::LeftToRight, mParentWidget);
            layout->setContentsMargins(1, 2, rightMargin, 2);
            if (!mLabelText.isEmpty()) {
                QString some_calced_text{};
                mTextLabel = new QLabel(some_calced_text, mParentWidget);
                layout->addWidget(mTextLabel);
            } else {
                if(mAlignment == Qt::AlignLeft){
                    int some_calced_val{20};
                    layout->addSpacing(some_calced_val);
                }
            }

            if(mAlignment == Qt::AlignRight){
                layout->addStretch();
            }

            layout->addWidget(mCustomWidget);

            if(mAlignment == Qt::AlignLeft){
                layout->addStretch();
            }
        }

        setDefaultWidget(mParentWidget);

        return mCustomWidget;
    }

    virtual QWidget *createCustomWidget(QWidget *parent) = 0;

private:
    Q_DISABLE_COPY(Base)

    QWidget *mParentWidget;
    QLabel  *mTextLabel;
    Qt::AlignmentFlag mAlignment;
    QString mLabelText;
    QString mIconPath;
};

class SpinBoxActionWidget : public Base
{
    Q_OBJECT
    public:
        explicit SpinBoxActionWidget(QWidget* parent, QString labelText = "", QString iconPath = "") :
            Base(parent, labelText, iconPath),
            mSpinBox(nullptr)
        {
                createTheWidgetSet(parent);
        }

        virtual ~SpinBoxActionWidget() {}

        QSpinBox* getSpinBox() const
        {
            return mSpinBox;
        }

    protected:
        QWidget *createCustomWidget(QWidget *parent) override
        {
            if (mSpinBox == nullptr) {
                mSpinBox = new QSpinBox(parent);
                mSpinBox->setFixedHeight(22);
            }

            return mSpinBox;
        }

    private:
        Q_DISABLE_COPY(SpinBoxActionWidget)

        QSpinBox *mSpinBox;
};

/* Elsewhere in code.... */
{
    QMenu theMenu = new QMenu(parentWindow);
    SpinBoxActionWidget theAct = new SpinBoxActionWidget(theMenu);
    SpinBoxActionWidget theSecondAct = new SpinBoxActionWidget(theMenu);

    theMenu->addAction(theAct);
    theMenu->addAction(theSecondAct);

    /* I now assume that I can do this, and the entire entry in the menu
     * represented by "theAct" can be made visible and invisible.
     * This doesn't work however, either the widget remains visible,
     * or is partially hidden.
    theAct->setVisible(true);
    theAct->setVisible(false);
    */
}

【问题讨论】:

  • 添加了代码。我对 QWidgetActions 应该如何实现更感兴趣。文档几乎不存在,所以我尽可能多地关注人们对它们的体验。
  • 不常用QWidgetAction。但是,据我了解,操作小部件不是呈现给用户的;相反,action_widget->createWidget(parent) 的结果被添加到容器中,并且是您应该调用 setVisible 的小部件,尽管我可能错了。
  • @Synxis 这当然是我看到的行为,尽管不是我所期望的。由于一切都以动作为基础,我认为在动作上设置可见性是正确的做事方式。
  • 创建的小部件是否重新设置了父级?无论如何,由于QWidgetAction 派生自QAction,它不是一个小部件,因此可见性不是一个可行的概念。
  • 我认为这可能是我忽略的关键信息!

标签: c++ qt


【解决方案1】:

您没有重新实现接口,这就是它不起作用的原因。

首先,请注意QWidgetAction 派生自QAction,这不是 QWidget;但是,它确实有一个 setVisible() 函数,它实际上只是将调用转发到由该操作创建的所有小部件。

您必须重新实现QWidgetAction::createWidget(parent) 才能添加新的小部件;你的createCustomWidget 没有做任何有用的事情。这是一个非常简单的例子:

class SpinAction : public QWidgetAction
{
    Q_OBJECT
public:
    SpinAction(QObject* parent) : QWidgetAction(parent) {}
    virtual ~SpinAction() {}
    QWidget* createWidget(QWidget* parent) { return new QSpinBox(parent); }
 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 // reimplement this function
};

您可以将您的操作添加到您想要的任何容器、菜单、工具栏等...此示例将为每个容器创建一个新小部件,这些创建的小部件不会同步(例如在 spinbox 值上)。

我刚刚在主窗口中对其进行了测试,在菜单和工具栏中添加了一个小部件操作,并且调用 setVisible() 可以完美运行。

【讨论】:

    猜你喜欢
    • 2013-07-19
    • 2020-06-12
    • 2023-03-06
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 1970-01-01
    相关资源
    最近更新 更多