【问题标题】:Qt adding child widget in resizeEventQt在resizeEvent中添加子小部件
【发布时间】:2016-06-26 15:26:20
【问题描述】:

我有一个从QFrame 派生的小部件W,其布局设置为QVBoxLayout 的实例。我想知道下面的resizeEvent 实现是正确的还是会导致无限循环:

void W::resizeEvent(QResizeEvent *event) {
    for (/* some condition based on the new size of this widget */) {
        // Infinite loop or not?
        qobject_cast<QVBoxLayout *>(layout())->addWidget(new QWidget());
    }
}

到目前为止它对我有用,这纯粹是运气吗?

【问题讨论】:

  • 视情况而定。你能展示一下吗?如果您使用event-&gt;size(),它将保持事件的大小。但是任何小部件插入都可能在函数返回后导致新的调整大小事件。
  • @vsz 你的赏金改变了问题太多。最初的问题是通过在 resizeEvent 中调用 resize 操作来实现可能的无限循环。 OP从未提及绘画/绘画与调整大小之间的关系。当前答案对于原始问题来说很好。我建议为您的问题创建一个新问题。

标签: c++ qt


【解决方案1】:

这没关系。 W 拥有一个 QLayout,它拥有 QWidget。将QWidget 添加到QLayout 不会更改W 的大小。你总是看到这个。例如,如果您将一个子小部件放在父级中,而父级太小,则子小部件将被剪裁。完全不同的是,父母的大小并不能适应孩子的大小。我相信您的代码将是基于父级大小(例如,当窗口大小发生变化时)隐藏或显示小部件的典型方式。

【讨论】:

  • 我猜这个问题被问到了(就像我搜索它一样),因为 manualresizeEvent() 表示“不需要(或不应该)在这个处理程序内完成绘图。 "这是否意味着应该避免只使用QPainter 样式的绘图,添加/删除小部件就可以了?
  • 类似的问题是子小部件的重新排列,例如,在布局上使用setRowStretch()。它们也不应该影响父母的几何形状。
【解决方案2】:

绘制和构建小部件的层次结构是两件不同的事情。所以,添加QWidgets 就可以了,但不能直接在resizeEvent 中使用QPainter

QWidgets 的层次结构

QWidgets 派生的层次结构(QLineEditQPushButton、...)是图形用户界面外观的高级规范,可以使用 QLayout 项目进行排序。

绘画

绘画(使用QPainter)是在屏幕上实际绘制某些东西的过程,纯粹在虚函数QWidget::paintEvent中完成。 QWidget 的每个衍生物都应该提供这个空基函数的实现。默认派生类 (QLineEdit, ...) 基于其当前状态(小部件的大小、QLineEdit 的当前文本、...)和当前 QStyle 对象提供了 paintEvent 的实现,通常会根据您的操作系统自动设置,但可以使用QWidget::setStyleQApplication::setStyle 以编程方式更改。可以使用QWidget::update 请求重绘。

“不应该/不需要”与“可能不”

句子“不需要(或不应该)在此处理程序内完成绘图。”是为实现自定义 QWidget(使用新的 paintEvent 实现)的人制作的很明显你不应该在这里实现你的绘画,但是paintEvent会被自动触发。

"Should not/need not" 是一些建议,他们不会写“可能不会”。因此,如果您出于某种原因(例如实时应用程序)想要立即刷新屏幕,您可以使用 repaint 立即调用重绘,从而在 resizeEvent 期间调用 paintEvent。只要QWidget 上的所有QPainter 操作都在paintEvent 内(根据warning in the QPainter documentation 的要求),一切都很好。

【讨论】:

    【解决方案3】:

    resizeEvent 函数中使用addWidget 向布局添加小部件不是问题,因为它不会立即触发绘图。

    您可以通过编译和执行这个简单的项目来轻松验证这一点:

    dialog.h:

    #pragma once
    #include <QDialog>
    
    class Dialog : public QDialog
    {
        Q_OBJECT
    
    public:
        Dialog(QWidget *parent = 0);
        ~Dialog();
    
        void resizeEvent(QResizeEvent *event);
        void paintEvent(QPaintEvent *event);
    
    private:
        bool resizing;
    };
    

    dialog.cpp:

    #include "dialog.h"
    
    #include <QResizeEvent>
    #include <QVBoxLayout>
    #include <QPushButton>
    #include <QDebug>
    
    Dialog::Dialog(QWidget *parent)
        : QDialog(parent),
          resizing(false)
    {
        new QVBoxLayout(this);
    }
    
    Dialog::~Dialog()
    {
    
    }
    
    void Dialog::resizeEvent(QResizeEvent *event)
    {
        resizing = true;
    
        if ( event->size().width() == event->size().height() )
        {
            qDebug() << "Adding widget";
            // Infinite loop or not?
            layout()->addWidget(new QPushButton());
        }
    
        resizing = false;
    }
    
    void Dialog::paintEvent(QPaintEvent *event)
    {
        if ( resizing )
        {
            qDebug() << "Painting while resizing widget";
        }
    }
    

    ma​​in.cpp:

    #include "dialog.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Dialog w;
        w.show();
    
        return a.exec();
    }
    

    当您运行程序时,调整对话框的大小以使其为方形(宽度==高度),插入一些按钮(“添加小部件”打印到控制台),但您永远不会看到“调整大小时绘画小部件”消息。这很可能是因为addWidget 设置了一个脏显示标志,该标志稍后由框架处理。它使显示无效,但不会立即重新绘制。

    所以你所做的很好,并且不违反框架要求(“不需要(或应该)在这个处理程序内完成绘图。”)。

    但是,如果您不确定(也许绘画可以立即在不同的操作系统上操作,或者在未来的 Qt 版本中......您无法确定),您也可以通过发出信号来延迟插入使用Qt::QueuedConnection 连接到一个槽,这个槽将“稍后”执行,然后调用addWidget,保证它在resizeEvent 函数之外完成。

    【讨论】:

    • 在我看来,您使用Qt::QueuedConnection 的解决方案是对文档的误解。这句话适用于实现自定义 QWidget(新实现 paintEvent)的人,以明确您不应该在这里实现您的绘画,但 paintEvent 将被自动触发。
    • "Should not/need not" 是一些建议,他们不写“可能不会”。因此,如果您出于某种原因(例如实时应用程序)想要立即刷新屏幕,您可以使用repaint 立即调用重绘,从而在resizeEvent 期间调用paintEvent
    • 使用Qt::QueuedConnection 不是一个“解决方案”,它只是一种建议的方法,以确保您不会在resizeEvent 范围内做任何有趣的事情。
    • 重点是,如果 Qt(或您自己)调用 repaint(立即触发 paintEvent)并不重要。只要QWidget 上的所有QPainter 操作都在paintEvent 内(根据the warning in the QPainter documentation 的要求),一切都很好。因此,即使您的示例测试 paintEvent 是否未在 resizeEvent 内被调用,也与我无关。
    • 你能澄清一下我的意思是否正确吗?您是说““不需要(或不应该)在此处理程序中完成绘图。”仅表示不应在 resizeEvent 内创建 QPainter,而是从此处调用 paintEvent,它本身会创建 QPainter可以吗?
    猜你喜欢
    • 2017-08-22
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-25
    • 2016-07-10
    相关资源
    最近更新 更多