qobject_cast<QVBoxLayout*>(layout()), is the appropriate cast? - c++

Considering the layout was set in a QWidget with the following code:
setLayout(new QVBoxLayout);
And then it needs to be retrieved (to add more stuff to the layout). This was done with the following code:
QHBoxLayout *hLayoutTime(new QHBoxLayout);
qobject_cast<QVBoxLayout*>(layout())->addLayout(hLayoutTime);
qobject_cast is the appropriate kind of cast to use here?

To avoid unneded casting write this like this:
void YourWidget::setupContents()
{
QVBoxLayout *vLayout = new QVBoxLayout(this); // effectively this does setLayout(new QVBoxLayout);
QHBoxLayout *hLayoutTime(new QHBoxLayout);
vLayout->addLayout(hLayoutTime);
… … …
}

Looking the code in your current example, Why don't you just get the pointer when creating?
auto *vLayout = new QVBoxLayout;
auto *hLayoutTime = new QHBoxLayout;
vLayout->addlaout(hLayoutTime);
Answering your question, probably the most adequate cast is:
dynamic_cast<QHBoxLayout*>(new QVBoxLayout);
dynamic_cast has several checks and benefits over static_cast, so it is better to use it when possible.

Related

Change background color of a Qlayout containing QButtons

I have this Qt code:
QHBoxLayout *taggerBox = new QHBoxLayout;
falseBtn = new QToolButton;
falseBtn->setText(tr("False"));
voidBtn = new QToolButton;
voidBtn->setText(tr("Void"));
taggerBox->addWidget(falseBtn);
taggerBox->addWidget(voidBtn);
I would like to change the background of the QHBoxLayout (NOT the background of each button). I didn't find any way to change the background color of a QLayout.
How can I do this ?
Thanks!
QLayout is not a visual element, it's a container that adjust location of contained widgets. You can change background of QFrame or other widgets you included QLayout into.
Since QHBoxLayout is not a QWidget it hasn't its own appearance. So you can't change its color.
You'll have to add an intervening widget that you set the layout on, and change that widget's background. E.g.
auto *taggerBox = new QWidget;
auto *layout = new QHBoxLayout(taggerbox);
falseBtn = new QToolButton(tr("False"));
voidBtn = new QToolButton(tr("Void"));
layout->addWidget(falseBtn);
layout->addWidget(voidBtn);
auto palette = taggerBox->palette();
palette.setColor(QPalette::Window, Qt::blue);
taggerBox->setPalette(palette);
If you're doing this in the constructor of some class, then likely the objects have the same lifetime as the class as there's no point to dynamically allocate them. In such circumstances, the widgets and layouts should be class members instead:
class MyClass : ... {
QWidget taggerBox;
QHBoxLayout taggerLayout{&taggerBox};
QToolButton falseBtn{tr("False")};
QToolButton voidBtn{tr("Void")};
public:
MyClass(...);
};
MyClass::MyClass(...) : ... {
taggerLayout.addWidget(&falseBtn);
taggerLayout.addWidget(&voidBtn);
auto palette = taggerBox.palette();
palette.setColor(QPalette::Window, Qt::blue);
taggerBox.setPalette(palette);
...
}

Make a QHBoxLayout accesible in an Instance of a QWidget

I want to Subclass a QWidget...
Widget::Widget(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::ImgWidget)
{
// Is this the right place or does it need to be outside like: Widget::layout...
QHBoxLayout *hLayout = new QHBoxLayout;
...
hLayout->addWidget( someWidget );
this->setLayout(hLayout);
}
...and then in an instance i would like to add a widget to the layout like
Widget *widget = new Widget();
...
widget->hLayout->addWidget( someOtherWidget );
The equivalent in Python would be done by the 'self' keyword like self.layout = QHBoxLayout() but i think it cant be done with the this keyword
But more general... What is the best way to do this in C++ because i used it a lot with pyqt
Any QWidget can provide access to the layout via the layout function.
Widget* widget = new Widget();
QLayout* layout = widget->layout();
I don't know why you want to externally modify the layout of the widget but at this point you need knowledge of that actual layout type. With knowledge of the layout type you can cast and use it.
QHBoxLayout* hLayout = qobject_cast<QHBoxLayout>(layout);
Implement a function addSubWidget ( QWidget* aubWidget ), the rest of the code is ok, and make hLayout private. Or batter, use the layout function with a cast, like #James sugested.
In c++ it is just recomended, not mandatory to use this->hLayout to be sure you do notshadow it with a local variable with the same name.

QMainWindow not showing up

I have made a quick test program which doesn't seem to bring up anything when executed. Here is my code:
z_lock.h
#ifndef Z_LOCK_H
#define Z_LOCK_H
#include <QtGui>
class z_lock : public QMainWindow
{
Q_OBJECT
public:
z_lock();
private slots:
void password_check();
void quit();
private:
QStackedWidget *book;
QWidget *page1;
QWidget *page2;
QLineEdit *input;
};
#endif
z_lock.cpp
#include "z_lock.h"
z_lock::z_lock(){
book = new QStackedWidget;
//page1
page1 = new QWidget;
QLabel *label1 = new QLabel("Enter password.");
input = new QLineEdit;
QPushButton *goButton = new QPushButton("Go");
connect(goButton, SIGNAL(clicked()), this, SLOT(password_check()));
QHBoxLayout *layout1;
layout1 -> addWidget(label1);
layout1 -> addWidget(input);
layout1 -> addWidget(goButton);
page1 -> setLayout(layout1);
//page2
page2 = new QWidget;
QLabel *label2 = new QLabel("Welcome, you're in.");
QVBoxLayout *layout2;
layout2 -> addWidget(label2);
page2 -> setLayout(layout2);
book -> addWidget(page1);
book -> addWidget(page2);
setCentralWidget(book);
}
void z_lock::quit(){
close();
}
void z_lock::password_check(){
QString guess = input -> text();
if (guess == "apple"){
z_lock::book -> setCurrentIndex(1);
}
}
main.cpp
#include "z_lock.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
z_lock *that;
that -> show();
return app.exec();
}
Please, any help would do. I have carried out research about everything to do with QMainWindow and still nothing. This will probably be stupidly easy to solve and I'm sorry for such a basic question.
You have several issues in your code... Let us start with the most important:
You are allocating the object in your main.cpp on the heap which is a sort-of issue in itself, but even if you do that, you should use the new keyword for that in C++.
That being said, you really should not allocate it here on the heap: partially because it would leak the memory, but more importantly there is no need for it.
Therefore, replace these lines:
z_lock *that;
that -> show();
with simply this:
z_lock that;
that.show();
This is pretty much the same issue for your layouts here, too:
QHBoxLayout *layout1;
QVBoxLayout *layout2;
Please change them to:
QHBoxLayout *layout1 = new QHBoxLayout;
QVBoxLayout *layout2 = new QVBoxLayout;
Furthermore, you should not include the whole QtGui module like this:
#include <QtGui>
Just include the classes which you eventually need. Even though this is in some Qt 4 book, this is bad practice.
This method is also useless in your code since it does nothing except wrapping the existing slot:
void z_lock::quit(){
close();
}
Also, you may wish to use the tr() method for things like this to get translation for other languages:
QLabel *label1 = new QLabel("Enter password.");
z_lock *that;
that -> show();
The problem is that is an uninitialized pointer. It doesn't point to a valid z_lock instance for you to call methods on.
You need to do either allocate and construct a z_lock instance with new:
z_lock* that = new z_lock;
that->show();
Or, more simply, switch to stack allocation:
z_lock that;
that.show();
The same applies to the "layout" variables in the z_lock constructor.
This is an example of why it's a good idea to compile at a high warning level and fix warnings. The compiler can easily notice and point out the invalid use of uninitialized variables.

Replace THIS when moving from MainWindow to function

I have moved the following code from the MainWindow constructor to a function within the MainWindow.
void allFilters(QStringList list){
QWidget *w = new QWidget(this);
w->setFixedSize(300,200);
QVBoxLayout *vbox = new QVBoxLayout;
foreach(QString filt, list){
QCheckBox *checkbox = new QCheckBox(filt, this);
checkbox->setChecked(true);
vbox->addWidget(checkbox);
connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(cbstate(int)));
}
w->setLayout(vbox);
w->show();
}
this is now causing me problems. I assume there is an alternative but I'm unaware of what it is?
Hopefully someone can help me!
It looks like allFilters isn't a member function within MainWindow. this is only valid within non-static member functions as it points to the instance of the object.
You'll need to define it like
void MainWindow::allFilters(QStringList list)

Getting Parent Layout in Qt

quick question. Is there any way to (easily) retrieve the parent layout of a widget in Qt?
PS: QObject::parent() won't work, for logical reasons.
EDIT:
I'm positive the widget has a parent layout, because I added it to a layout earlier in the code. Now, I have many other layouts in the window and while it is possible for me to keep track of them, I just want to know if there is an easy and clean way to get the parent layout.
EDIT2:
Sorry, "easy and clean" was probably not the best way of putting. I meant using the Qt API.
EDIT3:
I'm adding the widget to the layout like this:
QHBoxLayout* layout = new QHBoxLayout;
layout->addWidget(button);
SOLVED!
Usage: QLayout* parentLayout = findParentLayout(addedWidget)
QLayout* findParentLayout(QWidget* w, QLayout* topLevelLayout)
{
for (QObject* qo: topLevelLayout->children())
{
QLayout* layout = qobject_cast<QLayout*>(qo);
if (layout != nullptr)
{
if (layout->indexOf(w) > -1)
return layout;
else if (!layout->children().isEmpty())
{
layout = findParentLayout(w, layout);
if (layout != nullptr)
return layout;
}
}
}
return nullptr;
}
QLayout* findParentLayout(QWidget* w)
{
if (w->parentWidget() != nullptr)
if (w->parentWidget()->layout() != nullptr)
return findParentLayout(w, w->parentWidget()->layout());
return nullptr;
}
(Updated answer)
I guess it is not easily possible then. Since a Widget can be technically contained in multiple layouts (a horizontal layout which is aligned inside a vertical layout, for instance).
Just remember that a QWidget's parent does not change if it is aligned in a layout.
You possibly have to keep track of that yourself, then.
Simply use:
QHBoxLayout* parentLayout = button->parentWidget()->layout();
I assume button is a child of the widget which contains the layout which contains button. button->parentWidget() returns a pointer to the widget of the button's parent and ->layout() returns the pointer to the layout of the parent.
After some exploration, I found a "partial" solution to the problem.
If you are creating the layout and managing a widget with it, it is possible to retrieve this layout later in the code by using Qt's dynamic properties. Now, to use QWidget::setProperty(), the object you are going to store needs to be a registered meta type. A pointer to QHBoxLayout is not a registered meta type, but there are two workarounds. The simplest workaround is to register the object by adding this anywhere in your code:
Q_DECLARE_METATYPE(QHBoxLayout*)
The second workaround is to wrap the object:
struct Layout {
QHBoxLayout* layout;
};
Q_DECLARE_METATYPE(Layout)
Once the object is a registered meta type, you can save it this way:
QHBoxLayout* layout = new QHBoxLayout;
QWidget* widget = new QWidget;
widget->setProperty("managingLayout", QVariant::fromValue(layout));
layout->addWidget(widget);
Or this way if you used the second workaround:
QHBoxLayout* layout = new QHBoxLayout;
QWidget* widget = new QWidget;
Layout l;
l.layout = layout;
widget->setProperty("managingLayout", QVariant::fromValue(l));
layout->addWidget(widget);
Later when you need to retrieve the layout, you can retrieve it this way:
QHBoxLayout* layout = widget->property("managingLayout").value<QHBoxLayout*>();
Or like this:
Layout l = widget->property("managingLayout").value<Layout>();
QHBoxLayout* layout = l.layout;
This approach is applicable only when you created the layout. If you did not create the layout and set it, then there is not a simple way of retrieving it later. Also you will have to keep track of the layout and update the managingLayout property when necessary.
use widget.parent().layout() and search brute force (recursion included) is my only advice. Maybe you can search be "name".
Have you tried this? Don't forget to check for NULL.
QLayout *parent_layout = qobject_cast< QLayout* >( parent() );
If parent_layout equals NULL, then the parent widget is not a layout.
Have you tried QWidget::layout() ?