Consider following main.cpp (the only file of the whole Qt-project):
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QObject>
#pragma once
class collectedFunctions : public QObject
{
Q_OBJECT
public:
collectedFunctions(QObject* parent = 0) {};
~collectedFunctions() {};
public slots:
void setFunc() {
//Calculate 2+2 and change text of the label accordingly
}
};
#include "main.moc"
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
QWidget window;
window.resize(200, 200);
window.setWindowTitle("Test-GUI");
QVBoxLayout layout(&window);
QPushButton button(&window);
button.setText("Test");
button.show();
QLabel *label = new QLabel(&window);
label->setText("Hello");
collectedFunctions testingFuncs;
QObject::connect(&button, &QPushButton::clicked, &testingFuncs, &collectedFunctions::setFunc);
layout.addWidget(&button);
layout.addWidget(label);
window.show();
return app.exec();
}
My goal with this code is to create a slot that runs a function which the programmer defines (similar to the pyqt-implementation of the signals and slots system). The code above successfully compiles, not throwing any errors and so far meeting my expectations. Yet as soon I want to manipulate a widget (which in this case is the label), the setfunc-slot does not find the defined label. How can I manipulate a widget using this slot (e.g. using setText() at a label or addItems() at a combobox) or generally have them being recognized in the slot.
Update:
Thanks to the solution of this question, I figured that I could simply use a lambda instead of the Q_OBJECT makro, so I removed the header-code and then changed the connect from the Button to following:
QObject::connect(&button, &QPushButton::clicked, [&label](){
int num = 2 + 2;
string text = "2+2 = ";
text += std::to_string(num);
QString qtext = QString::fromStdString(text);
label->setText(qtext); });
you shouldn't use the Q_OBJECT macro in main.cpp.
The Q_OBJECT macro must appear in the private section of a class
definition that declares its own signals and slots or that uses other
services provided by Qt's meta-object system.
The moc tool reads a C++ header file. If it finds one or more class
declarations that contain the Q_OBJECT macro, it produces a C++ source
file containing the meta-object code for those classes. Among other
things, meta-object code is required for the signals and slots
mechanism, the run-time type information, and the dynamic property
system.
The C++ source file generated by moc must be compiled and linked with
the implementation of the class.
When you have your class defined in .cpp file instead of .h file moc fails to process it properly.
you need a separate file for class:
in collectedfunctions.h
#pragma once
#include <QObject>
class collectedFunctions: public QObject
{
Q_OBJECT
public:
collectedFunctions(QObject *parent = 0);
~collectedFunctions();
public slots:
void setFunc();
};
and in collectedfunctions.cpp
#include "collectedfunctions.h"
#include <QDebug>
collectedFunctions::collectedFunctions(QObject *parent)
{
}
collectedFunctions::~collectedFunctions()
{
}
void collectedFunctions::setFunc()
{
qDebug() << "2+2 = " << 2 + 2;
}
and in your main.cpp
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include "collectedfunctions.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget window;
window.resize(200, 200);
window.setWindowTitle("Test-GUI");
QVBoxLayout layout(&window);
QPushButton button(&window);
button.setText("Test");
button.show();
QLabel *label = new QLabel(&window);
label->setText("Hello");
collectedFunctions testingFuncs;
QObject::connect(&button, &QPushButton::clicked, &testingFuncs, &collectedFunctions::setFunc);
layout.addWidget(&button);
layout.addWidget(label);
window.show();
return app.exec();
}
don't forget to add QT +=core gui widgets in your .pro file.
Result:
If you want to change QLabel Text :
in collectedfunctions.h
#pragma once
#include <QObject>
class collectedFunctions: public QObject
{
Q_OBJECT
public:
explicit collectedFunctions(QObject *parent = 0);
~collectedFunctions();
signals:
void updateLable(int num);
public slots:
void setFunc();
private:
int num = 0;
};
and in collectedfunctions.cpp
#include "collectedfunctions.h"
#include <QDebug>
collectedFunctions::collectedFunctions(QObject *parent)
{
}
collectedFunctions::~collectedFunctions()
{
}
void collectedFunctions::setFunc()
{
qDebug() << "2+2 = " << 2 + 2;
num++;
emit updateLable(num);
}
and in your main.cpp
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include "collectedfunctions.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget window;
window.resize(200, 200);
window.setWindowTitle("Test-GUI");
QVBoxLayout layout(&window);
QPushButton button(&window);
button.setText("Test");
button.show();
QLabel *label = new QLabel(&window);
label->setText("Hello");
collectedFunctions testingFuncs;
QObject::connect(&button, &QPushButton::clicked, &testingFuncs, &collectedFunctions::setFunc);
QObject::connect(&testingFuncs, &collectedFunctions::updateLable, [&label](int num)
{
qDebug() << "Number = " << num;
label->setText(QString::number(num));
});
layout.addWidget(&button);
layout.addWidget(label);
window.show();
return app.exec();
}
you can see:
Related
There is a working app and I am adding a new language for GUI. Everything works fine but some part of the app are simply not translated. QLinguist detects all of them, and I have added a new translations, but still no result.
Here is the fragment of the code that is not getting translation:
"imagecropwindow_p.h":
#include <QWidget>
class QLabel;
class QPushButton;
class QHBoxLayout;
class QVBoxLayout;
class QFrame;
class CropWindowComponents: public QWidget
{
public:
CropWindowComponents(QWidget *parent = nullptr);
QPushButton *changeBtn;
QPushButton *cropBtn;
QPushButton *continueBtn;
QPushButton *cancelBtn;
};
class HorizontalWindow : public CropWindowComponents
{
Q_OBJECT
public:
HorizontalWindow(QWidget *parent = nullptr);
};
class VerticalWindow : public CropWindowComponents
{
Q_OBJECT
public:
VerticalWindow(QWidget *parent = nullptr);
};
"imagecropwindow_p.cpp":
#include "imagecropwindow_p.h"
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
CropWindowComponents::CropWindowComponents(QWidget *parent) :
QWidget(parent)
{
changeBtn = new QPushButton(tr("Change"), this);
cropBtn = new QPushButton(tr("Crop"), this);
continueBtn = new QPushButton(tr("Continue"), this);
cancelBtn = new QPushButton(tr("Cancel"), this);
}
HorizontalWindow::HorizontalWindow(QWidget *parent) :
CropWindowComponents(parent)
{
QHBoxLayout *btnsLyt = new QHBoxLayout;
btnsLyt->setMargin(0);
btnsLyt->addWidget(changeBtn);
btnsLyt->addWidget(cropBtn);
btnsLyt->addWidget(continueBtn);
btnsLyt->addWidget(cancelBtn);
btnsLyt->addStretch();
setLayout(btnsLyt);
}
VerticalWindow::VerticalWindow(QWidget *parent) :
CropWindowComponents(parent)
{
QVBoxLayout *btnsLyt = new QVBoxLayout;
btnsLyt->setMargin(0);
btnsLyt->addWidget(changeBtn);
btnsLyt->addWidget(cropBtn);
btnsLyt->addWidget(continueBtn);
btnsLyt->addWidget(cancelBtn);
btnsLyt->addStretch();
setLayout(btnsLyt);
}
"imagecropperwindow.h":
#include "imagecropwindow_p.h"
class ImageCropperWindow : public QWidget
{
Q_OBJECT
public:
explicit ImageCropperWindow(QWidget *parent = nullptr);
private slots:
void changeWindowOrientation();
private:
HorizontalWindow *horizWindow;
VerticalWindow *verticalWindow;
};
"imagecropperwindow.cpp":
#include "imagecropperwindow.h"
#include <QDebug>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLabel>
ImageCropperWindow::ImageCropperWindow(QWidget *parent) : QWidget(parent)
{
horizWindow = new HorizontalWindow(this);
verticalWindow = new VerticalWindow(this);
connect(horizWindow->changeBtn, &QPushButton::clicked,
this, &ImageCropperWindow::changeWindowOrientation);
connect(verticalWindow->changeBtn, &QPushButton::clicked,
this, &ImageCropperWindow::changeWindowOrientation);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(3);
layout->addWidget(horizWindow);
layout->addWidget(verticalWindow);
verticalWindow->setVisible(false);
setLayout(layout);
}
void ImageCropperWindow::changeWindowOrientation()
{
if (horizWindow->isVisible()) {
horizWindow->setVisible(false);
verticalWindow->setVisible(true);
}
else {
verticalWindow->setVisible(false);
horizWindow->setVisible(true);
}
this->resize(this->minimumSizeHint());
}
And "main.cpp":
#include <QApplication>
#include <QDebug>
#include <QTranslator>
#include "imagecropperwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTranslator newLang;
newLang.load(":/translations/newLanguage.qm");
a.installTranslator(&newLang);
ImageCropperWindow w;
w.show();
return a.exec();
}
You can find the whole project here.
PS: For an example case, I added stars (*) as a new translation, such as
nativeLanuage - ***newLanguage***
Change - ***Change***
Crop - ***Crop***
Continue - ***Continue***
Cancel - ***Cancel***
QTranslator uses the MOC to do the translations so if you want that if you want your widget to be translated you should use the macro Q_OBJECT, in your case CropWindowComponents does not have it, so the solution is to add it:
imagecropwindow_p.h
class CropWindowComponents: public QWidget
{
Q_OBJECT # <--- add this
public:
...
On the other hand do not add the .ts to the .qrc since the .ts only serves to convert it to the .qm binary. When you add a file to the .qrc it is compiled and added to the executable, increasing the size of the last one. Therefore adding the .ts increases the size of the executable unnecessarily.
What it should do: When the QComboBox is on the first item (index 0) it should hide the QStackedWidget. Which causes the QComboBox to extend as much as possible. As soon as you change the item in the QComboBox to anything, the QComboxBox should shrink and the QStackedWidget should display the correct page.
What I have and what it does instead: I test what the current index item is of the QComboBox and depending on that I change the size policies and visibility of widgets in order to obtain what I want. But it doesn't work. I tried to do workarounds but I cant seem to figure this out.
I also used qDebug() to see what currentIndexItem returns, and it seems to be stuck at 0, no matter to what index I change the QComboBox to. Do I have to update the currentItemIndex?
Note: I have a signal connected in the designer from QComboBox to QStackedWidget: currentIndexChanged(int) -> setCurrentIndex(int)
Here is my code.
My code:
interfacewindow.h
#ifndef INTERFACEWINDOW_H
#define INTERFACEWINDOW_H
#include <QMainWindow>
#include <QPainter>
#include <QComboBox>
namespace Ui
{
class InterfaceWindow;
}
class InterfaceWindow : public QMainWindow
{
Q_OBJECT
public:
explicit InterfaceWindow(QWidget *parent = 0);
~InterfaceWindow();
private:
Ui::InterfaceWindow *ui;
private slots:
void on_actionClose_triggered();
};
#endif // INTERFACEWINDOW_H
interfacewindow.cpp
#include "interfacewindow.h"
#include "ui_interfacewindow.h"
#include <QDebug>
InterfaceWindow::InterfaceWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::InterfaceWindow)
{
ui->setupUi(this);
if(ui->comboBox->currentIndex() == 0)
{
ui->comboBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
ui->stackedWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
ui->stackedWidget->setVisible(false);
}
else
{
ui->comboBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
ui->stackedWidget->setVisible(true);
}
}
InterfaceWindow::~InterfaceWindow()
{
delete ui;
}
void InterfaceWindow::on_actionClose_triggered()
{
this->close();
}
main.cpp
#include <QApplication>
#include "interfacewindow.h"
int main(int argc, char **argv)
{
QApplication a(argc, argv);
InterfaceWindow w;
w.show();
return a.exec();
}
This question already has answers here:
C++ Qt signal and slot not firing
(3 answers)
Closed 8 years ago.
I am very new to Qt and it looks like i have some very basic misunderstanding about how this library works. I am currently reading a book by m. Schlee but i do not want to continue until i do understand how to make this simple program work.
#include <QtWidgets>
#include <QApplication>
#include <QStackedWidget>
#include <QPushButton>
#include <QObject>
struct wizard : public QObject
{
QStackedWidget* p;
wizard(QStackedWidget* pp) : p(pp) { }
public slots:
void change()
{
int to = p->currentIndex();
if (to == p->count() - 1)
to = 0;
else
++to;
emit chIndex(to);
}
signals:
void chIndex(int);
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QStackedWidget qsw;
QPushButton qpb("magic");
qsw.resize(500, 500);
qsw.move(500, 300);
qsw.setWindowTitle("test qsw");
qpb.move(330, 300);
qpb.setWindowTitle("test qpb");
QWidget* pw1 = new QWidget();
QPalette pal1;
pal1.setColor(pw1->backgroundRole(), Qt::blue);
pw1->setPalette(pal1);
pw1->resize(500, 500);
pw1->setAutoFillBackground(true);
QWidget* pw2 = new QWidget();
QPalette pal2;
pal2.setColor(pw2->backgroundRole(), Qt::yellow);
pw2->setPalette(pal2);
pw2->resize(500, 500);
pw2->setAutoFillBackground(true);
qsw.addWidget(pw1);
qsw.addWidget(pw2);
wizard stupidity(&qsw);
QObject::connect(&qpb, SIGNAL(clicked()), &stupidity, SLOT(change()));
QObject::connect(&stupidity, SIGNAL(chIndex(int)), &qsw, SLOT(setCurrentIndex(int)));
qpb.show();
qsw.show();
return a.exec();
}
The idea is to launch 2 separate windows: one with painted background, and another with button that changes color (blue->yellow->blue->.. etc).
They appear, but nothing happens if i press the button. Please help.
Except for struct being a class and a missing Q_OBJECT macro the code is fine
Try the following:
create a main.h file having this content:
#ifndef MAIN_H
#define MAIN_H
#include <QObject>
#include <QStackedWidget>
class wizard : public QObject
{
Q_OBJECT
public:
QStackedWidget* p;
wizard(QStackedWidget* pp) : p(pp) { }
public slots:
void change()
{
int to = p->currentIndex();
if (to == p->count() - 1)
to = 0;
else
++to;
emit chIndex(to);
}
signals:
void chIndex(int);
};
#endif // MAIN_H
change your main.cpp to the following content:
#include <QtWidgets>
#include <QApplication>
#include <QPushButton>
#include <main.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QStackedWidget qsw;
QPushButton qpb("magic");
qsw.resize(500, 500);
qsw.move(500, 300);
qsw.setWindowTitle("test qsw");
qpb.move(330, 300);
qpb.setWindowTitle("test qpb");
QWidget* pw1 = new QWidget();
QPalette pal1;
pal1.setColor(pw1->backgroundRole(), Qt::blue);
pw1->setPalette(pal1);
pw1->resize(500, 500);
pw1->setAutoFillBackground(true);
QWidget* pw2 = new QWidget();
QPalette pal2;
pal2.setColor(pw2->backgroundRole(), Qt::yellow);
pw2->setPalette(pal2);
pw2->resize(500, 500);
pw2->setAutoFillBackground(true);
qsw.addWidget(pw1);
qsw.addWidget(pw2);
wizard stupidity(&qsw);
QObject::connect(&qpb, SIGNAL(clicked()), &stupidity, SLOT(change()));
QObject::connect(&stupidity, SIGNAL(chIndex(int)), &qsw, SLOT(setCurrentIndex(int)));
qpb.show();
qsw.show();
return a.exec();
}
qmake doesn't work very well with Q_OBJECT macro directly in cpp file. Btw. run qmake after changes applied.
I want to update text in a label in a first window from a second window where is a line edit to write some text. This text should be dispaly in first window.
I spend a week for it.
A famous connect doesn't work.
Is somebody who correct below code and explain how connect should work?
I use Qt in version 5.1.1
firstwindow.h
#ifndef FIRSTWINDOW_H
#define FIRSTWINDOW_H
#include <QMainWindow>
#include "secondwindow.h"
namespace Ui {
class Firstwindow;
}
class Firstwindow : public QMainWindow
{
Q_OBJECT
public:
explicit Firstwindow(QWidget *parent = 0);
~Firstwindow();
public slots:
void addEntry();
private slots:
void on_pushButton_clicked();
private:
Ui::Firstwindow *ui;
Secondwindow *asecondwindow;
Secondwindow *absecondwindow;
Secondwindow *abcsecondwindow;
};
#endif // FIRSTWINDOW_H
secondwindow.h
#ifndef SECONDWINDOW_H
#define SECONDWINDOW_H
#include <QDialog>
#include <QtWidgets>
namespace Ui {
class Secondwindow;
}
class Secondwindow : public QDialog
{
Q_OBJECT
public:
explicit Secondwindow(QWidget *parent = 0);
~Secondwindow();
QLineEdit *lineEdit;
private slots:
void on_pushButton_clicked();
private:
Ui::Secondwindow *ui;
QPushButton *pushButton;
};
#endif // SECONDWINDOW_H
main.cpp
#include "firstwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Firstwindow w;
w.show();
return a.exec();
}
firstwindow.cpp
#include "firstwindow.h"
#include "ui_firstwindow.h"
#include <QtCore>
#include <QtGui>
#include <QtWidgets>
Firstwindow::Firstwindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Firstwindow)
{
ui->setupUi(this);
asecondwindow = new Secondwindow();
QObject::connect(asecondwindow->lineEdit,SIGNAL(textChanged()),this, SLOT(addEntry()));
}
Firstwindow::~Firstwindow()
{
delete ui;
delete asecondwindow;
delete absecondwindow;
delete abcsecondwindow;
}
void Firstwindow::on_pushButton_clicked()
{
absecondwindow = new Secondwindow;
absecondwindow->exec();
}
void Firstwindow::addEntry()
{
abcsecondwindow = new Secondwindow;
if (abcsecondwindow->exec()) {
QString name = abcsecondwindow->lineEdit->text();
ui->label->setText(name);
}
}
secondwindow.cpp
#include "secondwindow.h"
#include "ui_secondwindow.h"
#include <QDialog>
Secondwindow::Secondwindow(QWidget *parent) :
QDialog(parent),
ui(new Ui::Secondwindow)
{
ui->setupUi(this);
}
Secondwindow::~Secondwindow()
{
delete ui;
}
void Secondwindow::on_pushButton_clicked()
{
// emit ui->lineEdit->textChanged();
QDialog::accept();
}
I see the following issues:
QLineEdit does not have a signal textChanged(). It should be textChanged(const QString &) instead. So you have to install your connection like:
QObject::connect(asecondwindow->lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(addEntry(const QString &)));
Please note that I changed the Firstwindow::addEntry() slot to Firstwindow::addEntry(const QString &) to match the signal's signature.
I cannot find when and where your QLineEdit member variable of the Secondwindow class is created.
There is a fundamental design problem with what you're doing. There's no need to expose the second window's internal properties to the first window. Just listen for changes within the second window and emit a signal whenever it changes. Then the first window can just listen to the changes on the second window.
Here's a full example showing what I mean. main.cpp:
#include <QApplication>
#include <QDialog>
#include <QLabel>
#include <QMainWindow>
#include <QPushButton>
#include <QLineEdit>
#include <QVBoxLayout>
class SecondWindow : public QDialog {
Q_OBJECT
public:
SecondWindow(QMainWindow *parent = 0) : QDialog(parent) {
QLineEdit *edit = new QLineEdit;
QPushButton *close = new QPushButton(QStringLiteral("close"));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(edit);
layout->addWidget(close);
setLayout(layout);
connect(edit, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged(QString)));
connect(close, SIGNAL(clicked()), this, SLOT(close()));
}
signals:
void textChanged(const QString &text);
};
class FirstWindow : public QMainWindow {
Q_OBJECT
public:
FirstWindow(QMainWindow *parent = 0) : QMainWindow(parent) {
QWidget *central = new QWidget(this);
QPushButton *button = new QPushButton(QStringLiteral("Open"));
label = new QLabel(QStringLiteral("Output appears here"));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(button);
layout->addWidget(label);
central->setLayout(layout);
setCentralWidget(central);
connect(button, SIGNAL(clicked()), this, SLOT(createWindow()));
}
private slots:
void createWindow() {
SecondWindow *window = new SecondWindow(this);
connect(window, SIGNAL(textChanged(QString)), this, SLOT(setLabelText(QString)));
window->resize(300, 300);
window->exec();
}
void setLabelText(const QString &text) {
label->setText(text);
}
private:
QLabel *label;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
FirstWindow w;
w.resize(400, 400);
w.show();
return a.exec();
}
#include "main.moc"
Not that the SecondWindow listens for changes on the QLineEdit and emits its own signal when that value changes. Then the FirstWindow just connects to that signal and changes its own QLabel whenever it receives the signal.
Alright so is there any way to make this program randomly change the variables x and y every time the button is clicked i am new to programming...
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <QtGUI>
#include <QWidget>
#include <cstdlib>
#include <ctime>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *window = new QWidget;
srand(time(0));
int x = 1+(rand()%900);
int y = 1+(rand()%400);
QPushButton *MainInter = new QPushButton("Push me!",window);
QPropertyAnimation *animation = new QPropertyAnimation(MainInter, "pos");
animation->setDuration(0);
animation->setEndValue(QPoint(x,y));
Object::connect(MainInter,SIGNAL(released()),animation,SLOT(start()));
window->resize(900,500);
window->show();
return a.exec();
}
What you can do is, instead of connecting the released() signal of your button directly to your animations start() SLOT, you would create your own custom SLOT. Then you connect the button to it, handle the action, and call the animation.
First read up on how to create a custom QWidget, instead of creating top level object in your main(). Simple example here
A custom widget might look like this:
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class QPushButton;
class QPropertyAnimation;
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = 0);
private:
QPushButton *button;
QPropertyAnimation *animation;
public slots:
void randomizeAnim();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include <QPushButton>
#include <QPropertyAnimation>
#include <ctime>
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent)
{
button = new QPushButton("Push me!", this);
animation = new QPropertyAnimation(button, "pos");
animation->setDuration(0);
QObject::connect(button, SIGNAL(released()), this, SLOT(randomizeAnim()));
}
void MyWidget::randomizeAnim()
{
srand(time(0));
int x = 1+(rand()%900);
int y = 1+(rand()%400);
animation->setEndValue(QPoint(x,y));
animation->start();
}
And now your main.cpp can be reduced to the boilerplate code:
#include <QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *window = new MyWidget;
window->resize(900,500);
window->show();
return a.exec();
}
Every time you click, your custom slot will handle the action and do the animation.