Qt: Can't set layout in QMainWindow - c++

I am trying to set my layout (using setLayout()) in my mainwindow. It does not show anything on launch:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0)
{
QVBoxLayout *vBoxLayout = new QVBoxLayout;
{
QPushButton *pushButton = new QPushButton(tr("A button"));
vBoxLayout->addWidget(pushButton);
}
setLayout(vBoxLayout);
}
};

You need to change the last two lines of code to be the following:
QWidget *widget = new QWidget();
widget->setLayout(VBoxLayout);
setCentralWidget(widget);
//VBoxLayout->addWidget(new QLayout);
//setLayout(VBoxLayout);
The QMainWindow is a special case. You set the contents of this widget by putting the layout in a new QWidget and then setting that as the central widget.See this answer also.

Related

problem with SIGNAL SLOT new notation for QAbstractButton

I am writing a small utility composed by :
1) 4 QToolBar
2) 1 QToolBox
3) 1 QMenu
4) 1 QGraphicsView
I have some buttons on the QToolBox, each button represents a grid with different spacing.
Everytime a user clicks a button on the QToolBox the spacing on the QGraphicsScene` changes.
I use daily the new notation and never had any problems with it until I had to use an "abstract" entity such as the QAbstractButton approach.
the problem I have is that I don't seem to properly set the connection signal/slot of the QAbstractButton:
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void backgroundButtonClicked(QAbstractButton *button);
private:
void createToolBox();
QButtonGroup *buttonGroup;
QButtonGroup *backgroundButtonGroup;
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
createToolBox();
scene = new DiagramScene(itemMenu,this);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(toolBox);
view = new QGraphicsView(scene);
QWidget *widget = new QWidget;
widget->setLayout(layout);
setCentralWidget(widget);
}
void MainWindow::backgroundButtonClicked(QAbstractButton *button)
{
QList<QAbstractButton*> buttons = backgroundButtonGroup->buttons();
foreach (QAbstractButton *myButton, buttons) {
if(myButton != button)
button->setChecked(false);
}
QString text = button->text();
if(text == tr("Blue Grid"))
scene->setBackgroundBrush(QPixmap(":/images/background1.png"));
else if(text == tr("White Grid"))
scene->setBackgroundBrush(QPixmap(":/images/background2.png"));
else if(text == tr("Gray Grid"))
scene->setBackgroundBrush(QPixmap(":/images/background3.png"));
else
scene->setBackgroundBrush(QPixmap(":/images/background4.png"));
scene->update();
view->update();
}
void MainWindow::createToolBox()
{
buttonGroup = new QButtonGroup(this);
buttonGroup->setExclusive(false);
QGridLayout *layout = new QGridLayout;
layout->addWidget(createCellWidget(tr("Conditional"), DiagramItem::Conditional), 0, 0);
layout->addWidget(createCellWidget(tr("Process"), DiagramItem::Step), 0, 1);
layout->addWidget(createCellWidget(tr("Input/Output"), DiagramItem::Io), 1, 0);
QToolButton *textButton = new QToolButton;
textButton->setCheckable(true);
buttonGroup->addButton(textButton, InsertTextButton);
textButton->setIcon(QIcon(QPixmap(":/images/textpointer.png")));
textButton->setIconSize(QSize(50, 50));
QWidget *itemWidget = new QWidget;
itemWidget->setLayout(layout);
backgroundButtonGroup = new QButtonGroup(this);
// This is my first attempt but it does not work:
QObject::connect(backgroundButtonGroup, &QAbstractButton::clicked, this, &QAbstractButton::backgroundButtonClicked());
}
Different options I tried are:
1) via static_cast<> trying to cast it into the QAbstractButton as shown below:
QObject::connect(static_cast<QAbstractButton*>(backgroundButtonGroup), this, static_cast<QAbstractButton>(backgroundButtonClicked(void)));
2) Also I tried the following according to official documentation but that also didn't work:
QObject::connect(backgroundButtonGroup, &QAbstractButton::clicked, this, &QAbstractButton::backgroundButtonClicked);
Adding to that I was digressing towards the following structure below (heading to Q_INVOKE) but I am afraid I was over complicating the issue, but just wanted to include the additional solution I was trying to explore:
const bool connected = connect(sender, &Sender::aSignal,
receiver, &Receiver::aSlot);
Q_ASSERT(connected);
Q_UNUSED(connected);
Thanks for pointing to the right direction for solving this issue.
You have the following errors:
QButtonGroup does not have the clicked signal but buttonClicked.
You must not use ().
The syntax in general is: obj, & Class_of_obj, in your case backgroundButtonGroup is QButtonGroup and this is MainWindow so preliminarily the syntax is:
QObject::connect(backgroundButtonGroup, &QButtonGroup::buttonClicked, this, &MainWindow::backgroundButtonClicked);
But buttonClicked is overload then you must use QOverload to indicate the signature.
Considering the above, the solution is:
QObject::connect(backgroundButtonGroup, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), this, &MainWindow::backgroundButtonClicked);
I recommend you check:
the QButtonGroup docs where it shows the example of how to make the connection.
In addition to New Signal Slot Syntax that indicates the various cases

QGridLayout addWidget(CustomWidget) is not working

I'm using the QGridLayout in my code, and want to add my custom widget to gridlayout, it's not working with addWidget(CustomWidget*).
This is runing on Windows10 with Visual Studio 2013 and Qt5.6.3.
// *.h
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = Q_NULLPTR);
private:
Ui::MainWindow ui;
};
class CustomWidget : public QWidget {
Q_OBJECT
public:
CustomWidget(QWidget *parent = Q_NULLPTR) : QWidget(parent) {}
~CustomWidget() {}
};
// *.cpp
// when i use CustomWidget
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
ui.setupUi(this);
QWidget *grid = new QWidget(this);
grid->setStyleSheet("background:pink;");
QGridLayout *layout = new QGridLayout(grid);
layout->setMargin(0);
layout->setSpacing(0);
grid->setLayout(layout);
grid->setGeometry(500, 150, 240, 180);
// following code is not working, when run this program,
// i can only see the 'grid' widget with pink background
CustomWidget *w = new CustomWidget(grid);
w->setStyleSheet("background:red;");
layout->addWidget(w, 0, 0);
}
// but if i use QWidget
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
ui.setupUi(this);
QWidget *grid = new QWidget(this);
grid->setStyleSheet("background:pink;");
QGridLayout *layout = new QGridLayout(grid);
layout->setMargin(0);
layout->setSpacing(0);
grid->setLayout(layout);
grid->setGeometry(500, 150, 240, 180);
// following code is working, when run this program,
// i can see the 'w' widget with red background
QWidget *w = new QWidget(grid);
w->setStyleSheet("background:red;");
layout->addWidget(w, 0, 0);
}
As it is said in the Qt's stylesheets reference, applying CSS styles to custom widgets inherited from QWidget requires reimplementing paintEvent() in that way:
void CustomWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
Although for what it says in the documentation, without doing it your custom widgets will support only the background, background-clip and background-origin properties, for what might be a bug.
You can read about it here: Qt Stylesheets reference in the section "List of Stylable Widgets" -> QWidget.

Why Qt::AlignTop doesn't work in QVBoxLayout that I use like main layout?

I have simple class that inherits QDialog, I add dynamically elements
and my elements are located in the center, but I want to add them at the top.
class CustomDialog : public QDialog {
Q_OBJECT
private:
QVBoxLayout *mainLayout;
CustomDialog()
{
mainLayout = new QVBoxLayout();
setLayout(mainLayout);
}
public:
void update()
{
QLabel* label = new QLabel("some text");
QVBoxLayout *verLayout = new QVBoxLayout;
verLayout->addStretch();
verLayout->setAlignment(Qt::AlignTop);
verLayout->addWidget(label, Qt::AlignTop);
mainLayout->setAlignment(Qt::AlignTop);
mainLayout->addLayout(verLayout, Qt::AlignTop);
}
};
What am I doing wrong? and why my dynamically added elements always in center?
I understand that you want to place it and that the top is shown, so you could use QSpacerItem to push it.
class CustomDialog : public QDialog {
Q_OBJECT
QVBoxLayout *mainLayout;
public:
CustomDialog(QWidget *parent=0): QDialog(parent)
{
mainLayout = new QVBoxLayout(this);
QSpacerItem *verticalSpacer = new QSpacerItem(20, 217, QSizePolicy::Minimum, QSizePolicy::Expanding);
mainLayout->addItem(verticalSpacer);
addWidgets("1");
addWidgets("2");
}
private:
void addWidgets(const QString &text)
{
QLabel* label = new QLabel(text);
QVBoxLayout *verLayout = new QVBoxLayout;
verLayout->addStretch();
verLayout->setAlignment(Qt::AlignTop);
verLayout->addWidget(label, Qt::AlignTop);
mainLayout->setAlignment(Qt::AlignTop);
mainLayout->insertLayout(mainLayout->count()-1, verLayout);
}
};
Or if you want it to have a reverse order you must insert it in the first position with:
mainLayout->insertLayout(0, verLayout);
Note: The use of addLayout is incorrect since the second parameter is stretch.

How to show a QMainWindow inside a QDialog

I am trying to show a QMainWindow inside a QDialog but the former does not appear.
I have subclassed QDialog, let's call it myDialog
A small example:
myDialog(QWidget *p_parent) : QDialog(p_parent)
{
QGridLayout *p_dialogLayout = new QGridLayout(this);
QMainWindow *p_MainWindow = new QMainWindow(this);
QLabel *p_label = new QLabel(this);
p_MainWindow->setCentralWidget(p_label);
QPushButton *p_cancel = new QPushButton("Cancel", this);
p_dialogLayout ->addWidget(p_MainWindow, 0, 0);
p_dialogLayout ->addWidget(p_cancel, 1, 0);
}
If I execute the dialog, I only see the button, not the embeded QMainWindow.
If i force to show the qmainwindow, the mainwindow is shown in another window.
Use QLayout::setMenuBar to add a toolbar to your dialog.
#include <QtWidgets>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = nullptr) : QDialog(parent)
{
resize(600, 400);
setLayout(new QHBoxLayout);
QToolBar *toolbar = new QToolBar;
toolbar->addAction("Action one");
toolbar->addAction("Action two");
layout()->setMenuBar(toolbar);
layout()->addWidget(new QLabel("Label one"));
layout()->addWidget(new QLabel("Label two"));
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
#include "main.moc"
I don't think this is supported by the Qt framework, according to their documentation from here, it's intended to be used only once in an application.
My suggestion would be to take all your MainWindow implementation in a separate form (inheriting QWidget), and just add that form to your MainWindow in the constructor using something like p_MainWindow->setCentralWidget(p_YourNewForm);
I have been able to do it.
The trick is to construct the QMainWindow without a parent, and then apply the .setParent
Here is how:
myDialog(QWidget *p_parent) : QDialog(p_parent)
{
QGridLayout *p_dialogLayout = new QGridLayout(this);
QMainWindow *p_MainWindow = new QMainWindow(); //Without a parent
QLabel *p_label = new QLabel(this);
p_MainWindow->setCentralWidget(p_label);
QPushButton *p_cancel = new QPushButton("Cancel", this);
p_dialogLayout ->addWidget(p_MainWindow, 0, 0);
p_dialogLayout ->addWidget(p_cancel, 1, 0);
p_MainWindow->setParent(this); //Set the parent, to delete the MainWindow when the dialog is deleted.
}

How to update a QTreeWidget by Clicking on QPushbutton

I'm developing a Qt app in C++
I have create a layout with button bar, TreeView...
The Treeview is defined in my MainWindow.cpp
MainWindow::MainWindow()
{
setWindowTitle(QString::fromUtf8("PULS"));
resize(800,600);
setUnifiedTitleAndToolBarOnMac(true);
createDeviceStatusBar();
createSectionBar();
createTreeView();
QWidget *MainWindowWidget = new QWidget();
QVBoxLayout *MainWindowLayout = new QVBoxLayout(MainWindowWidget);
BrowserSection = new QGroupBox();
QWidget *BrowserWidget = new QWidget();
QHBoxLayout *BrowserLayout = new QHBoxLayout(BrowserWidget);
BrowserLayout->addWidget(SectionBar);
BrowserLayout->addWidget(TreeSection);
BrowserSection->setLayout(BrowserLayout);
MainWindowLayout->addWidget(DeviceSection);
MainWindowLayout->addWidget(BrowserSection);
setCentralWidget(MainWindowWidget);
show();
}
The createSectionBar() is a layout defined as below:
void MainWindow::createSectionBar()
{
SectionBar = new QGroupBox();
QVBoxLayout *SectionBarlayout = new QVBoxLayout;
SectionBarlayout->setContentsMargins(QMargins(0,0,0,0));
MusicButton = new QPushButton();
MusicButton->setFixedSize(110,150);
MusicButton->setIcon(QIcon(":/images/music.png"));
MusicButton->setIconSize(QSize(90,144));
MusicButton->setFlat(true);
MusicButton->setAutoFillBackground(true);
connect(MusicButton, SIGNAL(clicked()), this, SLOT(MusicTreeFile()));
SectionBarlayout->addWidget(MusicButton);
SectionBar->setLayout(SectionBarlayout);
}
The createTreeView() is defined as below to enable TreeView and Items.
void MainWindow::createTreeView()
{
TreeSection = new QGroupBox();
QVBoxLayout *TreeLayout = new QVBoxLayout;
MyTree = new TreeWidget();
MyTree->setSortingEnabled(true);
MyTree->setColumnWidth(0, 400);
QTreeWidgetItem* headerItem = new QTreeWidgetItem();
headerItem->setText(0,QString("File Name"));
headerItem->setText(1,QString("Size (Bytes)"));
headerItem->setText(2,QString("Date"));
MyTree->setHeaderItem(headerItem);
MyTree->setAutoFillBackground(true);
TreeLayout->addWidget(MyTree);
TreeSection->setLayout(TreeLayout);
}
What I need is to find a way to file the MyTree with
while (file != NULL && file->parent_id == folder_parent) {
QTreeWidgetItem* item = new QTreeWidgetItem();
int i;
LIBMTP_file_t *oldfile;
item->setText(0,file->filename);
Tree->addTopLevelItem(item);
....
}
here is the header file:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
protected:
private slots:
void MusicTreeFile();
private:
void createSectionBar();
void createTreeView();
void createDeviceStatusBar();
QGroupBox *SectionBar;
QGroupBox *TreeSection;
QGroupBox *DeviceSection;
QGroupBox *BrowserSection;
QPushButton *MusicButton;
TreeWidget *MyTree;
};
but it needs to be done only when clicking on MusicPushButton, I have already connected the MusicTreeFile() to the PushButton() action. but how to access to MyTree as it's also defined in another class..
You do not connect a signal to a class. You connect it to an instance of a class. And both of your instances are defined in MainWindow. So after both widgets are created you can call
QObject::connect(this->MusicButton, SIGNAL(clicked()), this->MyTree, SLOT(slot_name()));
With slot_name being your function
TreeWidget::slot_name{
while (file != NULL && file->parent_id == folder_parent) {
....
}
}