I am trying to print a QLabel from a combobox in QT. Code looks like this:
QApplication a(argc, argv);
QWidget w;
QVBoxLayout *layout = new QVBoxLayout(&w);
QLabel *label = new QLabel("Here you will see the selected text from ComboBox", &w);
QComboBox *combo = new QComboBox(&w);
layout->addWidget(label);
layout->addWidget(combo);
Q_FOREACH(QSerialPortInfo port, QSerialPortInfo::availablePorts()) {
combo->addItem(port.portName());
QObject::connect(combo, SIGNAL(currentIndexChanged(QString)), label, (SLOT(setText(QString))));
How do i print the label via cout?
Your code seems to be using Qt4, let's port that to Qt5 and a newer C++, shall we?
#include <QtWidgets>
#include <QtSerialPort>
int main(int argc, char ** argv) {
QApplication app(argc, argv);
QWidget w;
auto layout = new QVBoxLayout(&w);
auto label = new QLabel("Here you will see the selected text from ComboBox");
auto combo = new QComboBox;
layout->addWidget(label);
layout->addWidget(combo);
for (auto port : QSerialPortInfo::availablePorts())
combo->addItem(port.portName());
QObject::connect(combo, &QComboBox::currentTextChanged, [label, combo](){
label->setText(combo->currentText());
qDebug() << combo->currentText();
});
w.show();
return app.exec();
}
Try to not use Q_FOREACH in new code, it will probably be removed in the future,
Use auto when the type will be already specified by the new operator, this simplifies code,
Use qDebug to output debug information to the terminal,
Use lambdas in connections when the invoked code is short,
Use the new style connections for connections, because they will guarantee that your code actually works, the old style has runtime checks, and the new has build time checks.
Related
I have QSplitter set as the central widget:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
mdiArea(new QMdiArea)
{
QWidget *widget = new QWidget;
widget->setMinimumSize(100, 100);
QSplitter *splitter = new QSplitter;
splitter->addWidget(mdiArea);
splitter->addWidget(widget);
setCentralWidget(splitter);
createActions();
}
void MainWindow::createSubwin()
{
QWidget *subwin = new QWidget(mdiArea);
subwin->setWindowTitle("Subwindow");
subwin->setMinimumSize(100, 100);
mdiArea->addSubWindow(subwin);
subwin->show();
}
void MainWindow::createActions()
{
QAction *actSub = new QAction("Add subwindow", this);
connect(actSub, SIGNAL(triggered()), SLOT(createSubwin()));
QMenu *winMenu = menuBar()->addMenu("Windows");
winMenu->addAction(actSub);
}
When I press maximize button of subwindow, the subwindow covers entire main window. Is there any way to prevent such behaviour and make subwindow occupy all the space of QMdiArea instead?
UPD: It looks like that the problem occurs only when at least one menu in main window's QMenuBar is present. Without menuBar everything works as expected:
https://www.qtcentre.org/threads/44457-QMdiSubWindow-maximizing-problem
Regarding the QSplitter, I gave OP the following hint:
Move the right part of the QSplitter into a dock widget (and drop the QSplitter), so that the left part is the only part of the QMainWindow::centralWidget(). This would mean to work with the existing class instead of against, and is probably easier to manage.
OP appreciated the hint with the dock widget but claimed the sub-window will still occupy the whole main window.
I must admit my lack of experience with MDI and made an MCVE to prove me myself right or wrong:
#include <QtWidgets>
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QMainWindow qWinMain;
qWinMain.setWindowTitle("QMainWindow - MDI - Dock");
qWinMain.resize(640, 480);
// MDI
QMdiArea qMDI;
qWinMain.setCentralWidget(&qMDI);
// MDI sub widget
QLabel qWinSub("MDI Sub-Window\nwidget");
qMDI.addSubWindow(&qWinSub);
// Dock
QDockWidget qDock;
qDock.setWindowTitle("Dock");
QLabel qLblDock("Dock\nwidget");
qDock.setWidget(&qLblDock);
qWinMain.addDockWidget(Qt::RightDockWidgetArea, &qDock);
qWinMain.show();
// runtime loop
return app.exec();
}
Output:
So, I cannot reproduce OPs claim—it works on my side.
My platform: Windows 10, VS2019, Qt5.15
I enhanced the first MCVE a bit to see how it works if MDI sub-windows are created after qWinMain.show() (what's expected as the usual case).
#include <QtWidgets>
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QMainWindow qWinMain;
qWinMain.setWindowTitle("QMainWindow - MDI - Dock");
qWinMain.resize(640, 480);
// MDI
QMdiArea qMDI;
qWinMain.setCentralWidget(&qMDI);
// Dock
QDockWidget qWinDock;
qWinDock.setWindowTitle("Dock");
QWidget qDock;
QVBoxLayout qVBoxDock;
QPushButton qBtnNewMDISubWin("New Sub-Window");
qVBoxDock.addWidget(&qBtnNewMDISubWin);
qDock.setLayout(&qVBoxDock);
qWinDock.setWidget(&qDock);
qWinMain.addDockWidget(Qt::RightDockWidgetArea, &qWinDock);
// create sub-window
int i = 0;
auto createSubWin = [&]() {
++i;
QLabel* pQWinSub = new QLabel(QString("MDI Sub-Window\nwidget %1").arg(i));
pQWinSub->setWindowTitle(QString("MDI Sub-Window %1").arg(i));
qMDI.addSubWindow(pQWinSub);
pQWinSub->show();
};
// install signal handlers
QObject::connect(&qBtnNewMDISubWin, &QPushButton::clicked,
createSubWin);
// runtime loop
qWinMain.show();
return app.exec();
}
Output:
It still works on my side as expected.
Note:
I had to add the explicit pQWinSub->show(); after qMDI.addSubWindow(pQWinSub); (which was not necessary in the first MCVE). However, this is exactly how it's done by OP's code.
OPs reply:
It turns out that the problem occurs only when menuBar is present
Oha. How comes?
I extended my MCVE again to add a menu bar:
#include <QtWidgets>
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QMainWindow qWinMain;
qWinMain.setWindowTitle("QMainWindow - MDI - Dock");
qWinMain.resize(640, 480);
// menu
QMenuBar qMenuMain;
QAction qCmdFile("File");
QMenu qMenuFile;
QAction qCmdFileNew("New");
qMenuFile.addAction(&qCmdFileNew);
qCmdFile.setMenu(&qMenuFile);
qMenuMain.addAction(&qCmdFile);
qWinMain.setMenuBar(&qMenuMain);
// MDI
QMdiArea qMDI;
qWinMain.setCentralWidget(&qMDI);
// Dock
QDockWidget qWinDock;
qWinDock.setWindowTitle("Dock");
QWidget qDock;
QVBoxLayout qVBoxDock;
QPushButton qBtnNewMDISubWin("New Sub-Window");
qVBoxDock.addWidget(&qBtnNewMDISubWin);
qDock.setLayout(&qVBoxDock);
qWinDock.setWidget(&qDock);
qWinMain.addDockWidget(Qt::RightDockWidgetArea, &qWinDock);
// create sub-window
int i = 0;
auto createSubWin = [&]() {
++i;
QLabel* pQWinSub = new QLabel(QString("MDI Sub-Window\nwidget %1").arg(i));
pQWinSub->setWindowTitle(QString("MDI Sub-Window %1").arg(i));
pQWinSub->setFrameShape(QFrame::Box);
qMDI.addSubWindow(pQWinSub);
pQWinSub->show();
};
// install signal handlers
QObject::connect(&qCmdFileNew, &QAction::triggered,
createSubWin);
QObject::connect(&qBtnNewMDISubWin, &QPushButton::clicked,
createSubWin);
// runtime loop
qWinMain.show();
return app.exec();
}
Output:
Note:
I partly agree with OP:
Yes, the look of the maximized MDI is a bit different now. It looks like it occupies the whole client area of the main window but…
…the dock widget is still visible. I added a box to the QLabel (the top widget in the MDI sub-window) to illustrate this. In fact, the sub-window still occupies the central widget only (regardless what the look of its title bar suggests).
I am currently learning to use Qt. So I am trying to create an application that uses QtWidgets. However, when I ran my program and resize manually the window obtained, the texts displayed are trimmed (see image)
.
The code I am using is shown below:
#include <QApplication>
#include "FenPrincipale.h"
using namespace std;
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
FenPrincipale fenetre;
fenetre.show();
return app.exec();
}
and the FenPrincipale contains:
FenPrincipale::FenPrincipale()
{
QWidget mainFen;
QGroupBox *groupbox1 = new QGroupBox("Class definition", &mainFen);
QLineEdit *className = new QLineEdit;
QLineEdit *mother_className = new QLineEdit;
QFormLayout *class_def = new QFormLayout;
class_def->addRow("Class name", className);
class_def->addRow("Mother Class", mother_className);
groupbox1->setLayout(class_def);
QGroupBox *groupbox2 = new QGroupBox("Options", &mainFen);
QCheckBox *header_protect = new QCheckBox("Protect header against mutiple inclusions");
QCheckBox *constr_gen= new QCheckBox("Generate default constructor");
QCheckBox *destruct_gen= new QCheckBox("Generate a destructor");
QVBoxLayout *options_layout = new QVBoxLayout;
options_layout->addWidget(header_protect);
options_layout->addWidget(constr_gen);
options_layout->addWidget(destruct_gen);
groupbox2->setLayout(options_layout);
QVBoxLayout *main_layout = new QVBoxLayout;
main_layout->addWidget(groupbox1);
main_layout->addWidget(groupbox2);
this->setLayout(main_layout);
this->setWindowTitle("Zero Class Generator");
this->resize(400,450);
}
I don't have any idea how to fix this problem. Can anyone help me?
QWidget::setMinimumSize
should make the job
https://doc.qt.io/qt-5/qwidget.html#setMinimumSize-1
I'm using QFileDialog::getOpenFileName right now. However, as suggested in this article, this crashes when the main application closes while the dialog is open. You can see an example of how to reproduce the crash here:
int main(int argc, char **argv) {
QApplication application{argc, argv};
QMainWindow *main_window = new QMainWindow();
main_window->show();
QPushButton *button = new QPushButton("Press me");
main_window->setCentralWidget(button);
QObject::connect(button, &QPushButton::clicked, [main_window]() {
QTimer::singleShot(2000, [main_window]() { delete main_window; });
QFileDialog::getOpenFileName(main_window, "Close me fast or I will crash!");
});
application.exec();
return 0;
}
I can use QFileDialog with the normal constructor instead, as described here. However, then I don't seem to get the native windows file open dialog.
Is there a way to get a non crashing program and use the native Windows file open dialog through Qt?
If you close your main_window instead of deleting it, you won't get any crash.
By the way, you could check if there is any QFileDialog opened to avoid a wrong app exit.
In the next example, I'm closing the dialog, but you could implement another solution:
#include <QTimer>
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QFileDialog>
#include <QDebug>
int main(int argc, char **argv) {
QApplication application{argc, argv};
QMainWindow *main_window = new QMainWindow();
main_window->show();
QPushButton *button = new QPushButton("Press me");
main_window->setCentralWidget(button);
QObject::connect(button, &QPushButton::clicked, [main_window]() {
QTimer::singleShot(2000, [main_window]() {
QObjectList list = main_window->children();
while (!list.isEmpty())
{
QObject *object= list.takeFirst();
if (qobject_cast<QFileDialog*>(object))
{
qDebug() << object->objectName();
QFileDialog* fileDialog = qobject_cast<QFileDialog*>(object);
fileDialog->close();
}
}
main_window->close();
});
QFileDialog::getOpenFileName(main_window, "Close me fast or I will crash!");
});
application.exec();
return 0;
}
The design of your application is broken. The shut down of the application normally happens when the outernmost event loop in the main thread exists. This won't happen while a file dialog is active - by definition, its event loop is running then. Thus you're doing something you shouldn't be doing, and the file dialog is merely a scapegoat, or a canary in the coalmine indicating brokenness elsewhere.
I want to have some sequential actions; for example press a QPushButton and then delete the layout that is running and run another layout in the "SAME WINDOW"
In fact, I don't know what exactly layouts and widgets are!
Are they an object? an instance of object or what?
I found the bellow code in the Internet, I don't know how to change it to make it useful for me
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget *window = new Qwidget;
QPushButton *button1 = new QPushButton("One");
QPushButton *button2 = new QPushButton("Two"); QPushButton *button3 = new QpushButton("Three");
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
window->setLayout(layout);
window->show();
return app.exec();
}
A better way than deleting layout and setting a new one would be to use a QStackedWidget (docs) and the concept of pages. Using QStackedWidget you can show and hide pages as you wish.
I am trying to add a label to the main window using Qt. Here is a piece of the code:
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget Main_Window;
QPixmap Image;
Image.load("1837.jpg");
QLabel i_label;
i_label.setPixmap(Image);
i_label.show();
QPushButton Bu_Quit("Quit", &Main_Window);
QObject::connect(&Bu_Quit, SIGNAL(clicked()), qApp, SLOT(quit()));
Main_Window.show();
return app.exec();
}
I've been having a very hard time figuring out how to properly add QLabels to QWidgets, I tried to set the Main_Window as the main widget using this method: app.setMainWidget(Main_Window) and the label was still outside the window. So how do I put labels into widgets using Qt?
hamza, this code worked fine for me:
#include <QtGui>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget Main_Window;
QLabel i_label("Start", &Main_Window);
//i_label.setPixmap(QPixmap("1837.jpg"));
QPushButton Bu_Quit("Quit" , &Main_Window);
QObject::connect(&Bu_Quit , SIGNAL(clicked()), qApp , SLOT(quit()));
QVBoxLayout *vbl = new QVBoxLayout(&Main_Window);
vbl->addWidget(&i_label);
vbl->addWidget(&Bu_Quit);
Main_Window.show();
return app.exec();
}
I commented setting the image code to show you that the label was set correctly. Make sure your image is valid (otherwise you won't see the text). The trick here was that you need to use qt layouts like QVBoxLayout
Add the label to a layout widget and set the window layout to that layout.
Design note: its better to create your own MainWindow class, inheriting from QMainWindow for instance, and design it from the inside.
or even better, use QtCreator.
You can try:
QWidget window;
QImage image("yourImage.png");
QImage newImage = image.scaled(150, 150, Qt::KeepAspectRatio);
QLabel label("label", &window);
label.setGeometry(100, 100, 100, 100);
label.setPixmap(QPixmap::fromImage(newImage));
window.show();
this way you can even decide where to put the label and choose the image size.