47

QPushButtons、QLabels、その他の楽しい QWidgets でいっぱいのウィンドウがあり、すべてがさまざまなQLayoutオブジェクトを使用して動的にレイアウトされています...そして、私がやりたいのは、これらのウィジェットの一部を非表示にすることです。つまり、非表示のウィジェットは、ウィンドウのレイアウトで通常のスペースを占有しますが、レンダリングされません。代わりに、ユーザーには、ウィジェットの長方形/領域にウィンドウの背景色が表示されます。

hide()および/またはsetVisible(false)ウィジェットがレイアウトから完全に削除され、他のウィジェットが拡張して「新しく利用可能な」スペースを占有できるようになるため、トリックを実行しません。避けたい効果。

QWidgetオーバーライドするすべてのタイプのサブクラスpaintEvent()(およびその他) を (適切な場合) no-op にすることができると思いますが、3 ダースの異なるサブクラスmousePressEvent()を作成する必要のないソリューションを好みます。QWidget

4

10 に答える 10

82

この問題は Qt 5.2 で解決されました。かわいい解決策は次のとおりです。

QSizePolicy sp_retain = widget->sizePolicy();
sp_retain.setRetainSizeWhenHidden(true);
widget->setSizePolicy(sp_retain);

http://doc.qt.io/qt-5/qsizepolicy.html#setRetainSizeWhenHidden

于 2016-01-07T18:58:54.973 に答える
15

私が知っている唯一の適切な方法は、イベント フィルターをウィジェットにアタッチし、再描画イベントを除外することです。ウィジェットがどれほど複雑であっても機能します。子ウィジェットを持つことができます。

以下は、完全なスタンドアロンの例です。ただし、いくつかの注意点があり、完成させるにはさらに開発が必要です。ペイント イベントのみがオーバーライドされるため、引き続きウィジェットを操作できますが、効果は表示されません。

マウス クリック、マウスの開始/終了イベント、フォーカス イベントなどは引き続きウィジェットに到達します。再描画時に実行される特定の処理にウィジェットが依存している場合、おそらくそれらのイベントでトリガーされた update() が原因で、問題が発生する可能性があります。

少なくとも、より多くのイベントをブロックするには、case ステートメントが必要です。たとえば、マウスの移動イベントやクリック イベントなどです。フォーカスの処理は懸念事項です。フォーカスされているウィジェットが非表示になっている場合、およびフォーカスを再取得するたびに、チェーン内の次のウィジェットにフォーカスを移動する必要があります。

マウスの追跡にもいくつかの懸念があります。ウィジェットが以前に追跡していた場合、ウィジェットがマウスの追跡を失ったふりをしたいでしょう。これを適切にエミュレートするには、いくつかの調査が必要になります.Qtがウィジェットに提示する正確なマウス追跡イベントプロトコルが何であるかは頭の中でわかりません。

//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"
于 2012-05-31T20:36:32.533 に答える
8

QStackedWidget を使用できます。ボタンを最初のページに配置し、空白の QWidget を 2 番目のページに配置し、ページ インデックスを変更して、元のスペースを保持したままボタンを非表示にします。

于 2013-01-08T20:26:49.733 に答える
4

私は3つの解決策を考えています:

1) QWidget をサブクラス化し、特別な/独自の setVisible() 置換メソッドを使用して、ウィジェットの描画をオン/オフします (ウィジェットを非表示にする必要がある場合は、オーバーライドされた paintEvent() メソッドで描画を無視するだけです)。これは汚い解決策です。他の方法で実行できる場合は使用しないでください。

2) QSpacerItemをプレースホルダーとして使用し、非表示にする QWidget の反対側に可視性を設定しますが、レイアウト内の位置とサイズは保持します。

3) 子/子ウィジェットのサイズに基づいてサイズを取得/同期する特別なコンテナー ウィジェット (QWidget から継承) を使用できます。

于 2012-05-30T15:18:27.770 に答える
3

私は同様の問題を抱えていたので、気にしている次元のサイズが 0 で、ExpandingsizeType のコントロールの隣にスペーサーを配置することになりました。次に、コントロール自体をExpandingsizeType でマークし、ストレッチを 1 に設定します。これにより、表示されている場合はスペーサーよりも優先されますが、表示されていない場合は、コントロールが通常占有するスペースを埋めるためにスペーサーが拡張されます。

于 2014-04-14T19:58:54.093 に答える
2

1 つのオプションは、常に false を返す QWidgetItem の新しいサブクラスを実装することですQLayoutItem::isEmpty。Qt の QLayout の例のサブクラスのドキュメントが原因で動作すると思われます:

QLayoutItem::isEmpty(); は無視します。これは、レイアウトが非表示のウィジェットを可視として扱うことを意味します。

ただし、レイアウトにアイテムを追加するのは少し面倒だと思うかもしれません。特に、UI ファイルでレイアウトを簡単に指定できるかどうかはわかりません。

于 2012-05-29T07:55:35.817 に答える
2

QWidget::setWindowOpacity(0.0) が必要なのかもしれません。しかし、この方法はどこでも通用するわけではありません。

于 2012-05-29T07:33:47.307 に答える
1

QFrameをラッパーとして使用できると思います。より良いアイデアがあるかもしれませんが。

于 2012-05-31T20:46:24.747 に答える
0

試してみてくださいvoid QWidget::erase ()。Qt3で動作します。

于 2012-05-29T07:52:16.370 に答える