I have a slot that receives a QString, and I want to assign the value for this parameter in another variable, or use it directly in another method of the same class.
The signal is emitted from some other class.
MyWidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include"myclass.h"
#include <QWidget>
#include <QtWidgets>
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0);
~MyWidget();
private:
Ui::MyWidget *ui;
signals:
void redirectData(QString data);
public slots:
void sendData();
private:
MyClass *myClass; // the object to receive and output the data
};
#endif // MYWIDGET_H
MyWidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
ui->setupUi(this);
myClass = new MyClass();
connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(sendData()));
connect(this, SIGNAL(redirectData(QString)), myClass, SLOT(outputData(QString)));
}
MyWidget::~MyWidget()
{
delete ui;
}
void MyWidget::sendData()
{
emit redirectData(ui->lineEdit->text());
myClass->show();
}
MyClass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QWidget>
namespace Ui {
class MyClass;
}
class MyClass : public QWidget
{
Q_OBJECT
public:
explicit MyClass(QWidget *parent = 0);
~MyClass();
QString x;
private:
Ui::MyClass *ui;
signals:
void send2(QString);
public slots:
void outputData(QString data);
};
#endif // MYCLASS_H
MyClass.cpp
#include "myclass.h"
#include "ui_myclass.h"
MyClass::MyClass(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyClass)
{
ui->setupUi(this);
ui->plainTextEdit->insertPlainText(x); // show x in plainTextEdit
}
MyClass::~MyClass()
{
delete ui;
}
void MyClass::outputData(QString data){
x=data; // affect data a x
}
I want to display the value of x in the QPlainTextEdit.
This method is correct but does not fit with the rest of my code. I would like to preserve the value in x.
MyClass.cpp
#include "myclass.h"
#include "ui_myclass.h"
MyClass::MyClass(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyClass)
{
ui->setupUi(this);
}
MyClass::~MyClass()
{
delete ui;
}
void MyClass::outputData(QString data){
ui->plainTextEdit->insertPlainText(data);
}
This now an OK question, if a tad wordy and basic. It is clearly mostly complete (the .ui files are missing - but don't include them!) and reproducible.
Thus, there are two things that you can do:
Simply set the value of the plain text edit in the slot:
void MyClass::outputData(QString data){
x = data;
ui->plainTextEdit->insertPlainText(x);
}
You don't need to store the value in x at all, if you don't need it anywhere else in MyClass.
If MyClass should expose the x property to interact with other classes, you should make it so - and then use the notification signal to modify the widget:
class MyClass : public QWidget {
Q_OBJECT
Q_PROPERTY(QString x READ x WRITE setX NOTIFY xChanged)
QString m_x;
Ui::MyClass *ui;
public:
explicit MyClass(QWidget *parent = {}) {
ui->setupUi(this);
connect(this, &MyClass::xChanged, ui->plainTextEdit, &QPlainTextEdit::insertPlainText);
~MyClass {}
Q_SIGNAL void xChanged(const QString &);
Q_SLOT void setX(const QString &x) {
if (m_x != x) {
m_x = x;
emit xChanged(m_x);
}
}
QString x() const { return m_x; }
};
Other notes
The MyClass::x member should not be public.
The containers passed as method arguments should be almost always of a const reference type - to avoid the premature pessimization of making copies of objects passed. Thus you should modify the signatures as follows - in both declarations (header files) and definitions (implementation - .cpp files):
void MyClass::send2(const QString&);
void MyClass::outputData(const QString &data)
void MyWidget::redirectData(const QString &data)
The old-style connect syntax you use demands normalized signatures and doesn't change - the const and reference must be dropped.
There's no need to store the ui by pointer - simply store it by value. The C++ language then automatically takes care of memory management for you, and the default compiler-generated destructor does the job.
In self-contained examples, there's no need to use the .ui files. Creating the widgets manually and laying them out is quite trivial, as you can see below.
A reworked example
Taking all this into account, this would be a self-contained demo - with no Ui files needed. Your question should have had something like this included - it's self contained, single file. The use of the properties is not undesirable to indicate intent: those are the changeable properties of the classes.
#include <QtWidgets>
class Source : public QWidget {
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
QHBoxLayout m_layout{this};
QLineEdit m_edit;
QPushButton m_send{tr("Send")};
QString m_text;
public:
Source(QWidget *parent = {}) : QWidget(parent) {
m_layout.addWidget(&m_edit);
m_layout.addWidget(&m_send);
connect(&m_send, &QPushButton::clicked, [this]{
setText(m_edit.text());
});
}
Q_SLOT void setText(const QString &text) {
if (text == m_text) return;
m_text = text;
emit textChanged(m_text);
}
QString text() const { return m_text; }
Q_SIGNAL void textChanged(const QString &);
};
class Destination : public QWidget {
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
QHBoxLayout m_layout{this};
QPlainTextEdit m_edit;
QString m_text;
public:
Destination(QWidget *parent = {}) : QWidget(parent) {
m_layout.addWidget(&m_edit);
connect(this, &Destination::textChanged, &m_edit, &QPlainTextEdit::setPlainText);
}
Q_SLOT void setText(const QString &text) {
if (text == m_text) return;
m_text = text;
emit textChanged(m_text);
}
QString text() const { return m_text; }
Q_SIGNAL void textChanged(const QString &);
};
int main(int argc, char **argv) {
QApplication app{argc, argv};
Source src;
Destination dst;
QObject::connect(&src, &Source::textChanged, &dst, [&](const QString &text){
if (!dst.isVisible()) {
dst.move(src.frameGeometry().topRight()); // align the windows
dst.show();
}
dst.setText(text);
});
src.show();
return app.exec();
}
#include "main.moc"
Related
I trying to display some text to a textbrowser via: FindChild and it never displays it in the textbrowswer any help would be helpfull..
Here is my mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
namespace Ui
{
class MainWindow;
class TestWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow* GetInstance(QWidget* parent = 0);
signals:
public slots:
void on_pushButton_3_clicked();
void MainWindow_TextBrowser_String(const QString & newText);
private:
Ui::MainWindow *ui;
static MainWindow* mainInstance;
};
Here is my mainwindow.cpp
// Constructor
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
// Destructor
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_3_clicked()
{
TestWindow mwindow;
mwindow.start();
}
MainWindow* MainWindow::mainInstance = 0;
MainWindow* MainWindow::GetInstance(QWidget *parent)
{
if (mainInstance == NULL)
{
mainInstance = new MainWindow(parent);
}
return mainInstance;
}
void MainWindow::MainWindow_TextBrowser_String(const QString & newText)
{
QString TextBrowser_String = QString(newText);
ui->textBrowser->append(TextBrowser_String);
}
I create the testwindow object in the pushbutton send the start function to call the findchild window to send a string to the textbrowser window
Here is my testwindow.cpp
void testwindow::start()
{
// Create a new mainwindow on the heap.
MainWindow* instance = MainWindow::GetInstance();
// Or I can call
// MainWindow instance; then point to findchild
QString Test_Window_String = QStringLiteral("Test Window String");
instance->findChild<QTextBrowser*>("textBrowser")->append(Test_Window_String);
}
I understand that you can use a singal and slot and simply just create a signal that sends the string to the append textbrowser
void testwindow::singalandslot()
{
MainWindow* instance = MainWindow::GetInstance();
connect(this, SIGNAL(TextBrowswer_String(const QString &)), instance , SLOT(MainWindow_TextBrowser_String(QString &)));
}
void testwindow::fireSignal()
{
emit TextBrowswer_String("sender is sending to receiver.");
}
Even with a signal or FindChild it seems that the object is already deleted or i'm doing something wrong.
Can you please share your Ui::MainWindow Class and setupUi implementation to get a clear view?
Hope you have created the instance for QTextBrowser* inside setupUi or in the constructor.
With the below setupUi implementation, both ur usecases are working.
namespace Ui
{
class MainWindow: public QWidget
{
Q_OBJECT
public:
QTextBrowser* textBrowser;
void setupUi(QWidget* parent)
{
setParent(parent);
textBrowser = new QTextBrowser(parent);
textBrowser->setObjectName("textBrowser");
textBrowser->setText("Hello");
}
};
}
When i try to put QLabel in QWidget class its not work properly (no hover event or click event only the label pixmap is show) only the last instance work properly, when not use set parent, it create in new window for each label but its work correctly
this gif show the problem:
https://media.giphy.com/media/3o7TKKmZSISGXN4Opq/giphy.gif
this is QLabel subclass header:
#include <QObject>
#include <QLabel>
class myLabel : public QLabel
{
Q_OBJECT
public:
myLabel();
protected:
void mousePressEvent(QMouseEvent *);
void enterEvent(QEvent *);
void leaveEvent(QEvent *);
signals :
void labelClicked();
void enterSignal();
void leaveEventSignal();
private:
};
this class to make a labelButton:
#include <QObject>
#include <QWidget>
#include "mylabel.h"
class labelButton : public QWidget
{
Q_OBJECT
public:
labelButton();
//some functions
private slots:
//slots
private:
//private member
};
and this the class that i want to use the labelButtons in:
#include <QWidget>
#include "labelbutton.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
labelButton *b_1, *b_2, *b_3;
};
here is widget.cpp:
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
b_1 = new labelButton;
b_1->setParent(this);
b_1->moveButton(70, 100);
//some functions to initialize the labelButton
b_1->show();
//-----------------------
b_2 = new labelButton;
b_2->setParent(this);
b_2->moveButton(70, 200);
//some functions to initialize the labelButton
b_2->show();
//-----------------------
b_3 = new labelButton;
b_3->setParent(this);
b_3->moveButton(70, 300);
//some functions to initialize the labelButton
b_3->show();
}
here its work, the problem was in passing the parent
i made a function that take a widget and set buttons parent from the function value
b_1 = new labelButton;
//b_1->setParent(this);
b_1->setParentFunc(this);
b_1->moveButton(70, 100);
//some functions to initialize the labelButton
// b_1->show();
in labelButton:
void labelButton::setParentFunc(QWidget *p)
{
myParent = p;
}
mLabel_1->setParent(myParent); // myParent instead of this
I have been reading about Qt signals and slots and I am trying to get this to work, but until now without success. I hope someone can point me in the right direction.
I have two files, homeCommand.cpp and messagelogcommand.cpp. I have a QPlainTextEdit object in messagelogcommand.cpp that I want to update from homeCommand.cpp.
How can I do this using signals and slots? My signal is being called, as my QDebug is being printed out once a second, however the widget does not update.
This is what I am trying to do:
In MessageLogCommand.h
class MessageLogCommand : public QWidget
{
Q_OBJECT
public:
explicit MessageLogCommand(QWidget *parent = 0);
QLabel *homeLabel;
QPlainTextEdit *messageLog;
public Q_SLOTS:
void updateWidgets(const QString &text);
};
homeCommand.h
class homeCommand : public QWidget
{
Q_OBJECT
Q_SIGNALS:
void textChanged(const QString &text);
public:
explicit homeCommand(QWidget *parent = 0);
public slots:
void run(void);
void getHealthStatusPacket(void);
homeCommand.cpp
homeCommand::homeCommand(QWidget *parent) : QWidget(parent)
{
...
//Timer
QTimer *timer = new QTimer(this);
timer->setSingleShot(false);
connect(timer, SIGNAL(timeout()), this, SLOT(run()));
timer->start(1000);
setLayout(layout);
}
void homeCommand::run(void)
{
getHealthStatusPacket();
}
void homeCommand::getHealthStatusPacket(void)
{
...
Q_EMIT textChanged("ZOMG");
}
In MessageLogCommand.cpp
MessageLogCommand::MessageLogCommand(QWidget *parent) : QWidget(parent)
{
QGridLayout *layout = new QGridLayout;
QWidget::setFixedHeight(600);
//Sub-system Label
homeLabel = new QLabel("GSS Message Log");
QFont subsystemFont = homeLabel->font();
subsystemFont.setPointSize(12);
subsystemFont.setBold(true);
homeLabel->setFont(subsystemFont);
layout->addWidget(homeLabel, 0, 0);
//Event Log
messageLog = new QPlainTextEdit();
messageLog->setFixedHeight(500);
messageLog->setFixedWidth(600);
layout->addWidget(messageLog, 2,0);
setLayout(layout);
}
void MessageLogCommand::updateWidgets(const QString &text)
{
qDebug() << "Here";
messageLog->appendPlainText(text);
}
In main.cpp
MessageLogCommand s;
homeCommand m;
QObject::connect(&m, SIGNAL(textChanged(QString)), &s, SLOT(updateWidgets(QString)));
A very basic example is:
class MainClass:public QObject //class must be derived from QObject!
{
Q_OBJECT //this macro must be in the class definition
//so the moc compiler can generate the necessary glue code
public:
void doSomething() {
...
Q_EMIT textChanged(someText);
}
Q_SIGNALS:
void textChanged(const QString &text);
};
class SubClass:public QObject
{
Q_OBJECT
public Q_SLOTS:
void onTextChanged(const QString &text) { //do not inline
//do something
}
};
int main()
{
QApplication a;
MainClass m;
SubClass s;
QObject::connect(&m, SIGNAL(textChanged(QString)),
&s, SLOT(onTextChanged(QString))); //const and & are removed from
//the arguments
return a.exec(); //run the event loop
}
So, there are 2 things important:
1. Signals and slots must be declared in a class derived from QObject
2. The classes containing signals and slots declarations must add the Q_OBJECT macro to the class declaration
To keep it simple for you: always declare your classes containing signals or slots in a header file (never in a .cpp file).
A very good starting point for signals and slots is: http://woboq.com/blog/how-qt-signals-slots-work.html but also the official Qt doc does it: http://qt-project.org/doc/qt-4.8/signalsandslots.html
Basically what happens: you declare some special methods (signals and slots), at the compilation phase Qt generates extra CPP files which take care of your methods (moc) then everything is compiled and linked together and at the end when Qt or someone else emits a signal it will go to the corresponding slot.
I try to explain it.
In main.h you should to declare a signal:
signals:
void textChanged(const QString& text);
And in messagelog.h you should to declare a slot:
public slots:
void updateWidgets(const QString& text);
In main.cpp you should emit this signal:
void TheMethod() {
emit this->textChanged("Your text/value");
}
In messagelog.cpp you should get this value:
// Note: Normalized signal/slot signatures drop the consts and references.
connect(&a, SIGNAL(textChanged(QString)), this, SLOT(updateWidgets(QString)));
void updateWidgets(const QString& text) {
messageLog = new QPlainTextEdit();
messageLog->setFixedHeight(500);
messageLog->setFixedWidth(600);
messageLog->setPlainText(text)
layout->addWidget(messageLog, 2,0);
}
I think it should works.
UPDATE:
Complete example: https://dl.dropboxusercontent.com/u/29647980/test.zip
I want to convert a QString from another class toInt, but it seams to fail because the result is 0 while it should be 5 and the rest of the code works.
Because I am new to C/Qt and find classes a bit confusing, I think I have done something wrong with my classes.
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
MyClass tmp;
int myNumber = tmp.m_replyStr.toInt();
ui->lcdNumber->display(myNumber);
}
MyClass::MyClass()
{
m_manager = new QNetworkAccessManager(this);
connect( m_manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
}
void MyClass::fetch()
{
m_manager->get(QNetworkRequest(QUrl("http://example.tld/test.html"))); // html contains only the number 5
}
void MyClass::replyFinished(QNetworkReply* pReply)
{
QByteArray data=pReply->readAll();
QString str(data);
m_replyStr = str;
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QObject>
#include <QNetworkAccessManager>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
};
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass();
void fetch();
QString m_replyStr;
public slots:
void replyFinished(QNetworkReply*);
private:
QNetworkAccessManager* m_manager;
};
#endif // WIDGET_H
You're accessing m_replyStr of a newly initialised instance tmp, which doesn't set anything into its m_replyStr. So it has the default-initialised value of "empty string."
EDIT
Based on your follow-up question, perhaps you were looking for something like this?
class MyClass;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(MyClass &myClassInstance, QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
MyClass *myClass;
};
Widget::Widget(MyClass &myClassInstance, QWidget *parent = 0)
: QWidget(parent)
, ui(new Ui::Widget)
, myClass(&myClassInstance)
{
ui->setupUi(this);
}
void Widget::on_pushButton_clicked()
{
int myNumber = myClass->m_replyStr.toInt();
ui->lcdNumber->display(myNumber);
}
I have two classes, MyClass and Widget. Below is the MyClass class and from my Widget class i want to get the str variable. How is that done?
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass();
void fetch();
public slots:
void replyFinished(QNetworkReply*);
private:
QNetworkAccessManager* m_manager;
};
MyClass::MyClass()
{
m_manager = new QNetworkAccessManager(this);
connect( m_manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
}
void MyClass::fetch()
{
m_manager->get(QNetworkRequest(QUrl("http://stackoverflow.com")));
}
void MyClass::replyFinished(QNetworkReply* pReply)
{
QByteArray data=pReply->readAll();
QString str(data);
//this str should be available in my widget class
}
EDIT: Here is a the important part of the widget
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
};
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
//here str should be accessed
}
If you want the str variable from your function available to classes or other functions, here are two choices:
Return it from the function.
Declare a variable in MyClass to hold the string and set the
variable to the value.
Case 1: Returning from a function
QString MyClass::replyFinished(...)
{
QString str(data);
return data;
}
Case 2: Declare a class member variable
class MyClass
{
public:
QString m_replyStr;
};
//...
void MyClass::replyFinished(...)
{
QByteArray data = pReply->readAll();
m_replyStr = data;
}
Modifying your question with an example of what you want to do would be very helpful.
You can emit a signal with str as argument and connect it to a slot in your widget. Then you can do what you want with it.
This way you will preserve the event oriented design and you have not need to control if str exists. Simply when it's ready the slot will handle it.
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass();
void fetch();
public slots:
void replyFinished(QNetworkReply*);
signals:
void strReplyReady(QString str);
private:
QNetworkAccessManager* m_manager;
};
...
void MyClass::replyFinished(QNetworkReply* pReply)
{
QByteArray data=pReply->readAll();
QString str(data);
emit strReplyRead(str);
}
your Widget
class MyWidget : public QWidget
{
//public members
...
public slots:
void readReply(QString str);
}
void MyWidget::readReply(QString str){
//do what you want with str
}
in the main.cpp you do the connect with the static member of QObject
QObject::connect(myClassPointer,SIGNAL(strReplyReay(QString)) ,
myWidgetPointer,SLOT(readReply(QString)));