Can you hide a QGroupBox frame but preserve it's content visible?

12,197

Solution 1

You can use QFrame + QGridLayout (or some more complex combination of layouts) + QSS instead of a QGroupBox.

Considering a QGroupBox only, a trivial solution via QSS could be:

static const char kSavedTitle[] = "_savedTitle";
void hideBoxFrame(QGroupBox * box) {
  box->setProperty(kSavedTitle, box->title());
  box->setTitle(QString());
  box->setStyleSheet("border:none");
}
void showBoxFrame(QGroupBox * box) {
  box->setTitle(box->property(kSavedTitle).toString());
  box->setStyleSheet(QString());
}

Solution 2

My option:

QGroupBox theBox;
theBox.setFlat(true);
//This removes the border from a QGroupBox named "theBox".
theBox.setStyleSheet("QGroupBox#theBox {border:0;}");
//This removes the border from the group box and all of its children
theBox.setStyleSheet("border:0;");

Solution 3

You can derive your own Group Box from the QGroupBox and reimplement the paintEvent() method. It should be very simple. Original QGroupBox::paintEvent() looks like this:

void QGroupBox::paintEvent(QPaintEvent *)
{
    QStylePainter paint(this);
    QStyleOptionGroupBox option;
    initStyleOption(&option);
    paint.drawComplexControl(QStyle::CC_GroupBox, option);
}

What you need to do is just to modify the style option right before the widget is painted:

void CMyGroupBox::paintEvent(QPaintEvent *)
{
    QStylePainter paint(this);
    QStyleOptionGroupBox option;
    initStyleOption(&option);

    // This should disable frame painting.
    option.features = QStyleOptionFrame::None;

    paint.drawComplexControl(QStyle::CC_GroupBox, option);
}

Solution 4

Here's an example that does it by swapping the widgets and reparenting the children. It works for any widget that has direct children, not only QGroupBox. It would require special case handling for widgets such as QScrollArea and QMainWindow that wrap children in a special sub-widget.

See this question for a related discussion of programmatically promoting widgets.

screenshot of the example

// https://github.com/KubaO/stackoverflown/tree/master/questions/group-reparent-36603051
#include <QtWidgets>

/// Replaces the visible widget with a hidden widget, preserving the layout of the
/// children, and making the new widget visible.
void swapWidgets(QWidget * a, QWidget * b)
{
   auto src = a->isVisible() ? a : b;
   auto dst = a->isVisible() ? b : a;
   Q_ASSERT(dst->isHidden());
   /// Move the children to the destination
   dst->setLayout(src->layout());
   /// Replace source with destination in the parent
   auto layout = src->parentWidget()->layout();
   delete layout->replaceWidget(src, dst);
   /// Unparent the source, otherwise it won't be reinsertable into the parent.
   src->setParent(nullptr);
   /// Only the destination should be seen.
   src->hide();
   dst->show();
}

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   QWidget w;
   QGridLayout wLayout{&w};
   QPushButton swapBtn{"Swap"};
   wLayout.addWidget(&swapBtn);

   QWidget noBox;
   QGroupBox box{"Group"};
   wLayout.addWidget(&box);
   QGridLayout boxLayout{&box};
   for (int i = 0; i < 16; ++i)
      boxLayout.addWidget(new QLabel(QString("Tr%1").arg(i)), i/8, i%8);

   swapBtn.connect(&swapBtn, &QPushButton::clicked, [&] { swapWidgets(&box, &noBox); });
   w.show();
   return app.exec();
}
Share:
12,197
jpo38
Author by

jpo38

Software developer, mainly C++, worked with MFC, now working with Qt. Using CMake and more Python every day...

Updated on June 15, 2022

Comments

  • jpo38
    jpo38 about 2 years

    I have a QGroupBox. Depending on the context, it's title may be redundent (displayed in another place of the GUI), so I then need to make as if the QGroupBox was not here....but I must preserve it's content visible (so I don't want to call QGroupBox::hide())!

    I need to do this dynamically at runtime and would like to avoid creating/destroying the QGroupBox + reparenting it's content....there must be an easier way to do this.

    What I tried so far:

    QGroupBox visible:

    enter image description here

    • QGroupBox::setTitle("") removes the text.
    • QGroupBox::setFlat(true) makes the frame be a single line.

    I end up with this:

    enter image description here

    Not too bad...but a line remains....is there a way to completely hide the QGroupBox frame but preserve it's content visible?

  • jpo38
    jpo38 about 8 years
    That's an option, but more difficult to setup than applying a stylesheet as commented by MasterAler
  • jpo38
    jpo38 over 7 years
    Nice alternative.
  • Cecil Curry
    Cecil Curry over 6 years
    Actually, this solution is approximately as trivial to implement as MasterAler's prior solution but has the significant advantage of not hiding the frames of all child widgets. While simple, setting a stylesheet of border:0 unconditionally applies that style to all child widgets. That's bad. While slightly less simple, this solution suffers no such critical defects. That's good.
  • jpo38
    jpo38 over 6 years
    But QFrame won't let you display a title on the bar ("Emulator 0" in my screenshot)
  • Sachith Bathiya
    Sachith Bathiya over 6 years
    that's true. But it looks like the easiest approach to do that with a label
  • fogx
    fogx over 4 years
    how would i do this for the PyQt version? I am unsure of how to change the method, because the module doesn't have the logic... def paintEvent(self, a0: QtGui.QPaintEvent) -> None: ...