I would like to create custom QT dialog (non-modal). Problem with my implementation is that it shows only dialog window with title, and no widgets that I've added to it.
Code below (I've ommited most of it, added just dialog and main window parts).
MainWindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
/// some other stuff
private:
std::unique_ptr<ui::DialogAddUpdateItem> addItemDialog;
/// some other stuff
}
MainWindow.cpp
/// some stuff
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
/// some stuff
addItemButton = new QPushButton(tr("Add item"));
QObject::connect(addItemButton, &QPushButton::pressed, this, &MainWindow::openAddItemDialog);
navLay->addWidget(addItemButton);
addItemDialog = make_unique<ui::DialogAddUpdateItem>(this);
/// some stuff
}
void MainWindow::openAddItemDialog() {
addItemDialog->show();
//addItemDialog->raise(); does not work with or without those functions
//addItemDialog->activateWindow();
//QApplication::processEvents();
}
DialogAddUpdateItem.h
namespace ui {
class DialogAddUpdateItem : public QDialog
{
Q_OBJECT
public:
DialogAddUpdateItem(QWidget *parent = nullptr);
private:
QPushButton *buttonAcc, *buttonRevert, *buttonCancel;
QGroupBox *centralWidget, *buttonsWidget;
QLabel *labelName, *labelDescription;
QLineEdit *textName;
QPlainTextEdit *textDescription;
}
}
DialogAddUpdateItem.cpp
namespace ui {
DialogAddUpdateItem::DialogAddUpdateItem(QWidget *parent) : QDialog(parent)
{
if (!item) {
setWindowTitle(tr("New object"));
}
centralWidget = new QGroupBox;
QHBoxLayout *itemLay = new QHBoxLayout;
centralWidget->setLayout(itemLay);
labelName = new QLabel(tr("Name"));
itemLay->addWidget(labelName);
textName = new QLineEdit;
if (item) {
textName->setText(QString::fromStdString(item->getName()));
}
itemLay->addWidget(textName);
labelDescription = new QLabel(tr("Description"));
if (item) {
textDescription = new QPlainTextEdit(QString::fromStdString(item->getDescription()));
} else {
textDescription = new QPlainTextEdit;
}
itemLay->addWidget(textDescription);
buttonAcc = new QPushButton(tr("Save"));
buttonAcc->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QObject::connect(buttonAcc, &QPushButton::clicked, this, &DialogAddUpdateItem::acceptItem);
buttonRevert = new QPushButton(tr("Revert"));
buttonRevert->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QObject::connect(buttonRevert, &QPushButton::clicked, this, &DialogAddUpdateItem::revertItem);
buttonCancel = new QPushButton(tr("Cancel"));
buttonCancel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QObject::connect(buttonCancel, &QPushButton::clicked, this, &DialogAddUpdateItem::cancelItem);
buttonsWidget = new QGroupBox;
itemLay->addWidget(buttonsWidget);
QVBoxLayout *buttonsLay = new QVBoxLayout;
buttonsLay->addWidget(buttonAcc);
buttonsLay->addWidget(buttonRevert);
buttonsLay->addWidget(buttonCancel);
}
}
In DialogAddUpdateItem.cpp the centralWidget has no parent, therefore it is not bound to anything and therefore not displayed. You should modify this:
centralWidget = new QGroupBox;
into this:
centralWidget = new QGroupBox(this);
Now the DialogAddUpdateItem will be the parent of the centralWidget and it should display it.
Also it seems like You are leaving some other widgets without a parent - it might cause trouble. For example the QLineEdit textName has this issue.
Related
I'm writing a qt program and trying to resize mainwindow when sub widget is hidden, but there's some difference in Linux and Windows, and I don't know the property way to adjust size in both.
Here's my minimum code:
// MainWindow
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QWidget *mainWidget = new QWidget(this);
QVBoxLayout *mainlayout = new QVBoxLayout(mainWidget);
QPushButton *hide = new QPushButton(mainWidget);
subwidget *sub = new subwidget(mainWidget);
mainlayout->addWidget(hide);
mainlayout->addWidget(sub);
connect(hide, &QPushButton::clicked, sub, &subwidget::onHide);
setCentralWidget(mainWidget);
adjustSize();
connect(hide, &QPushButton::clicked, this, [&] {
QTimer::singleShot(0, this, [&] { adjustSize(); });
});
}
// Widget
subwidget::subwidget(QWidget *parent)
: QWidget{parent}
{
QVBoxLayout *vlayout = new QVBoxLayout(this);
QPushButton *btn1 = new QPushButton();
btn2 = new QPushButton();
vlayout->addWidget(btn1);
vlayout->addWidget(btn2);
}
void subwidget::onHide()
{
btn2->hide();
}
When I set the timer interval to 1, mainwindow will be the adjusted size when btn2 is hidden in Linux, but it doesn't work in Windows. How can I adjust the mainwindow in windows?
PS: I have tried to add a signal when subwidget is hidden and connect it to adjustSize like connect(sub, &subwidget::hidden, this, [&] { adjustSize(); });, but it also doesn't work.
I have set a dark theme on my QWidget. In that widget I call a QDialog. The dialog appears in default palette which is light.
This is my custom dialog (Which in this case is for choosing colors for palette! Twisted right?) .cpp file:
#include "custompalettedialog.h"
CustomPaletteDialog::CustomPaletteDialog(QPalette palette, QWidget *parent) : QDialog(parent),
m_palette(palette)
{
QVBoxLayout* mainLayout = new QVBoxLayout(this);
mainLayout->setSpacing(0);
mainLayout->setMargin(0);
QFormLayout* mainFormLayout = new QFormLayout;
mainFormLayout->setHorizontalSpacing(0);
mainFormLayout->setVerticalSpacing(0);
mainLayout->addLayout(mainFormLayout);
for (int var = 0; var < QPalette::ColorRole::NColorRoles; ++var) {
QPushButton* bandButton = new QPushButton;
bandButton->setFlat(true);
bandButton->setAutoFillBackground(true);
QPalette pal = bandButton->palette();
pal.setColor(QPalette::Button, m_palette.color(static_cast<QPalette::ColorRole>(var)));
bandButton->setPalette(pal);
connect(bandButton, &QPushButton::clicked, this, [this, bandButton, var]() {
QColor color = QColorDialog::getColor();
if (color.isValid()) {
m_palette.setColor(static_cast<QPalette::ColorRole>(var), color);
QPalette pal = bandButton->palette();
pal.setColor(QPalette::Button, color);
bandButton->setPalette(pal);
}
});
mainFormLayout->addRow(QVariant::fromValue(static_cast<QPalette::ColorRole>(var)).toString(), bandButton);
}
QPushButton* doneButton = new QPushButton("Done");
connect(doneButton, &QPushButton::clicked, this, &QDialog::accept);
mainLayout->addWidget(doneButton);
}
QPalette CustomPaletteDialog::getPalette()
{
return m_palette;
}
QPalette CustomPaletteDialog::getPalette(bool* ok, const QPalette palette, QWidget *parent, const QString title)
{
CustomPaletteDialog* dialog = new CustomPaletteDialog(palette, parent);
dialog->setFont(parent->font());
dialog->setModal(true);
dialog->setWindowTitle(title);
dialog->exec();
QPalette pal = dialog->getPalette();
*ok = dialog->result();
dialog->deleteLater();
return pal;
}
and the .h file:
#ifndef CUSTOMPALETTEDIALOG_H
#define CUSTOMPALETTEDIALOG_H
#include <QDialog>
#include <QFormLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QColorDialog>
#include <QComboBox>
class CustomPaletteDialog : public QDialog
{
Q_OBJECT
public:
explicit CustomPaletteDialog(QPalette palette, QWidget *parent = nullptr);
static QPalette getPalette(bool* ok, const QPalette palette, QWidget *parent = nullptr, const QString title = QString());
QPalette getPalette();
private:
QPalette m_palette;
};
#endif // CUSTOMPALETTEDIALOG_H
I call the static method getPalette from a parent widget.
I have tried adding this:
dialog->setPalette(parent->palette());
before dialog->setFont(parent->font()); in that static method and not working. My question is how to propagate QPalette from parent QWidget to child QDialog?
This is how I used it:
QPushButton* paletteAddButton = new QPushButton("Add...");
mainGroupBoxLayout->addWidget(paletteAddButton);
connect(paletteAddButton, &QPushButton::clicked, this, [this, customThemeItemModel]() {
bool ok = false;
QPalette palette = CustomPaletteDialog::getPalette(&ok, this->palette(), this, "Chosse UI Palette");
if (ok) {
QStandardItem* item = new QStandardItem("newPalette");
item->setToolTip("Double Click to Change Name, Right Click for More");
item->setData(palette);
customThemeItemModel->appendRow(item);
saveThemes(customThemeItemModel);
}
});
I have a list of themes, user can add custom themes to that list.
I have an application that has 3 main widgets. I also have a pop-out QDockWidget. I'm trying to get the QDockWidget to dock into the right half of the bottom widget, but as you can see in the image below, the only places I can dock the window are on the edges of the application. How can I make it so that the QDockWidget window takes up the right half of the bottom widget?
Also, is there a way to have a QDockWidget be already docked upon opening the application instead of having it open separately in its own window?
EDIT: Using #Bertrand's answer below, here's what I wound up doing:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
void on_actionRestore_layout_triggered();
QMainWindow* m_rightSideWindow;
QDockWidget* m_dockWidget1;
QDockWidget* m_dockWidget2;
QDockWidget* m_dockWidget3;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtWidgets>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
m_rightSideWindow(NULL),
m_dockWidget1(NULL),
m_dockWidget2(NULL),
m_dockWidget3(NULL)
{
ui->setupUi(this);
QSplitter *splitter = new QSplitter(this);
splitter->setOrientation(Qt::Horizontal);
QTreeView* leftSideWidget = new QTreeView(this);
m_rightSideWindow = new QMainWindow(this);
m_rightSideWindow->setWindowFlags(Qt::Widget);
m_rightSideWindow->layout()->setContentsMargins(3, 3, 3, 3);
splitter->addWidget(leftSideWidget);
splitter->addWidget(m_rightSideWindow);
m_dockWidget1 = new QDockWidget("Dock 1", this);
m_rightSideWindow->addDockWidget(Qt::TopDockWidgetArea, m_dockWidget1);
m_dockWidget1->setTitleBarWidget(new QWidget()); // remove title bar
m_dockWidget1->setAllowedAreas(Qt::NoDockWidgetArea); // do not allow to dock
QTextEdit* textEdit1 = new QTextEdit(this); // put any QWidget derived class inside
m_dockWidget1->setWidget(textEdit1);
m_dockWidget2 = new QDockWidget("Dock 2", this);
m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dockWidget2);
m_dockWidget2->setTitleBarWidget(new QWidget());
m_dockWidget2->setAllowedAreas(Qt::NoDockWidgetArea);
QTextEdit* textEdit2 = new QTextEdit(this);
m_dockWidget2->setWidget(textEdit2);
m_dockWidget3 = new QDockWidget("Dock 3", this);
m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dockWidget3);
QTextEdit* textEdit3 = new QTextEdit(this);
m_dockWidget3->setWidget(textEdit3);
setCentralWidget(splitter);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionRestore_layout_triggered()
{
QList<QDockWidget*> list = findChildren<QDockWidget*>();
foreach(QDockWidget* dock, list)
{
if(dock->isFloating())
dock->setFloating(false);
m_rightSideWindow->removeDockWidget(dock);
if (dock == m_dockWidget1)
m_rightSideWindow->addDockWidget(Qt::TopDockWidgetArea, m_dockWidget1);
else
m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, dock);
dock->setVisible(true);
}
m_rightSideWindow->splitDockWidget(m_dockWidget2, m_dockWidget3, Qt::Horizontal);
}
You can dock a QDockWidget on a QMainWindow or another QDockWidget.
To get the desired layout embed a sub QMainWindow on the right side of your main window, and use it as a QWidget with setWindowFlags(Qt::Widget):
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtWidgets>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QSplitter *splitter = new QSplitter(this);
splitter->setOrientation(Qt::Horizontal);
QTreeView* leftSideWidget = new QTreeView(this);
m_rightSideWindow = new QMainWindow(this);
m_rightSideWindow->setWindowFlags(Qt::Widget);
m_rightSideWindow->layout()->setContentsMargins(3, 3, 3, 3);
splitter->addWidget(leftSideWidget);
splitter->addWidget(m_rightSideWindow);
m_dockWidget1 = new QDockWidget("Dock 1", this);
m_rightSideWindow->addDockWidget(Qt::TopDockWidgetArea, m_dockWidget1);
m_dockWidget1->setTitleBarWidget(new QWidget()); // remove title bar
m_dockWidget1->setAllowedAreas(Qt::NoDockWidgetArea); // do not allow to dock
QTextEdit* textEdit1 = new QTextEdit(this); // put any QWidget derived class inside
m_dockWidget1->setWidget(textEdit1);
m_dockWidget2 = new QDockWidget("Dock 2", this);
m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dockWidget2);
m_dockWidget2->setTitleBarWidget(new QWidget());
m_dockWidget2->setAllowedAreas(Qt::NoDockWidgetArea);
QTextEdit* textEdit2 = new QTextEdit(this);
m_dockWidget2->setWidget(textEdit2);
m_dockWidget3 = new QDockWidget("Dock 3", this);
m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dockWidget3);
QTextEdit* textEdit3 = new QTextEdit(this);
m_dockWidget3->setWidget(textEdit3);
setCentralWidget(splitter);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionRestore_layout_triggered()
{
QList<QDockWidget*> list = findChildren<QDockWidget*>();
foreach(QDockWidget* dock, list)
{
if(dock->isFloating())
dock->setFloating(false);
m_rightSideWindow->removeDockWidget(dock);
if (dock == m_dockWidget1)
m_rightSideWindow->addDockWidget(Qt::TopDockWidgetArea, m_dockWidget1);
else
m_rightSideWindow->addDockWidget(Qt::BottomDockWidgetArea, dock);
dock->setVisible(true);
}
m_rightSideWindow->splitDockWidget(m_dockWidget2, m_dockWidget3, Qt::Horizontal);
}
I am at trying to make a simple app which contains 2 pushButtons and QWidgetList with radiobuttons. All Ui-elements needs to be created manually. I tried to use signals like that, but Qt Creator doesn't compile this.
// window.h
namespace Ui {
class Window;
}
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = 0);
QPushButton * addButton;
QPushButton * removeButton;
QLineEdit textEdit;
QList<QRadioButton*> radioButtonList;
QGridLayout * layout;
public slots:
void addButton_clicked();
private:
QGroupBox *createRadiobuttonGroup();
QGroupBox *createPushButtonGroup();
QGroupBox *createTextEdit();
QGroupBox *createListWidget();
Ui::Window *ui;
};
//Window.cpp
Window::Window(QWidget *parent) :
QWidget(parent),
ui(new Ui::Window)
{
QGridLayout *grid = new QGridLayout;
grid->addWidget(createRadiobuttonGroup(), 0, 1);
grid->addWidget(createPushButtonGroup(), 1, 1);
grid->addWidget(createTextEdit(), 1, 0);
grid->addWidget(createListWidget(), 0, 0);
setLayout(grid);
setWindowTitle(tr("Group Box"));
resize(640, 480);
}
QGroupBox *Window::createListWidget()
{
QGroupBox *groupBox = new QGroupBox(tr("RadioButton List"));
QListWidget *radioButtonList = new QListWidget();
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(radioButtonList);
vbox->addStretch(1);
groupBox->setLayout(vbox);
QListWidgetItem *item = new QListWidgetItem();
radioButtonList -> addItem(item);
QString *value = new QString("Radiobutton value");
radioButtonList -> setItemWidget(item, new QRadioButton(tr(value->toUtf8())));
return groupBox;
}
QGroupBox *Window::createRadiobuttonGroup()
{
QGroupBox *groupBox = new QGroupBox();
QRadioButton *radio1 = new QRadioButton(tr("&Vetical"));
QRadioButton *radio2 = new QRadioButton(tr("&Horizontal"));
radio1->setChecked(true);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(radio1);
vbox->addWidget(radio2);
vbox->addStretch(1);
groupBox->setLayout(vbox);
return groupBox;
}
QGroupBox *Window::createPushButtonGroup()
{
QGroupBox *groupBox = new QGroupBox();
QPushButton *addButton = new QPushButton(tr("&Add"));
QPushButton *renameButton = new QPushButton(tr("&Remove"));
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(addButton);
vbox->addWidget(renameButton);
vbox->addStretch(1);
groupBox->setLayout(vbox);
return groupBox;
}
QGroupBox *Window::createTextEdit()
{
QGroupBox *groupBox = new QGroupBox();
QLineEdit *textEdit = new QLineEdit();
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget (textEdit);
vbox->addStretch(1);
groupBox->setLayout(vbox);
connect(addButton, SIGNAL(clicked()), this, SLOT(addButton_clicked()));
return groupBox;
}
void Window::addButton_clicked()
{
QRadioButton radio_btn = new QRadioButton("name");
vbox << radio_btn; // append radio button to the list
vbox->addWidget(radio_btn);
}
void Window::addButton_clicked()
{
QRadioButton radio_btn = new QRadioButton("name");
vbox << radio_btn; // append radio button to the list
vbox->addWidget(radio_btn);
}
Variable vbox does not exist in that scope. And even if it did, QVBoxLayout does not have a << operator, so you can't use that. You also call it a list for some reason.
I'm using QTabWidget (pHTab composed in AbstractManagerTab) to show some data
(IpTrafficPage and SpecTrafficPage widgets),
and I need to dynamically add QPushButtons to added tabs.
When I start application, added buttons are visible only at the last tab.
What could be wrong?
class AbstractTrafficPage : public QWidget
{
Q_OBJECT
public:
explicit AbstractTrafficPage(QWidget *parent = 0);
void addCommandButton(QWidget *btn);
private:
QVBoxLayout *commBtnsLayout;
};
AbstractTrafficPage::AbstractTrafficPage(QWidget *parent) :
QWidget(parent),
commBtnsLayout(new QVBoxLayout)
{
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(commBtnsLayout);
mainLayout->addStretch();
setLayout(mainLayout);
}
void AbstractTrafficPage::addCommandButton(QWidget *btn)
{
commBtnsLayout->addWidget(btn);
}
class IpTrafficPage : public AbstractTrafficPage
{
Q_OBJECT
public:
explicit IpTrafficPage(QWidget *parent = 0) : AbstractTrafficPage(parent) {};
};
class SpecTrafficPage : public AbstractTrafficPage
{
Q_OBJECT
public:
explicit SpecTrafficPage(QWidget *parent = 0) : AbstractTrafficPage(parent) {};
};
class AbstractManagerTab : public QWidget {
public:
AbstractManagerTab(QWidget *parent);
~AbstractManagerTab();
void addCommandButton(QWidget *btn);
private:
QTabWidget *pHTab;
}
AbstractManagerTab::AbstractManagerTab(QWidget *parent) :
QWidget(parent),
pHTab(new QTabWidget)
{
IpTrafficPage *ipPage = new IpTrafficPage(this);
pHTab->addTab(ipPage, tr("IP);
SpecTrafficPage *specPage = new SpecTrafficPage(this);
pHTab->addTab(specPage, tr("Spec"));
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(pHTab);
setLayout(mainLayout);
}
AbstractManagerTab::~AbstractManagerTab()
{
delete pHTab;
}
AbstractManagerTab::addCommandButton(QWidget *btn)
{
for (int index = 0; index < pHTab->count(); ++index) {
AbstractTrafficPage *page = dynamic_cast<AbstractTrafficPage *>
(pHTab->widget(index));
if (page)
page->addCommandButton(btn);
}
}
class StoredRecsTab : public AbstractManagerTab
{
Q_OBJECT
public:
explicit StoredRecsTab(QWidget *parent = 0);
};
StoredRecsTab::StoredRecsTab(QWidget *parent) :
AbstractManagerTab(parent)
{
QPushButton *createRecBtn = new QPushButton(tr("Create"), this);
QPushButton *removeRecBtn = new QPushButton(tr("Remove"), this);
addCommandButton(createRecBtn);
addCommandButton(removeRecBtn);
}
Any QWidget can have only one parent. If you want to add a button to many widgets, you need to create many button objects (one per tab).
Another option is to move the button to the visible tab on tab change. But I think it's not so good decision.