GtkVBox Qt equivalent - c++

In GTK, I used to have a window to which I gtk_container_add()'d a GtkVBox. Then I could pack widgets I wanted to the GtkVBox to have them appear in the window.
Now I've decided to try out Qt, but I can't seem to figure out how to do this in Qt.
Right now what I've done is create a QMainWindow, but I found that you can only pack one main widget into it, which is obviously quite limiting. So I wanted to create something like the GtkVBox and use that as the main widget and then add other widgets to this box.
What I've found by Googling are however only the Q3VBox widget, which seems to be what I want, but is deprecated, and the QVBoxLayout.
I tried to use the QVBoxLayout, but it tells me that I cannot change the layout of my QMainWindow since it already has a layout.
Edit: Here is how I do it (this is in the constructor):
box = new QVBoxLayout;
setLayout(box)
It compiles fine, but during runtime, it prints on the console:
QWidget::setLayout: Attempting to set QLayout "" on HCGWindow "", which already has a layout
(HCGWindow is my app's window, which is a subclass of QMainWindow)
So, how can I create something similar to a GtkVBox in Qt, and if the solution is the Q3VBox, why is it deprecated and what other thing should I use?
Thanks

In fact, here is the recommended solution provided by the Qt documentation.
You should create a QVBoxLayout and add the widgets you want in it. After that, you set the layout on another empty widget and then you set this widget as the central widget of the QMainWindow subclass. Here is an example in code:
QWidget* widget1 = new QWidget(); // This could be anything subclassing QWidget.
QWidget* widget2 = new QWidget();
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(widget1);
layout->addWidget(widget2);
QWidget* central = new QWidget(); // Only a containing QWidget.
central->setLayout(layout);
this->setCentralWidget(central);
Now, you QMainWindow subclass should have the two QWidgets in it, arranged in a QVBoxLayout.
Note here that I did not give any parent to anyone. You could have done it, but when you call addWidget or setCentralWidget, the ownership of the widget (and the layout) is given to the containing class.
If you read a bit about Qt, you'll know that this allows the parent to destroy his children when he is about to be destroyed itself.
Finally, note that QMainWindow is an exception and, from what I know, is the only class with setCentralWidget as a method. If you attempt to create a QWidget subclass, you will be able to use setLayout (as shown in the example above).
Hope this helps.

Try to create QVBoxLayout instance, add your widgets to it and add (not replace) this layout to main window's layout.
Note, QLayout class has no member addLayout, but subclasses has one.
Firstly you must get and remember classname of main window's layout:
qDebug(this.layout()->objectName);
Then add your QVBoxLayout to window's layout:
dynamic_cast<YourWindowLayoutClass>(
this.layout())->addLayout(your_qvboxlayout_object);
I hope it will work.

Related

Qt Widgets, is it mandatory to set the containing widget as parent?

I would like to insert a QWidget inside a container QWidget (via its layout), but avoid parenting the inserted widget to the container widget.
There are good reasons behind this, the inserted widget is a toolbox tied to a document, and this toolbox is sent to a floating dock widget when the document becomes the active document.
Is this possible?
I would like to insert a QWidget inside a container QWidget (via its
layout), but avoid parenting the inserted widget to the container
widget.
There are good reasons behind this, the inserted widget is a toolbox
tied to a document, and this toolbox is sent to a floating dock widget
when the document becomes the active document.
Is this possible?
This simple answer is No - cannot avoid the widget being parented. But hold on. First, why the answer is No. Then how can we still do what you want.
Setting the layout for the widget does an implicit parent set.
Setting the widget for the layout does an implicit parent set.
QVBoxLayout* layout = new QVBoxLayout; // no parent yet
this->setLayout(layout); // it does layout->setParent(this);
QWidget* widget = new MyWidget; // no parent yet
layout->addWidget( widget ); // it does widget->setParent(this);
If layout is the layout manager on a different widget, setLayout()
will reparent the layout and make it the layout manager for this
widget.
With QLayout the reparenting is a bit more complicated because addWidget does call addItem:
void QLayout::addItem(QLayoutItem * item)
Implemented in subclasses to add an item. How it is added is specific
to each subclass.
This function is not usually called in application code. To add a
widget to a layout, use the addWidget() function; to add a child
layout, use the addLayout() function provided by the relevant QLayout
subclass.
Note: The ownership of item is transferred to the layout, and it's the
layout's responsibility to delete it.
See also addWidget(), QBoxLayout::addLayout(), and
QGridLayout::addLayout().
void QLayout::addWidget(QWidget * w)
Adds widget w to this layout in a manner specific to the layout. This
function uses addItem().
But we can still do something about such request:
There are good reasons behind this, the inserted widget is a toolbox
tied to a document, and this toolbox is sent to a floating dock widget
when the document becomes the active document.
Is this possible?
But that is of course possible. Say, by calling QWidget::setParent which is quite a common practice when we need to move the parent into new layout.

Qt QWidget::setGeomerty

i'm stuck with a simple Function of Qt that does not work for me.i made a class that inherits
from QMainWindow and another class that inherits from QWidget.then i made from the second a member object(a pointer to) inside the first and assigned it as its centralWidget during the construction of my window.
when it comes to adjust my centraWidget inside the window with the function QWidget::setGeomerty() it simply don't work.here's my code:
void MainWindow::show()
{
//some code that centers my window on the screen
int margin=this->width()/7;
centralWidget()->setGeometry(margin,centralWidget()->geometry().top(),this->width()-margin,centralWidget()->geometry().bottom());
QMainWindow::show();
}
i know it might be stupid but i just can't figure it out.help me.
QMainWindow has its own layout in which the center area is occupied by the central widget. So it won't be pretty straightforward to break that layout and modify the central widget size / position arbitrarily.
What I recommend is to use a placeholder central widget and add your widget as a child.
I'm pretty sure you can achieve what you want by setting a proper Qt built in layout to the "placeholder" central widget and then adding your widget to the layout.
layouts was necessary to manage what i want; i think it's not possible to hand directly over the central widget and try to move/resize it;but by adding a layout and a child widget, we can dispose of them.here is my code:
mainwindow.cpp
// i focused on my window constructor
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
m_MainView(new MainView(this)),
m_WindowLayout(new MainWindLayout(NULL))//my custom layout witch just inherits from QGridLayout
{
//.............
setCentralWidget(m_MainView);
m_WindowLayout=new MainWindLayout(m_MainView);//my layout set into my central Widget"m_MainView".
QWidget *temp(dynamic_cast<QWidget *>(m_MainView->centralView()));//centralView() returns a child QWidget of my central Widget
QMargins margins(this->width()/5,0,this->width()/5,0);//setting up layout margins :left,top,right,bottom;exactly what i need
m_WindowLayout->setContentsMargins( margins);
m_WindowLayout->addWidget(temp,0,0,-1,-1);//adding my child widget to the layout filling all cells of the gridlayout.
}
thanks everybody

Promote QWidget to QMainWindow or add QMainWindow to QWidget from Qt Designer

My problem:
I want to customize the way the title bar works and looks for my application.
My idea:
I created a new QWidget form in Qt Designer and added a QWidget to it. I added the following code in constructor:
setAttribute(Qt::WA_TranslucentBackground);
setWindowFlags(Qt::FramelessWindowHint);
QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect();
effect->setBlurRadius(20);
effect->setXOffset(0);
effect->setYOffset(0);
setGraphicsEffect(effect);
which makes the outer widget transparent and adds shadow to my inner widget. From this on I can create a custom title bar widget which I can implement however I want.
This is the result:
My issue
I want to make this usable from the designer as a main window and the QWidget doesn't allow me to add FROM THE DESIGNER tool bars, menu bar and status bar.
What I thought about was adding a QMainWindow widget as a child widget for the outer QWidget(which is transparent and acts as support for my shadow(the shadow is drawn on it)). I did this successfully but only from code:
QMainWindow *centralwidget = new QMainWindow();
centralwidget->setStyleSheet("background-color: lightgray;");
centralwidget->setGeometry(0, 0, 50, 20);
centralwidget->setWindowFlags(Qt::Widget);
this->layout()->addWidget(centralwidget);
QMenuBar *menuBar = new QMenuBar(centralwidget);
menuBar->addAction("Action");
QStatusBar *statusBar = new QStatusBar;
statusBar->showMessage("Status bar here");
centralwidget->addToolBar("tool bar");
centralwidget->setMenuBar(menuBar);
centralwidget->setStatusBar(statusBar);
This is the result:
My question:
How can I achieve this result from Qt Designer? Is it possible to promote a QWidget to QMainWindow? I cannot think to another way of doing it... It is really important for me to make it usable from Qt Designer because I intend to make it a template widget and be able to create e.g. a new QCustomMainWindow form Qt Creator just like you can create a QWidget or a QMainWindow.
Please help!
Here is another SO question similar to yours: Qt4: Placing QMainWindow instance inside other QWidget/QMainWindow
Just adding on to my original comment:
Start with a QMainWindow, and then apply the appropriate flags to it. QMainWindow is a subclass of QWidget. If it can't be done easily in the designer, it is pretty painless to do in code. Do it in your constructor right after the ui->setup() call.
Start with QMainWindow
Customize Window Flags
So in the constructor in mainwindow.cpp, you put
http://qt-project.org/doc/qt-5/qt.html#WindowType-enum
this->setWindowFlags(Qt::Widget);
This is the default type for QWidget. Widgets of this type are child
widgets if they have a parent, and independent windows if they have no
parent. See also Qt::Window and Qt::SubWindow.
// or if you want to apply more than one you, "or" it together, like so:
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool);
Try out a couple of those and see what you like.
Customize Widget Attributes
There are also Widget Attributes, that give you strong control over how your widgets look like and behave.
http://qt-project.org/doc/qt-5/qt.html#WidgetAttribute-enum
Qt Style Sheets
In addition to all the flags and attributes above, you can also modify a ton of it with stylesheets:
http://qt-project.org/doc/qt-5/stylesheet-reference.html
this->setStyleSheet("background: #000000;");
Qt Designer Custom Widgets
And also if you are interested in making this a reusable thing in Qt Designer, you can make it into a Qt Designer plugin, or custom widgets.
http://qt-project.org/doc/qt-4.8/designer-using-custom-widgets.html
http://qt-project.org/doc/qt-4.8/designer-creating-custom-widgets.html
QMdiArea and QMdiWindow
Another path to look into besides using QMainWindow is QMdiSubWindow
http://qt-project.org/doc/qt-5/QMdiSubWindow.html

How to expand widgets with window resize?

I have a simple qt application with a QTabWidget inside the main window. I also have a few QPushButton(s) and QRadioButton(s).
What I want is that when I resize the window either manually or by maximizing/minimizing it should resize the containers in the same way.
In other words, what I want is equivalent of DockStyle.Fill in qt C++
How can I do that ?
In Qt you have to use Layouts:
The Qt layout system provides a simple and powerful way of automatically arranging child widgets within a widget to ensure that
they make good use of the available space.
In short, all components in a layout will be relocated to new places after the window, to which the layout belongs, is resized.
If you are using deisgner:
1. Click the empty space of a widget to select itself(or a main Window, I use just a base widget here for demonstration), and the layout option will be hightlighted:
2. Choose a desired layout
Here is what object monitor looks like after a QVBoxLayout is used:
If your widget doesn't use layout, it will look like this:
What we have done here is to make the base widget/mainWindow equip a main layout. You can see that the buttons are automatically aligned, when you resize the widget, those component will be relocated according to the layout:
Perhaps you will find it nettlesome of those expanding space, so the next move is to add a Spacer to the layout; so when layout is resized, only the spacer will stretch.
(Another option is to make your widgets expandable, see ** at the end of this post)
3. Besides, you can add a layout into another to create a nested layout
For example, first I choose A and B (by pressing Ctrl) and use QVBoxLayout. This additional layout is not base layout and hence highlighted by red rectangle.
Then I choose C and the layout which contains A & B, and use QHBoxLayout on them,
Finally I use another QVBoxLayout as my main layout on the base widget, just like what we did previously.
And the object monitor:
If you like the special feeling of hitting keyboard and always handcraft the code:
For the last example:
QWidget *Form = new QWidget;
QPushButton *pushButton_A = new QPushButton("A");
QPushButton *pushButton_B = new QPushButton("B");
QPushButton *pushButton_C = new QPushButton("C");
QVBoxLayout *verticalLayout = new QVBoxLayout;
QHBoxLayout *horizontalLayout = new QHBoxLayout;
QVBoxLayout *mainLayout = new QVBoxLayout;
verticalLayout->addWidget(pushButton_A);
verticalLayout->addWidget(pushButton_B);
horizontalLayout->addWidget(pushButton_C);
horizontalLayout->addLayout(verticalLayout);
mainLayout->addLayout(horizontalLayout);
Form->setLayout(mainLayout);
Form->show();
In your case
Here is an example of layout:
Notice that QMainWidget has a centralwidget as a base widget. Besides, each tab of QTabWidget has it's own base widget (tab and tab_2 in the picture) which adopts another base layout.
*Don't forget to add Spacer in layouts to shape them as you like.
** You can set size policy on each widget (QTabWidget, QPushButton etc) to make them horizontally/vertically expandable or fixed, this cooperates with the layout strategy. For example, in the very begin example if we set
button A to be vertically fixed, horizontally expanding
button B to be vertically expanding, horizontally expanding
button C to be vertically expanding, horizontally fixed
It will look like this when resizing:
you need to look into how to use layouts in your application
http://qt-project.org/doc/qt-4.8/layout.html
As a quick and simple first try, in the Designer you can right-click on the main window, and choose "layout" from the drop-down menu. Here you can pick the grid layout, for instance.

Add QTextEdit objects to a QMainWindow

I seem to be having an issue. Objective: I want to dynamically add QTextEdit to a QMainWindow, I have a lot of data I wish to split amongst various QTextEdit objects. I've been looking at centralWidget and did some digging into ui->setupUi(this); generated by the Qt Creator and spotted that the parent for objects of interest was the central widget of the QMainWindow. Thus I've tried something like this:
this->m_vecTextEdits.push_back( new QTextEdit(this->centralWidget()) );
where 'this' is the QMainWindow. I just want to add these QTextEdit to the QMainWindow and later remove them. I also tried new QTextEdit(this) hoping it would appear on the QMainWindow with the properties defined by the objects geometry to no luck.
If I setCentralWidget to be that of the QTextEdit than it works but I don't want the object to consume the entire QMainWindow and restrict access to existing widgets.
So I'm in need of advice of basically how I can add QTextEdit widgets to the existing centralWidget of the QMainWindow and have them appear in the window and also remove.
I wanted to add multiple QTextEdit so I can use a residing QListWidget
(the index property) to switch amongst the many QTextEdit widgets
You could put a QStackedWidget in place of your QTextEdit, and add all the QTextEdits to it.
Only one of the textedits would be visible at all time, but you can switch between them automatically by connecting the signal currentRowChanged(int) of your QListWidget to the slot setCurrentIndex(int) so that the index of the QTextEdit stay the same as the index of the selected item in your list.
The QStackedWidget will replace your container m_vecTextEdits too.
It's not enough to just create the widget objects; you also need to add them to a layout object. Try something like:
QBoxLayout * bl = new QBoxLayout(centralWidget());
QTextEdit * t = new QTextEdit;
bl->addWidget(t);