Qt: QGridLayout refusing to add widgets - qt

So i have been trying to use QGridLayout for a while and it keeps giving me the error:
"error: no matching function for call to 'QLayout::addWidget(QScrollArea*, int, int)". I have no idea what am I doing wrong. Here is the part of the code which seems to be causing the error:
QScrollArea * setScrollArea(QWidget * w)
{
w->setStyleSheet("background-color:white;");
QScrollArea * scrollArea = new QScrollArea;
scrollArea->setWidgetResizable(true);
scrollArea->setWidget(w);
return scrollArea;
} ^
.
.
.
shower = new QWidget;
shower->setLayout(new QGridLayout);
shower->layout()->addWidget(setScrollArea(upWindow), 0, 0);
shower->layout()->addWidget(setScrollArea(downWindow), 1, 0);
Does anyone have an idea, what am i doing wrong?

QWidget::layout() returns a simple QLayout that has no function addWidget( QWidget *, int, int ).
To use the QGridLayout functionality, do the following:
shower = new QWidget;
QGridLayout * layout = new QGridLayout;
layout->addWidget(setScrollArea(upWindow), 0, 0);
layout->addWidget(setScrollArea(downWindow), 1, 0);
shower->setLayout(layout);

Related

How to move QWidget in QAbstractItemView?

I have a QComboBox, which has many items on it:
combo->addItem("def");
combo->addItem("abc");
Now I would like to add QWidget to one of my item, for example:
QPushButton *button = new QPushButton;
button->setStyleSheet("QPushButton {background:red}");
button->setFixedSize(10,10);
QModelIndex index = combo->model()->index(0,0);
combo->view()->setIndexWidget(index, button);
I set button's size to 10x10 ( of course my QComboBox is bigger ). And I would like to move this button to other place ( picture ).
You can try using layout
QPushButton *button = new QPushButton;
button->setStyleSheet("QPushButton {background:red}");
button->setFixedSize(10,10);
auto widget = new QWidget{this};
auto layout = new QHBoxLayout{widget};
layout->setContentsMargins(0, 0, 0, 0);
layout->addStretch();
layout->addWidget(button);
QModelIndex index = combo->model()->index(0,0);
combo->view()->setIndexWidget(index, widget);

Designing GUI programmatically - good practice for nested layouts and multiple widgets (Qt)

I am interested in better understanding Qt and for that I would like to see how a relatively complex example of nested layouts and multiples widgets GUI is done solely programmatically; i.e. without the use of Qt Creator's Design.
I have seen several example code demonsrating only very simple layouts and -almost- always without utilising the header files; in fact most of the examples I have seen, dump the code in the main. It is my understanding (please correct me if I am wrong) that good programming practices dictate that you separate the design in a separate class (e.g. mainwindow) and in the main.cpp you merely invoke and show that main window. Perhaps, most crucially, all the definitions of widgets, layouts etc. should be defined in the header file and then invoked and customised in the mainwindow.cpp.
A fine exammple of good programming practices programmatically but for a relatively simple GUI desing can be seen here.
If anyone can provide online resource(s) where non-simple code examples of good programmatical GUI designs that show how to properly define and customise nested layouts and widgets that would be very much appreciated.
Alternatively, here is a straightforward programmatical GUI design example for which it would be great to derive code (without the Designer) for me to study and gain understanding from:
note: my focus is only on the nested layouts, multiple widgets and the where and how these should be defined and invoked on the different Qt source files.
where the nested layout and widget specifics can be seen here:
with the actual GUI result as seen here:
UPDATE
As Mike suggested in the comments section, from the uic the code for what the Designer does can be seen, which in my case for the example mentioned above is the following
>uic mainwindow.ui outputs:
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/QFrame>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QProgressBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QSpacerItem>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
{
public:
QWidget *centralWidget;
QVBoxLayout *verticalLayout_3;
QFrame *top_frame;
QGridLayout *gridLayout;
QSpacerItem *horizontalSpacer;
QProgressBar *progressBar_2;
QProgressBar *progressBar_4;
QSpacerItem *verticalSpacer;
QSpacerItem *horizontalSpacer_2;
QPushButton *pushButton_1;
QProgressBar *progressBar_1;
QPushButton *pushButton_2;
QPushButton *pushButton_3;
QProgressBar *progressBar_3;
QPushButton *pushButton_4;
QFrame *bottom_frame;
QHBoxLayout *horizontalLayout;
QFrame *frame;
QFormLayout *formLayout;
QLabel *label_1;
QLabel *label_2;
QSpacerItem *verticalSpacer_2;
QLineEdit *lineEdit;
QLineEdit *lineEdit_2;
QFrame *frame_2;
QHBoxLayout *horizontalLayout_2;
QLabel *label_3;
QSpacerItem *horizontalSpacer_3;
QLabel *label_4;
void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QStringLiteral("MainWindow"));
MainWindow->resize(878, 632);
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QStringLiteral("centralWidget"));
verticalLayout_3 = new QVBoxLayout(centralWidget);
verticalLayout_3->setSpacing(6);
verticalLayout_3->setContentsMargins(11, 11, 11, 11);
verticalLayout_3->setObjectName(QStringLiteral("verticalLayout_3"));
top_frame = new QFrame(centralWidget);
top_frame->setObjectName(QStringLiteral("top_frame"));
QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(top_frame->sizePolicy().hasHeightForWidth());
top_frame->setSizePolicy(sizePolicy);
top_frame->setFrameShape(QFrame::StyledPanel);
top_frame->setFrameShadow(QFrame::Raised);
gridLayout = new QGridLayout(top_frame);
gridLayout->setSpacing(6);
gridLayout->setContentsMargins(11, 11, 11, 11);
gridLayout->setObjectName(QStringLiteral("gridLayout"));
horizontalSpacer = new QSpacerItem(30, 20, QSizePolicy::Fixed, QSizePolicy::Minimum);
gridLayout->addItem(horizontalSpacer, 0, 2, 1, 1);
progressBar_2 = new QProgressBar(top_frame);
progressBar_2->setObjectName(QStringLiteral("progressBar_2"));
progressBar_2->setValue(24);
gridLayout->addWidget(progressBar_2, 2, 3, 1, 1);
progressBar_4 = new QProgressBar(top_frame);
progressBar_4->setObjectName(QStringLiteral("progressBar_4"));
progressBar_4->setValue(24);
gridLayout->addWidget(progressBar_4, 2, 5, 1, 1);
verticalSpacer = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed);
gridLayout->addItem(verticalSpacer, 1, 1, 1, 1);
horizontalSpacer_2 = new QSpacerItem(10, 20, QSizePolicy::Fixed, QSizePolicy::Minimum);
gridLayout->addItem(horizontalSpacer_2, 0, 4, 1, 1);
pushButton_1 = new QPushButton(top_frame);
pushButton_1->setObjectName(QStringLiteral("pushButton_1"));
gridLayout->addWidget(pushButton_1, 0, 0, 1, 1);
progressBar_1 = new QProgressBar(top_frame);
progressBar_1->setObjectName(QStringLiteral("progressBar_1"));
progressBar_1->setValue(24);
gridLayout->addWidget(progressBar_1, 0, 3, 1, 1);
pushButton_2 = new QPushButton(top_frame);
pushButton_2->setObjectName(QStringLiteral("pushButton_2"));
gridLayout->addWidget(pushButton_2, 0, 1, 1, 1);
pushButton_3 = new QPushButton(top_frame);
pushButton_3->setObjectName(QStringLiteral("pushButton_3"));
gridLayout->addWidget(pushButton_3, 2, 0, 1, 1);
progressBar_3 = new QProgressBar(top_frame);
progressBar_3->setObjectName(QStringLiteral("progressBar_3"));
progressBar_3->setValue(24);
gridLayout->addWidget(progressBar_3, 0, 5, 1, 1);
pushButton_4 = new QPushButton(top_frame);
pushButton_4->setObjectName(QStringLiteral("pushButton_4"));
gridLayout->addWidget(pushButton_4, 2, 1, 1, 1);
verticalLayout_3->addWidget(top_frame);
bottom_frame = new QFrame(centralWidget);
bottom_frame->setObjectName(QStringLiteral("bottom_frame"));
bottom_frame->setFrameShape(QFrame::StyledPanel);
bottom_frame->setFrameShadow(QFrame::Raised);
horizontalLayout = new QHBoxLayout(bottom_frame);
horizontalLayout->setSpacing(6);
horizontalLayout->setContentsMargins(11, 11, 11, 11);
horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
frame = new QFrame(bottom_frame);
frame->setObjectName(QStringLiteral("frame"));
frame->setFrameShape(QFrame::StyledPanel);
frame->setFrameShadow(QFrame::Raised);
formLayout = new QFormLayout(frame);
formLayout->setSpacing(6);
formLayout->setContentsMargins(11, 11, 11, 11);
formLayout->setObjectName(QStringLiteral("formLayout"));
label_1 = new QLabel(frame);
label_1->setObjectName(QStringLiteral("label_1"));
formLayout->setWidget(0, QFormLayout::LabelRole, label_1);
label_2 = new QLabel(frame);
label_2->setObjectName(QStringLiteral("label_2"));
formLayout->setWidget(1, QFormLayout::LabelRole, label_2);
verticalSpacer_2 = new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding);
formLayout->setItem(2, QFormLayout::LabelRole, verticalSpacer_2);
lineEdit = new QLineEdit(frame);
lineEdit->setObjectName(QStringLiteral("lineEdit"));
QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Expanding);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(lineEdit->sizePolicy().hasHeightForWidth());
lineEdit->setSizePolicy(sizePolicy1);
formLayout->setWidget(3, QFormLayout::SpanningRole, lineEdit);
lineEdit_2 = new QLineEdit(frame);
lineEdit_2->setObjectName(QStringLiteral("lineEdit_2"));
sizePolicy1.setHeightForWidth(lineEdit_2->sizePolicy().hasHeightForWidth());
lineEdit_2->setSizePolicy(sizePolicy1);
formLayout->setWidget(4, QFormLayout::LabelRole, lineEdit_2);
horizontalLayout->addWidget(frame);
frame_2 = new QFrame(bottom_frame);
frame_2->setObjectName(QStringLiteral("frame_2"));
frame_2->setFrameShape(QFrame::StyledPanel);
frame_2->setFrameShadow(QFrame::Raised);
horizontalLayout_2 = new QHBoxLayout(frame_2);
horizontalLayout_2->setSpacing(6);
horizontalLayout_2->setContentsMargins(11, 11, 11, 11);
horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2"));
label_3 = new QLabel(frame_2);
label_3->setObjectName(QStringLiteral("label_3"));
horizontalLayout_2->addWidget(label_3);
horizontalSpacer_3 = new QSpacerItem(40, 20, QSizePolicy::Fixed, QSizePolicy::Minimum);
horizontalLayout_2->addItem(horizontalSpacer_3);
label_4 = new QLabel(frame_2);
label_4->setObjectName(QStringLiteral("label_4"));
horizontalLayout_2->addWidget(label_4);
frame->raise();
frame->raise();
label_3->raise();
label_4->raise();
horizontalLayout->addWidget(frame_2);
verticalLayout_3->addWidget(bottom_frame);
MainWindow->setCentralWidget(centralWidget);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0));
pushButton_1->setText(QApplication::translate("MainWindow", "PushButton_1", 0));
pushButton_2->setText(QApplication::translate("MainWindow", "PushButton_2", 0));
pushButton_3->setText(QApplication::translate("MainWindow", "PushButton_3", 0));
pushButton_4->setText(QApplication::translate("MainWindow", "PushButton_4", 0));
label_1->setText(QApplication::translate("MainWindow", "TextLabel_1", 0));
label_2->setText(QApplication::translate("MainWindow", "TextLabel_2", 0));
label_3->setText(QApplication::translate("MainWindow", "TextLabel_3", 0));
label_4->setText(QApplication::translate("MainWindow", "TextLabel_4", 0));
} // retranslateUi
};
namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_MAINWINDOW_H
Below is a transformation that you might wish to perform. I've included a shortened version of your code to demonstrate.
Start with uic output.
class Ui_MainWindow
{
public:
QWidget *centralWidget;
QVBoxLayout *verticalLayout_3;
QFrame *top_frame;
};
Put all members of Ui_Foo into Foo itself, retaining their order.
class MainWindow : public QMainWindow
{
QWidget *centralWidget;
QVBoxLayout *verticalLayout_3;
QFrame *top_frame;
};
Change member types from pointers to values.
class MainWindow : public QMainWindow
{
QWidget centralWidget;
QVBoxLayout verticalLayout_3;
QFrame top_frame;
...
};
Initialize layouts in the class declaration by giving them the widgets they act on. This makes the structure of the user interface all obvious from the header itself:
class MainWindow : public QMainWindow
{
QWidget centralWidget;
QVBoxLayout verticalLayout_3{&centralWidget};
QFrame top_frame;
...
};
Add code from setupUi to the constructor's body, changing it appropriately to act on values, not pointers:
MainWindow::MainWindow(QWidget * parent) : QWidget{parent}
{
setObjectName(QStringLiteral("MainWindow"));
resize(878, 632);
centralWidget.setObjectName(QStringLiteral("centralWidget"));
verticalLayout_3.setSpacing(6);
verticalLayout_3.setContentsMargins(11, 11, 11, 11);
verticalLayout_3.setObjectName(QStringLiteral("verticalLayout_3"));
top_frame.setObjectName(QStringLiteral("top_frame"));
QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(top_frame->sizePolicy().hasHeightForWidth());
top_frame.setSizePolicy(sizePolicy);
top_frame.setFrameShape(QFrame::StyledPanel);
top_frame.setFrameShadow(QFrame::Raised);
...
}

Getting QTableWidgetItem out of cellWidget()'s QCheckBox

I'm storing QCheckBox in QTableWidget, in following way:
QCheckBox *checkBox = new QCheckBox();
QWidget *widget = new QWidget();
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->addWidget(checkBox);
layout->setAlignment(Qt::AlignCenter);
layout->setContentsMargins(0,0,0,0);
widget->setLayout(layout);
tableWidget->setCellWidget(row, 2, widget);
Then, I catch stateChanged() of the checkBox:
connect( checkBox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxStateChanged(int)) );
void MainWindow::checkBoxStateChanged(int)
{
QCheckBox * box = qobject_cast< QCheckBox * >( sender() );
if( !box ) {
return;
}
}
Now, I can get to QTableWidget – it is box->parent()->parent()->parent(). Object before that, i.e. box->parent()->parent(), is qt_scrollarea_viewport (that's objectName()). I've searched children of the "viewport", and there's 16 QWidgets – the number of rows in my table. However, their children are only QHBoxLayout and QCheckBox. There apparently is no reference to QTableWidgetItem – it looks like if I were in some parallel object hierarchy, and QTableWidgetItem is in other hierarchy. Is that true? How to get the item?
See this question: How to work with signals from QTableWidget cell with cellWidget set
Adapted to you case:
void MainWindow::checkBoxStateChanged(int)
{
QCheckBox * box = qobject_cast< QCheckBox * >( sender() );
if (box)
{
int row = box->property("row").toInt();
int column = box->property("column").toInt();
QTableWidgetItem* item = tableWidget->item(row, column);
}
}

qt vertical and horizontal layouts inside gridlayout?

I am new to Qt App Development. I am attaching two screen shots, one is the desired ui and other is created one using code.
I believe my code will explain things, instead of my typing here and confusing all my friends here. What needs to be changed /updated?
/* HEADER FILE */
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
// Ui::Widget *ui;
};
#endif // WIDGET_H
/*Implementation Code */
#include "widget.h"
#include "ui_widget.h"
#include<QGridLayout>
#include<QVBoxLayout>
#include<QHBoxLayout>
Widget::Widget(QWidget *parent) :
QWidget(parent)//,
//ui(new Ui::Widget)
{
this->setGeometry(50,50,850,650);
QGridLayout *gridLayout= new QGridLayout(this);
setLayout(gridLayout);
QVBoxLayout *vLayout = new QVBoxLayout(this);
QHBoxLayout *hLayout = new QHBoxLayout(this);
//QWidget *tmp1 = new QWidget(this);
//QWidget *tmp2 = new QWidget(this);
// tmp1->setLayout(vLayout);
// tmp2->setLayout(hLayout);
gridLayout->addLayout(vLayout,0,3);
gridLayout->addLayout(hLayout,3,0);
//gridLayout->addWidget(tmp1,0,3,1,1);
//gridLayout->addWidget(tmp2,3,0,1,1);
QWidget *w = new QWidget(this);
QWidget *w1 = new QWidget(this);
QWidget *w2 = new QWidget(this);
QWidget *w3 = new QWidget(this);
QWidget *w11 = new QWidget(this);
QWidget *w22 = new QWidget(this);
QWidget *w33 = new QWidget(this);
QWidget *w4 = new QWidget(this);
QWidget *w5 = new QWidget(this);
w->setStyleSheet("background-color:rgb(0,0,0);");
w1->setStyleSheet("background-color:rgb(255,0,0);");
w2->setStyleSheet("background-color:rgb(255,0,255);");
w3->setStyleSheet("background-color:rgb(0,255,0);");
w11->setStyleSheet("background-color:rgb(255,0,0);");
w22->setStyleSheet("background-color:rgb(255,0,255);");
w33->setStyleSheet("background-color:rgb(0,255,0);");
w4->setStyleSheet("background-color:rgb(0,0,255);");
w5->setStyleSheet("background-color:rgb(255,255,0);");
vLayout->addWidget(w1);
vLayout->addWidget(w2);
vLayout->addWidget(w3);
vLayout->addWidget(w11);
vLayout->addWidget(w22);
vLayout->addWidget(w33);
hLayout->addWidget(w4);
hLayout->addWidget(w5);
gridLayout->addWidget(w,0,0,2,2);
show();
}
Widget::~Widget()
{
//delete ui;
}
The code doesn't look so bad. In my opinion, you just need to tweak the parameters to your addWidget/addLayout calls. Think about what your grid-layout should be like, and then choose the parameters accordingly.
I would try it like this:
// Desired grid layout is of size 2x2:
// .................
// . row0 . row0 .
// . col0 . col1 .
// .................
// . row1 . row1 .
// . col0 . col1 .
// .................
// Big widget at row 0, column 0
gridLayout->addWidget (w, 0, 0);
// "Horizontal group" at row 1, column 0
gridLayout->addLayout (hLayout, 1, 0);
// "Vertical group" at rows 0+1 (i.e. rowspan 2), column 1
gridLayout->addLayout (vLayout, 0, 1, 2, 1);
Does that work better (I havent tried it out myself)?

Qt widgets not placed correctly

I've subclassed QWidget and defined constructor this way:
LoupingWidget::LoupingWidget(QWidget *parent): QWidget(parent)
{
QGroupBox *topGroupBox = new QGroupBox(this);
QGraphicsView *xRGBPlot = new QGraphicsView(this);
QGraphicsView *yRGBPlot = new QGraphicsView(this);
QGraphicsView *loupe = new QGraphicsView(this);
QSlider *slider = new QSlider(this);
QGridLayout *boxGLayout = new QGridLayout;
boxGLayout->addWidget(xRGBPlot, 0, 0);
boxGLayout->addWidget(slider, 0, 1);
boxGLayout->addWidget(loupe, 1, 0);
boxGLayout->addWidget(yRGBPlot, 1, 1);
topGroupBox->setLayout(boxGLayout);
}
Next, I am trying to add it in a QDialog:
Window::Window(QWidget *parent): QDialog(parent)
{
LoupingWidget *firstLoupindWidget = new LoupingWidget(this);
LoupingWidget *secondLoupindWidget = new LoupingWidget(this);
// QGraphicsView *mainPicture = new QGraphicsView(this);
QGridLayout *gridLayout = new QGridLayout;
// gridLayout->addWidget(mainPicture, 0, 0);
gridLayout->addWidget(firstLoupindWidget, 1, 0);
gridLayout->addWidget(secondLoupindWidget, 1, 1);
setLayout(gridLayout);
}
When this two lines are commented out, two widgets are placed horizontally.
And that's good, but when I uncomment lines with another QGraphicsViews, it fills entire window.
What am I doing wrong?
LoupingWidget doesn't have a layout, so when it's added to another layout, layout can't resize it according to its contents. You need to create another layout (e.g. QGridLayout) in LoupingWidget constructor, add topGroupBox to the layout and set the layout as LoupingWidget's layout.

Resources