如何在不更改其他Qt小部件位置的情况下使Qt小部件不可见? [英] How to make a Qt widget invisible without changing the position of the other Qt widgets?

查看:84
本文介绍了如何在不更改其他Qt小部件位置的情况下使Qt小部件不可见?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个充满QPushButtons和QLabels以及其他有趣的QWidgets的窗口,它们都使用各种QLayout对象动态地进行了布局...我想做的是偶尔使其中的一些小部件变得不可见.也就是说,不可见的窗口小部件仍将占据窗口布局中的正常空间,但不会被渲染:相反,用户只能在窗口小部件的矩形/区域中看到窗口的背景颜色.

I've got a window full of QPushButtons and QLabels and various other fun QWidgets, all layed out dynamically using various QLayout objects... and what I'd like to do is occasionally make some of those widgets become invisible. That is, the invisible widgets would still take up their normal space in the window's layout, but they wouldn't be rendered: instead, the user would just see the window's background color in the widget's rectangle/area.

hide()和/或setVisible(false)不会解决问题,因为它们会导致将窗口小部件完全从布局中删除,从而允许其他窗口小部件进行扩展以占据新近可用"的空间;我想避免的效果.

hide() and/or setVisible(false) won't do the trick because they cause the widget to be removed from the layout entirely, allowing other widgets to expand to take up the "newly available" space; an effect that I want to avoid.

我想我可以使每个QWidget类型的子类都覆盖paintEvent()(和mousePressEvent()等),使其成为空操作(在适当的情况下),但是我更喜欢一个不包含以下内容的解决方案:要求我创建三打不同的QWidget子类.

I suppose I could make a subclass of every QWidget type that override paintEvent() (and mousePressEvent() and etc) to be a no-op (when appropriate), but I'd prefer a solution that doesn't require me to create three dozen different QWidget subclasses.

推荐答案

我知道的唯一体面的方法是将事件过滤器附加到小部件,并过滤掉重绘事件.无论小部件多么复杂,它都可以工作-它可以有子小部件.

The only decent way I know of is to attach an event filter to the widget, and filter out repaint events. It will work no matter how complex the widget is - it can have child widgets.

下面是一个完整的独立示例.但是,它带有一些警告,并且需要进一步的开发才能使其完整.仅覆盖paint事件,因此您仍然可以与小部件进行交互,只是看不到任何效果.

Below is a complete stand-alone example. It comes with some caveats, though, and would need further development to make it complete. Only the paint event is overridden, thus you can still interact with the widget, you just won't see any effects.

鼠标单击,鼠标进入/离开事件,焦点事件等仍将到达小部件.如果该窗口小部件依赖于重画时要完成的某些事情,可能是由于这些事件触发了update()造成的,那就麻烦了.

Mouse clicks, mouse enter/leave events, focus events, etc. will still get to the widget. If the widget depends on certain things being done upon an a repaint, perhaps due to an update() triggered upon those events, there may be trouble.

至少您需要一个case语句来阻止更多事件-例如说鼠标移动和单击事件.处理焦点是一个问题:如果在焦点集中时以及在需要重新获得焦点时隐藏该窗口小部件,则需要将焦点移到链中的下一个窗口小部件.

At a minimum you'd need a case statement to block more events -- say mouse move and click events. Handling focus is a concern: you'd need to move focus over to the next widget in the chain should the widget be hidden while it's focused, and whenever it'd reacquire focus.

鼠标跟踪也带来了一些问题,如果您以前曾跟踪过该小部件,您可能会假装它丢失了鼠标跟踪.正确地模拟这一点需要进行一些研究,我不知道Qt呈现给小部件的确切的鼠标跟踪事件协议是什么.

The mouse tracking poses some concerns too, you'd want to pretend that the widget lost mouse tracking if it was tracking before. Properly emulating this would require some research, I don't know off the top of my head what is the exact mouse tracking event protocol that Qt presents to the widgets.

//main.cpp
#include <QEvent>
#include <QPaintEvent>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QGridLayout>
#include <QDialogButtonBox>
#include <QApplication>

class Hider : public QObject
{
    Q_OBJECT
public:
    Hider(QObject * parent = 0) : QObject(parent) {}
    bool eventFilter(QObject *, QEvent * ev) {
        return ev->type() == QEvent::Paint;
    }
    void hide(QWidget * w) {
        w->installEventFilter(this);
        w->update();
    }
    void unhide(QWidget * w) {
        w->removeEventFilter(this);
        w->update();
    }
    Q_SLOT void hideWidget()
    {
        QObject * s = sender();
        if (s->isWidgetType()) { hide(qobject_cast<QWidget*>(s)); }
    }
};

class Window : public QWidget
{
    Q_OBJECT
    Hider m_hider;
    QDialogButtonBox m_buttons;
    QWidget * m_widget;
    Q_SLOT void on_hide_clicked() { m_hider.hide(m_widget); }
    Q_SLOT void on_show_clicked() { m_hider.unhide(m_widget); }
public:
    Window() {
        QGridLayout * lt = new QGridLayout(this);
        lt->addWidget(new QLabel("label1"), 0, 0);
        lt->addWidget(m_widget = new QLabel("hiding label2"), 0, 1);
        lt->addWidget(new QLabel("label3"), 0, 2);
        lt->addWidget(&m_buttons, 1, 0, 1, 3);
        QWidget * b;
        b = m_buttons.addButton("&Hide", QDialogButtonBox::ActionRole);
        b->setObjectName("hide");
        b = m_buttons.addButton("&Show", QDialogButtonBox::ActionRole);
        b->setObjectName("show");
        b = m_buttons.addButton("Hide &Self", QDialogButtonBox::ActionRole);
        connect(b, SIGNAL(clicked()), &m_hider, SLOT(hideWidget()));
        QMetaObject::connectSlotsByName(this);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Window w;
    w.show();
    return a.exec();
}

#include "main.moc"

这篇关于如何在不更改其他Qt小部件位置的情况下使Qt小部件不可见?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆