8

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
  • 20,821
  • 10
  • 70
  • 151
  • I had a similar problem, what I end up doing is to place content in a QTableWidget. With QTablewidget, I can hide all borders. – m. c. Apr 13 '16 at 17:59
  • 1
    @MasterAler: `QComboBox::setStyleSheet( "border: none" );` works just perfectly. If you add this as an answer, I'll be glad to accept it. – jpo38 Apr 14 '16 at 06:28
  • @KubaOber: Just expecting to find something more trivial....as MasterAler proposed for instance. – jpo38 Apr 14 '16 at 06:29
  • @user3183610: `QGroupBox` can be made chackable, `QTableWidget` can't.... – jpo38 Apr 14 '16 at 06:29

5 Answers5

10

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;");
AlgoBorg
  • 3
  • 2
pablo_worker
  • 1,042
  • 9
  • 26
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);
}
Tomas
  • 2,170
  • 10
  • 14
  • That's an option, but more difficult to setup than applying a stylesheet as commented by MasterAler – jpo38 Apr 14 '16 at 06:30
  • Actually, this solution is approximately as trivial to implement as [MasterAler](https://stackoverflow.com/users/2846068/masteraler)'s [prior solution](https://stackoverflow.com/a/36623476/2809027) 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. – Cecil Curry Dec 15 '17 at 06:51
  • 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: ...` – fogx Nov 18 '19 at 15:42
2

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());
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
MasterAler
  • 1,614
  • 3
  • 23
  • 35
2

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();
}
Community
  • 1
  • 1
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
0

Yes there is a alternative that you can Try.

You can morph into a QFrame which will keep the behavior But make the container boundaryless

You can simply right click on the Group Box in the QDesigner and Select the 'Morph Into' option to select from