Solved Create customized Container-Widget
-
Hi everyone,
I am trying to archieve something like the following using Qt:The idea is to have a customized Frame with an extended title-area on top. Therefore I want to subclass QWidget or a derived class like QFrame. And of course rewrite the paintEvent.
The Challenge in this case is, that the Widget should be used as a container for other widgets, similar to QFrame:So the differnce to a QFrame would be, that it will have two different Areas (black lines):
- the Outer-Frame, which has to interacts with its neighbors/Splitters/Layouts
- the Inner-Frame, which contains other widgets (red, blue, green)
I found a lot of documents and tutorials about basic Widget-Subclassing out there, but not about using it as a container.
I know about the possibility of writing plugins, but I don‘t need an integration in the Qt Designer-interface. So that is maybe (?) not necessary.
I am just looking for a general idea like: „Simply subclass QFrame and …(some useful operation here).“
Every hint or link to a useful doc is welcome!Thank you so much,
your justStartedQt -
Hi and welcome.
for the inner-frame I think you can just use layouts to have them
arranged like that
http://doc.qt.io/qt-5/layout.html
The http://doc.qt.io/qt-5/qgridlayout.html seems like a good matchAnd you can just use the promotion feature to use your custom widget.
a full plugin is not needed.Regarding Containers.
If you add a layout to any widget , it can be a container. (most anyway) -
@justStartedQt said in Create customized Container-Widget:
Hi everyone,
I am trying to archieve something like the following using Qt:Isn't that just a QTabWidget with a bit of stylesheet on top?
-
@mrjj
First of all: thank you for this fast answer.
So the "Outer-Frame" would be my Subclassed QFrame / QWidget. But how would Widgets, which I place inside my Frame (examples in red, blue, green) then now, that they have to use only the area i called "Inner-Frame"?
Maybe a stupid Question, but thank you very much anyway. -
@justStartedQt
Im not sure excactly what you mean.
The Color widgets would be in a layout and stay inside the area defined by the
owner of the layout.And you just insert the widgets into the layout and they can only use the the space assigned.
The layout have margins and you can just raise the top margin to have some "air" above it.Also as @VRonin says, you could style QTabWidget
to make it look like that and then use layout in its "page" to have
one or more QFrame with the color widgets. And the color widget
would stay inside the QFrame.http://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar
If i understand you correctly i think you can just nest QFrame or widgets and use layout to get the feature you want.
-
Hi again and thanks that you are trying to help me.
I maybe haven't really expressed clearly what I mean.Its Maybe not really about Tabs, because the widget will always have only 1 Title and therefore only 1 Content. Also there is no extra functionality like moving it. It is more like a decorated Frame, which holds content/other widgets.
Besides I want to reuse that widget like in the Image. Or even subclass it again for something else. In your Example (I'm sorry, if I missunderstood that) it looks like you rather used multiple Widgets placed together than creating a single new one?
Possibility 1: I create the Widget MyTitleFrame by subclassing QFrame. But if I now parent fx. a Pushbutton to it, how would the Pushbutton then know, that there is a special area for the Child-Widgets? All Widgets would just use all the space in the "MainFrame".
Possibility 2: I create the Widget MyTitleFrame by subclassing QFrame, which holds another Frame. This "Inner-Frame" could be used to place other Widgets correctly. But if I now parent a Pushbutton to a MyTitleFrame, how does the Pushbutton know, that it should not use the "Mainframe", but the "Inner-Frame".
I try my best to communicate my problem, but I see that I am not as good in it.
Thank you anyway for your repeated efforts, mrjj.
-
Hi
Yes my sample is made of multiple widgets The tab Width has an inner QFrame with layout
and that inner QFrame has the gridlayout ( like your Possibility 2, but i used a tab to get the caption thing easy)
You can easy use such construct by dragging it to the left side widget list and get a "template"
than you can drag into any form again.Possibility 1:
One way would to use a layout and set topmargin as then the button would obey that.
You would still be able to draw on the widget (outside layout) but any widget you insert would
respect the layout. You can then draw the inner black frame in paint event, using the layouts margins as offset.
Using stylesheets, a widgets can have border too. It dont have to be QFrame. Also your frame seems
pretty simple so subclassing widget would also work fine and simply draw it.Possibility 2:
You insert the Pushbutton to the correct frame/layout. like Inner-Frame->layout()->AddWidget(QPushButton)
And then it stays there. You would not insert into MyTitleFrame layout/parent to MyTitleFrameWhen inserting widgets into other widgets, you use layout most of the time as else the inner widget will be free floating
and not scale with parent. (which is often desired)
So a child widget stays inside the parent and if parent have layout it will be handled by the layout.But if you rather make a custom widget, its also quite feasible but if you dont use a layout,
you will manually have to make sure any child are moved down. You could use stylesheet and
make use of the http://doc.qt.io/qt-5/stylesheet-customizing.html to make sure its moved but mixing
custom drawing and stylesheet is more involving that simply using a layout with top margin set to what ever offset you want.
(so it dont start up in the caption area)
The simply draw the inner frame with info from the layout and also draw Title and outerframe. -
Hi
for learning, here is a fast implementation of a drawn version.
Its not perfect but demostrates how it can be done with painting +layout.#ifndef TITLEFRAMEWIDGET_H #define TITLEFRAMEWIDGET_H #include <QGridLayout> #include <QPainter> #include <QPushButton> #include <QWidget> class TitleFrameWidget : public QWidget { Q_OBJECT QGridLayout* gridLayout; const int TitleHeightBox = 22; const int TopMargin = 20; // air to widget area const int pad = 4; const int innerpad = 2; public: explicit TitleFrameWidget(QWidget* parent = nullptr) : QWidget(parent) { gridLayout = new QGridLayout(this); gridLayout->setObjectName(QStringLiteral("gridLayout")); gridLayout->setContentsMargins(pad, TopMargin+TitleHeightBox, pad + (innerpad * 2), pad ); // for test gridLayout->addWidget( new QPushButton("tester")); } signals: public slots: protected: virtual void paintEvent(QPaintEvent* event) override { QPainter p(this); QString Title = "Title"; // Title text should be a property or at least be set via ctor // get Title size QFontMetrics fm( font() ); int tw = fm.width(Title); int th = fm.height(); // draw title bg QRect outerframe (0, TitleHeightBox, width() - 1 - pad, height() - TitleHeightBox - 1); // -1 is long story.. p.drawRect(outerframe); // title rect p.setBrush(QBrush(QColor(96, 96, 96))); p.setPen(Qt::NoPen); p.drawRect(pad, 0, width() - ( width() * 0.30), TitleHeightBox ); // 30 % width // draw Title p.setPen(Qt::white); // used for text color p.drawText(pad * 2, tw, Title); // inner frame QRect innerframe = outerframe; innerframe -= QMargins(2, TopMargin, 2, 2); p.setPen(QColor(96, 96, 96)); p.setBrush(Qt::NoBrush); p.drawRect(innerframe); } }; #endif // TITLEFRAMEWIDGET_H
Using layout we prevent it from covering the title area/have what ever offset we want.
That shown. I would say just using some widgets inside each other to gain same effect is less work as you get adjustable margins and and settable titel for free. Directly in Designer.
However it is indeed possible to handcraft one :)