Change label text from another class using Qt signals and slots - c++

I'm trying to change text of a class Label from another class. I have class MainWindow, which contains Label.
I also have a Bot class from which I wanna change the value of label.
I'm trying to create signal and slots but I have no idea where to start.
I created signal and slots like so:
//in mainwindow.h
signals:
void changeTextSignal();
private slots:
void changeText();
//in mainwindow.cpp
void MainWindow::changeText(){
this->label->setText("FooBar");
}
But I have no idea how to connect a signal to be able to change Label's text from another class.

Read up on Qt signal-slot mechanism. If I understand you correctly, you are trying to signal from Bot to MainWindow that the Label text needs to change. Here's how you do it...
//bot.h
class Bot
{
Q_OBJECT;
//other stuff here
signals:
void textChanged(QString);
public:
void someFunctionThatChangesText(const QString& newtext)
{
emit textChanged(newtext);
}
}
//mainwindow.cpp
MainWindow::MainWindow
{
//do other stuff
this->label = new QLabel("Original Text");
mybot = new Bot; //mybot is a Bot* member of MainWindow in this example
connect(mybot, SIGNAL(textChanged(QString)), this->label, SLOT(setText(QString)));
}
void MainWindow::hello()
{
mybot->someFunctionThatChangesText("Hello World!");
}

Related

QT connect signal and slot in from different classes to mainwindow class?

I want to implement signal and slot between two classes mainwindow and reader.
Inside the reader class I declare the signal SetProgress:
reader.h
class reader :public QObject
{
Q_OBJECT
signals:
void SetProgress(QString sOperation, int nPercentage);
}
reader.cpp
void reader::UpdateProgress(double amount)
{
int nPrecentage = (100 * amount / (max- min));
emit SetProgress(m_sCurrentOperation, nPrecentage);
}
mainwindow.h
public:
reader *MyReader
private slots:
void SlotDisplayProgress(QString sActivity_i, int ProgressPercentage_i);
mainwindow.cpp
void mainwindow :: SlotDisplayProgress(QString sActivity_i, int nProgressPercentage_i)
{
this->ui->QprogressBar->setValue(nProgressPercentage_i);
}
inside Mainwidow.cpp I will declare signal and slot
MyReader = reader::New();
connect ( MyReader, &reader::SetProgress, this, &mainwindow::SlotDisplayProgress );
I tried debugging and everything works correctly till the emit part. However, the slot is never executed.
Try setting Qt::DirectConnection:
connect ( MyReader, &reader::SetProgress, this, &mainwindow::SlotDisplayProgress, ***Qt::DirectConnection***);
I had a problem like this, where I connected the signal and slot, and it only worked when I defined the type of connection.
I hope this helps.
PS. I don't know if this depends on the version of QT but when I connect signals and slots the syntax I write is the following:
ImageURLLoadListener* downloader = new ImageURLLoadListener(&id, socket);
connect(downloader, SIGNAL(imageLoaded(QString*,QTcpSocket*)), this, SLOT(on_resourceImageDownload(QString*,QTcpSocket*)), Qt::DirectConnection);
I don't know if it's related or not...
Is MyReader pointer? Use &MyReader if not so.

Qt/C++ : get Ui QLineEdit text from another class

I'm trying to make a simple test to use an UI object made with "Qt Design" but I'm pretty new to Qt and C++.
I've got a quite simple Ui : 3 LineEdits and 1 PushButton :
IMAGE : the UI window
I've a Client Class which is supposed to control Ui. It connects the QPushButton and it should get the content from QLineEdit.
But the result in QDebug is always the same when I push the Button, even when I change QlineEdit field: "Client connected : "" : 0 "
Moreover, if I use on_pushButton_clicked made with QtDesign, it will display the real values of QlineEdits.
Why the QStrings are always the same ? Am I passing a copy of the initial object ? How to solve that ?
Is it the good way to make a ViewController ? Else, what is the good way?
Client.cpp
#include "client.h"
#include "mainwindow.h"
#include "logwindow.h"
Client::Client()
{
LogWindow* w1 = new LogWindow();
MainWindow* w2 = new MainWindow();
_stack = new QStackedWidget();
_stack->addWidget(w1);
connect(w1->getButton(),SIGNAL(clicked()),this,SLOT(connexion()));
_stack->addWidget(w2);
_stack->show();
}
//When the button is Pushed, gets the content from QlineEdits and prints them
void Client::connexion()
{
QString ip=(LogWindow (_stack->currentWidget())).getIP();
int port=((LogWindow (_stack->currentWidget())).getPort()).toInt();
socket = new QTcpSocket(this);
socket->connectToHost(ip, port);
_stack->setCurrentIndex((_stack->currentIndex()+1)%_stack->count());
qDebug() <<"Client connected : " << ip << ":"<<port;
}
And a class made automatically by Qt :
LogWindow.cpp
#include "logwindow.h"
#include "ui_logwindow.h"
LogWindow::LogWindow(QWidget *parent) :
QWidget(parent),
ui(new Ui::LogWindow)
{
ui->setupUi(this);
}
LogWindow::~LogWindow()
{
delete ui;
}
QPushButton* LogWindow::getButton()
{
return ui->pushButton;
}
QString LogWindow::getIP()
{
//LineEdit named "IP_text"
return ui->IP_text->text();
}
QString LogWindow::getPort()
{
//LineEdit named "Port_text"
return ui->Port_text->text();
}
LogWindow.h
namespace Ui {
class LogWindow;
}
class LogWindow : public QWidget
{
Q_OBJECT
public:
explicit LogWindow(QWidget *parent = 0);
~LogWindow();
QPushButton* getButton();
QString getIP();
QString getPort();
private slots:
void on_pushButton_clicked();
private:
Ui::LogWindow *ui;
};
Thuga solved it :
In Client::connexion you are creating a new instance of LogWindow.
Make LogWindow* w1 a member variable of your Client class, if you want
to access it in other Client's member functions as well.
There is not much to complain about, except that _stack is a widget
without a parent, so you must make sure you destroy it when you don't
need it anymore (for example call delete _stack; in the destructor).
Most beginners would have tried to make the ui variable public to get
the data from IP_text, but you did correctly, by making the
LogWindow::getIP function.
If you don't want to expose ui->pushButton outside of your class, you
can make a signal for your LogWindow class, and connect the clicked
signal of ui->pushButton to that signal. You can connect signals to
signals, it doesn't have to be a slot.

Qt pass variables between forms

I want to pass a string from a form that is opened by the first form to the first form.
I am new to C++.
Here is my code.
Form1.h // main form
#include "dialog.h"
namespace Ui {
class Form1;
}
class Form1 : public QMainWindow
{
Q_OBJECT
public:
explicit Form1(QWidget *parent = 0);
~Form1();
void refresh(QString str_local);
private slots:
void on_pushButton_clicked();
private:
Ui::Form1 *ui;
Dialog *dialog1;
};
// form1.cpp
void Form1::on_pushButton_clicked()
{
dialog1= new Dialog; //Create new form with other class
dialog1->show();
QObject::connect(dialog1, SIGNAL(change(str_remote)), this, SLOT(refresh(str_local))); //Connect when is emit signal cambia in the child form and pass the string to local function
}
void Form1::refresh(QString str_local)
{
qDebug() << "Back to main" << str_local;
ui->label->setText(str_local);
}
// dialog.h the second form that should pass the value to main form
...
class Dialog : public QDialog
{
Q_OBJECT
signals:
void change(QString s);
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private slots:
void on_pushButton_clicked();
private:
Ui::Dialog *ui;
};
// dialog.cpp
...
void Dialog::on_pushButton_clicked()
{
QString name;
name = ui->lineEdit->text();
emit change(name);
this->close();
}
I get the error:
No such signal Dialog::change(str_remote) in ../Format/form1.cpp:22 .
You have some strange code in here:
QObject::connect(dialog1, SIGNAL(change(str_remote)), this, SLOT(refresh(str_local)));
Since your class already inherits QObject indirectly, you can simply drop the scope specifier.
You probably aim for using the new compilation-time syntax signal-slot mechanism.
You have not marked your slot as slot in the header file.
You are trying to use the old signal/slot syntax with variable names for the signal and slot as opposed to the types.
Your signal is not using the good practice of const T& (i.e. constant reference).
You are specifying this explicitly, whereas it can be dropped. This is just admittedly personal taste.
You do not follow the Qt signal/slot naming convention, e.g. your signal is a verb rather adjective. It is also too generic, rather than "fooChanged" as the good practice goes.
There are other issues in your code as well, but this time I only focused on that one line. I would use this line with modern Qt and C++ programming principles in mind:
connect(dialog1, &Dialog::changed, (=)[const auto &myString] {
ui->label->setText(myString);
});
However, since this requires CONFIG += c++14, if your compiler does not support that (e.g. VS2010), you can go for this:
connect(dialog1, SIGNAL(change(const QString&)), this, SLOT(refresh(const QString&)));

Qt4: connect slot and signal from other forms

I have a small problem. I want run function in MainWindow from AnotherWindow. I can't set connect() for it.
Main class: MainWindow
Other form: AnotherWindow
Function in main class: setVariable(QString)
Function in other form: btnClicked()
I have now connected button signal clicked():
// In AnotherWindow.cpp
connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(btnOkClicked()));
// Function in same file
void interfaceWindow::btnOkClicked() {
/* Some actions - emit signal? */
this->close();
}
btnOkClicked() are declared as private slot.
// In MainWindow.cpp
void MainWindow::setVariable(QString _var) {
this->var = _var;
}
setVariable(QString) are declared as public slot.
How I can send variable from AnotherForm (from btnOkClicked() function) to MainWindow (setVariable(QString) function) ? How and where I must send signal and make connection?
I readed about signals and slots, but my code don't work - I don't paste it here because it's terrible :)
Any help for Qt newbie?
You need to have an reference of AnotherWindow in MainWindow OR vice versa. Then you need the following things:
// AnotherWindow.h
signals:
void buttonOkClickedSignal(QString var);
// AnotherWindow.cpp
void interfaceWindow::btnOkClicked() {
emit buttonOkClickedSignal("The button got clicked!");
this->close();
}
Next step varies based on whether MainWindow has reference to AnotherWindow or vice versa. You can either:
// AnotherWindow.cpp
connect(this, SIGNAL(buttonOkClickedSignal(QString), &mainWindow, SLOT(setVariable(QString)));
or:
// MainWindow.cpp
connect(&anotherWindow, SIGNAL(buttonOkClickedSignal(QString), this, (SLOT(setVariable(QString)));
If you are invoking the slot through signal it shouldn't matter whether it's private or public (see Qt Documentation).
Hope this helps.
I'm not entirely sure I understand your question, but let me try.
You want to be able to fire a slot in another class. There are a few ways you can do that.
Declare one as a friend class to the other. Then they can see the protected and private variables/memebers
It is possible to make slots static so you can call them without a class object.
For example,
class MainWindow {
private slot:
void setVariable(QString);
}
class AnotherWindow {
friend class MainWindow;
MainWindow *window;
public:
AnotherWindow() {
connect(this, SIGNAL(fire(QString)), window, SLOT(setVariable(QString)));
}
signals:
void fire(QString);
public slots:
void onButtonClicked() {
emit fire(QString);
}
}
The previous is pseudocode so don't expect it to compile. I think this is what you want. Basically since your slot is private on MainWindow you need to make it a friend. To connect, it needs to be a member. Then when the onButtonClicked slot is evoked, then it fire()s the setVarialbe() slot.
Here is a simple code for your another window:
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget * parent = 0)
{
okBtn = new QPushButton ("I am Ok!");
MyData = "";
connect(okBtn ,SIGNAL(clicked()),this,SLOT(OnOk()));
}
~MyWidget();
private:
QString MyData;
QPushButton * okBtn;
//something that modify string MyData
signals:
void MyDataSignal(QString);
//Internal slot that emits signal with proper data
private slots:
void OnOk()
{
if(MyData!="")
{
emit MyDataSignal(MyData);
}
}
};
Now in MainWindow create an object of MyWidget (suppose myWid)and connect it to slot
connect(myWid, SIGNAL(MyDataSignal(QString)),this,SLOT(OnMyWidOkClicked(QString)));
the signal will pass string to slot.
While making signals and slots keep in mind following points:
To connect a signal to a slot (or to another signal), they must have the same parameter
Parameters should be in the same order in both signal and slot.
if a signal has more parameters than the slot it is connected to, the additional parameters are simply ignored but opposite is not possible.
If you will connect a signal that have unmatched parameters to slot then no compile time error will occur but at run time command window will show a warning that signal/slot/connection does not exist.

mainwindow.ui and dialog.ui to set/read communication date

I have two windows: mainwindow.ui and dialog.ui. In the mainwindow.cpp I initialise some objects on the heap of another class for Ethernet-communication and use functions of these objects to read date from the bus and show the values in the mainwindow.ui. In dialog.ui I would like to set the values on the bus, but the problem is to access the communication-functions and objects in mainwindow.cpp.
I wanted to define dialog.cpp as friend class, but I make something wrong. Here is some code:
mainwindow.h
class MainWindow : public QMainWindow
{protected: DateReg *myPosReg;...}
mainwindow.cpp
...
myPosReg = new DateReg(DateValue->AddReg());
...
myPosReg->GetValue(a,b,c);
myPosReg->setValue(a,b,c);
...
Can I somehow access setValue() function in dialog.cpp? Should I allways use dialog.cpp for the dialog.ui or there is some possibility work with dialog.ui-date in mainwindow.cpp? To set the values in dialog.ui I use QDoubleSpinBox.
In the mainwindow.ui I call dialog.ui.
Excuse me for my English.
As far as I understand, you have two classes: MainWindow and Dialog. As MainWindow::myPosReg is protected, you can only access it in Dialog, if Dialog derives from MainWindow or if it is a friend.
The following design should work:
class MainWindow : public QMainWindow
{
[...]
protected:
DateReg *myPosReg;
friend class Dialog;
};
class Dialog
{
[...]
MainWindow* myMainWindow;
void someFunction()
{
myMainWindow->myPosReg->setValue([...]);
}
};
As an alternative, I would suggest a more Qt-ish way by using signals and slots. When the spin-boxes in Dialog change, emit a signal to which MainWindow listens.
We start with the dialog:
class Dialog : public QDialog
{
[...]
Dialog()
{
[...init ui...]
connect(ui->spinBoxA, SIGNAL(valueChanged(int)),
this, SLOT(onSpinBoxValueChanged()));
connect(ui->spinBoxB, SIGNAL(valueChanged(int)),
this, SLOT(onSpinBoxValueChanged()));
connect(ui->spinBoxC, SIGNAL(valueChanged(int)),
this, SLOT(onSpinBoxValueChanged()));
}
signals:
void valuesChanged(int a, int b, int c);
private slots:
void onSpinBoxValueChanged()
{
emit valuesChanged(ui->spinBoxA->value(), ui->spinBoxB->value(),
ui->spinBoxC->value());
}
};
So the dialog has an internal slot onSpinBoxValueChanged(), which is called when
one of the spinboxes changes its value. The sole purpose of this slot is to emit
another signal valuesChanged to which we'll connect the main window (i.e. the
dialog's internal slot combines three values into one signal).
The main window could be the following:
class MainWindow : public QMainWindow
{
[...]
DateReg *myPosReg;
public slots:
void setValues(int a, int b, int c)
{
myPosReg->setValues(a, b, c);
}
};
And the code, which connects both
int main()
{
[...]
MainWindow* mainWindow = new MainWindow;
Dialog* dialog = new Dialog;
connect(dialog, SIGNAL(valuesChanged(int,int,int)),
mainWindow, SLOT(setValues(int,int,int)));
}
When the user changes the value in a spinbox, the following chain-reaction happens:
QSpinBox::valueChanged(int) -> Dialog::onSpinBoxValueChanged()
-> Dialog::valuesChanged() -> MainWindow::setValues() -> DateReg::setValues()
The advantage is that you decouple MainWindow and Dialog: Dialog just signals that the values have changed but does not care what happens with them and MainWindow changes its myPosReg but does not care, where the values are coming from.