Share data between two QWidget instances - c++

I would like share a string between two instances of QWidget.
In main.cpp, two objects are instantiated and shown like this:
#include "dialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w1,w2; //Derived from QWidget
w1.show();
w2.show();
return a.exec();
}

I would introduce SharedState class:
// shared_state.h
#ifndef SHARED_STATE_HPP
#define SHARED_STATE_HPP
#include <QObject>
class SharedState : public QObject
{
Q_OBJECT
public:
SharedState(QString initialValue = "")
: currentValue(initialValue)
{}
QString getCurrentValue()
{
return currentValue;
}
public slots:
void setValue(QString newValue)
{
if(currentValue != newValue)
{
currentValue = newValue;
emit valueChanged(currentValue);
}
}
signals:
void valueChanged(QString);
private:
QString currentValue;
};
#endif // SHARED_STATE_HPP
Now I would provide reference to SharedState in Dialog's constructor,
// dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QWidget>
#include "shared_state.h"
namespace Ui {
class Dialog;
}
class Dialog : public QWidget
{
Q_OBJECT
public:
explicit Dialog(SharedState& state, QWidget *parent = 0);
~Dialog();
private slots:
void handleTextEdited(const QString&);
public slots:
void handleInternalStateChanged(QString);
private:
Ui::Dialog *ui;
SharedState& state;
};
#endif // DIALOG_H
You may have noticed that I have added two slots, one to handle the case when the text is manually edited and one when shared state will inform us that we are out of date.
Now in Dialog's constructor I had to set initial value to textEdit, and connect signals to slots.
// dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(SharedState& state, QWidget *parent) :
QWidget(parent),
ui(new Ui::Dialog),
state(state)
{
ui->setupUi(this);
ui->textEdit->setText(state.getCurrentValue());
QObject::connect(ui->textEdit, SIGNAL(textEdited(QString)),
this, SLOT(handleTextEdited(QString)));
QObject::connect(&state, SIGNAL(valueChanged(QString)),
this, SLOT(handleInternalStateChanged(QString)));
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::handleTextEdited(const QString& newText)
{
state.setValue(newText);
}
void Dialog::handleInternalStateChanged(QString newState)
{
ui->textEdit->setText(newState);
}
Now the change in the main function:
// main.cpp
#include "dialog.h"
#include "shared_state.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
SharedState state("Initial Value");
Dialog w1(state), w2(state);
w1.show();
w2.show();
return a.exec();
}

Related

How do I edit QMainWindow UI Widget From Another Class?

I need to edit a QLabel from MainWindow's UI in another source file. I've tried messing around with singals and slots, but honestly I'm completely lost and the Qt documentation doesn't help me in this exact situation. I understand that this has been asked in the past, but I have not found a solution that works for me. I'm new to Qt, and C++ in general.
I have the following code (greatly simplified):
"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();
void setFoo(char* text);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
"mainwindow.cpp"
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
ui->setupUi(this);
this->statusBar()->setSizeGripEnabled(false);
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::setFoo(char* text) {
ui->fooLabel->setText(text);
}
"secondwindow.h"
#ifndef SECONDWINDOW_H
#define SECONDWINDOW_H
#include <QWidget>
namespace Ui {
class SecondWindow;
}
class SecondWindow: public QWidget {
Q_OBJECT
public:
explicit SecondWindow(QWidget *parent = 0);
~SecondWindow();
private:
Ui::SecondWindow*ui;
}
#endif // SecondWindow_H
"secondwindow.cpp"
#include "secondwinodw.h"
#include "ui_secondwinodw.h"
#include "mainwindow.h"
SecondWindow::SecondWindow(QWidget *parent) :
QWidget(parent),
ui(new Ui::SecondWindow) {
ui->setupUi(this);
}
SecondWindow::~SecondWindow() {
delete ui;
}
void SecondWindow::on_fooButton_clicked() {
MainWindow::setFoo("example");//The method is private so this is not possible, but this is my goal
}
When a user clicks on fooButton, I need to access and edit the MainWindow's UI QLabel(or a public method that does this).
The secondwindow is not being created in the main() function
void MainWindow::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_A:
if (event->modifiers()==Qt::ShiftModifier) {
SecondWindow*secwind= new SecondWindow();
secwind->show();
}
break;
}
}
In OOP the ones that interact are the objects, not the classes or the files, that is, the following expression:I need to edit QLabel from MainWindow's UI in another source file It does not make sense, what you should say is that an object of the MainWindow class is modified by another object of the SecondWindow class. The files do not make the program, the interaction between objects do it.
I'm assuming that both objects are created in the main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w1;
SecondWindow w2;
w1.show();
w2.show();
return a.exec();
}
Now if I go to attack the main problem, Qt handles the concept of signals and slots, so we will use it, as the action to a SecondWindow object will cause the information to be sent, I will create a signal that carries that information:
secondwindow.h
#ifndef SECONDWINDOW_H
#define SECONDWINDOW_H
#include <QWidget>
namespace Ui {
class SecondWindow;
}
class SecondWindow: public QWidget {
Q_OBJECT
public:
explicit SecondWindow(QWidget *parent = 0);
~SecondWindow();
signals:
void messageChanged(const QString & message); // <---
private slots:
void void SecondWindow::on_fooButton_clicked();
private:
Ui::SecondWindow*ui;
}
#endif // SecondWindow_H
when the button is pressed, the signal with the information must be emitted
secondwindow.cpp
...
void SecondWindow::on_fooButton_clicked() {
emit messageChanged("example");//The method is private so this is not possible, but this is my goal
}
Now we go to the receiver's side, how will we get a slots, you have done it but do not use char *, that's C, we're using C++ and much better we're using Qt, it's best to use QString:
mainwindow.h
....
void setFoo(const QString & text);
mainwindow.cpp
...
void MainWindow::setFoo(const QString & text) {
ui->fooLabel->setText(text);
}
And finally we make the connections:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w1;
SecondWindow w2;
QObject::connect(&w2, &SecondWindow::messageChanged, &w1, &MainWindow::setFoo);
w1.show();
w2.show();
return a.exec();
}
update:
void MainWindow::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_A:
if (event->modifiers()==Qt::ShiftModifier) {
SecondWindow*secwind= new SecondWindow();
connect(secwind, &SecondWindow::messageChanged, this, &MainWindow::setFoo);
secwind->show();
}
break;
}
}

Qt5: error: ‘qt_metacall’ is not a member of

I try to become more familiar with singnals and slots with Qt.
I want to emit a signal in one class and want to handle it at one other.
Here my example code:
main.c
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class Emiter
{
signals:
void anSignal ();
};
class MainWindow : public QMainWindow
{
Q_OBJECT
private slots:
void handleEmitter ();
public:
MainWindow(QWidget *parent = 0);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
auto emiter = new Emiter();
connect( emiter,
&Emiter::anSignal,
this,
&MainWindow::handleEmitter );
}
void
MainWindow::handleEmitter()
{
}
Then I get this error:
error: ‘qt_metacall’ is not a member of ‘Emiter’ enum { Value = sizeof(test(&Object::qt_metacall)) == sizeof(int) };
What does this mean?
Signals and slots are available only in QObject derived classes, and a Q_OBJECT macro is needed.
class Emiter : public QObject
{
Q_OBJECT
public:
signals:
void anSignal ();
};
For more detail answer: click here
Another case is if you use multiple inheritances, you need to put QObject as the first parent class.

Qt make modification of MainWindow from another class

I would like to make some modifications of the main window from another file.
I created another ui file Form1Window (which open when a button is cliked in the MainWindow).
I want to call from the class Form1Window a function named test() of the MainWindow class
I succeed in calling function test() but I can't execute the whole content of the function (I can display a message but can't execute the part where I want to clear an edittext)
MainWindow.h
#include "form1window.h"
public slots:
void nettoyer();
private slots:
void openFrom1();
private:
Ui::MainWindow *ui;
From1Window *uiFrom1;
};
MainWindow.cpp
void MainWindow::openFrom1()
{
uiFrom1 = new From1Window(this);
uiFrom1->show();
}
void MainWindow::nettoyer(){
QMessageBox msgBox;
msgBox.setText("test");
msgBox.setIcon(QMessageBox::Information);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.exec();
ui->auteur->clear();
//THIS LINE HAS NO EFFECT WHEN CALLED FROM THE OTHER CLASS
}
form1window.cpp
#include "mainwindow.h"
#include "ui_form1window.h"
void From1Window::on_supprimer_clicked()
{
MainWindow *a=new MainWindow ();
a->test();
close();
}
I've read about the role of the pointer of MainWindow class (C++ /Qt Proper way to access ui from another class in qt //Edited) and I've also tried connect()
Thank for your help
//THIS LINE HAS NO EFFECT WHEN CALLED FROM THE OTHER CLASS
this->ui->auteur->clear();
The line will never executed unless you dismiss QMessageBox. This is because you triggered QMessageBox with exec() function. This function has its own event queue and does not return until finishes. You may set QMessageBox as modal and display it with show() method. In that case QMessageBox will not block execution of the the flow.
This problem can also happen with QDialog(s) if you display them with exec().
I provide you a simple two window signal/slot example:
main.cpp
#include "mainwindow.h"
#include "form.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Form f;
f.show();
return a.exec();
}
form.h
#ifndef FORM_H
#define FORM_H
#include <QWidget>
#include <QPushButton>
class Form : public QWidget
{
Q_OBJECT
public:
explicit Form(QWidget *parent = 0);
~Form();
private:
QPushButton *pb;
};
#endif // FORM_H
form.cpp
#include "form.h"
#include "mainwindow.h"
#include <QDebug>
Form::Form(QWidget *parent) : QWidget(parent)
{
MainWindow *mw = new MainWindow();
pb = new QPushButton("clickME", this);
QObject::connect(pb, SIGNAL(clicked()), mw, SLOT(test()));
mw->show();
}
Form::~Form()
{
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLabel>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void test();
private:
QLabel *l;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
l = new QLabel("test", this);
}
MainWindow::~MainWindow()
{
}
void MainWindow::test() {
qDebug() << "test called!" << endl;
l->setText("text changed");
}
This works for me.
output

QT project QThread and C++ Thread limitations

mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileSystemModel>
#include <QThread>
#include <statusdialog.h>
#include <pbt.h>
#include <stdint.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
//void on_treeView_clicked(const QModelIndex &index);
void onCustomContextMenuTV(const QPoint &point);
void dirSize();
void getSelectedTreeItemSize();
void resultHandle(uint64_t);
signals:
void sizeCalculation(uint64_t);
private:
Ui::MainWindow *ui;
QString sPath;
QFileSystemModel *dirmodel;
QFileSystemModel *filemodel;
QAction *dirSizeAct;
statusDialog statusdialog;
};
#endif // MAINWINDOW_H
pbt.h
#ifndef STATUSDIALOG_H
#define STATUSDIALOG_H
#include <QDialog>
#include <stdint.h>
namespace Ui {
class statusDialog;
}
class statusDialog : public QDialog
{
Q_OBJECT
public:
explicit statusDialog(QWidget *parent = 0);
~statusDialog();
void setProgressbarMax(uint64_t);
private slots:
void on_pushButton_clicked();
private:
Ui::statusDialog *ui;
};
#endif // STATUSDIALOG_H
statusdialog.h
#ifndef STATUSDIALOG_H
#define STATUSDIALOG_H
#include <QDialog>
#include <stdint.h>
namespace Ui {
class statusDialog;
}
class statusDialog : public QDialog
{
Q_OBJECT
public:
explicit statusDialog(QWidget *parent = 0);
~statusDialog();
void setProgressbarMax(uint64_t);
private slots:
void on_pushButton_clicked();
private:
Ui::statusDialog *ui;
};
#endif // STATUSDIALOG_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
sPath = "C:/";
dirmodel = new QFileSystemModel(this);
dirmodel->setFilter(QDir::NoDotAndDotDot | QDir::AllDirs);
dirmodel->setRootPath(sPath);
ui->treeView->setModel(dirmodel);
ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->treeView, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onCustomContextMenuTV(const QPoint &)));
connect(this,SIGNAL(sizeCalculation(uint64_t)),this,SLOT(resultHandle(uint64_t)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::resultHandle(uint64_t t_size)
{
statusdialog.setProgressbarMax(t_size);
}
void MainWindow::onCustomContextMenuTV(const QPoint &point)
{
dirSizeAct = new QAction(tr("Size"), this);
connect(dirSizeAct, SIGNAL(triggered()), this, SLOT(dirSize()));
QMenu contextMenu(this);
contextMenu.addAction(dirSizeAct);
QModelIndex index = ui->treeView->indexAt(point);
if (index.isValid()){
contextMenu.exec(ui->treeView->mapToGlobal(point));
}
}
void MainWindow::dirSize()
{
pBT pbt;
pbt.setFP(this->getSelectedTreeItemSize);
QThread thread1;
connect(&thread1,SIGNAL(started()),&pbt,SLOT(startThreadAction()));//Clone the object and it will not work, becouse it is QWidget
pbt.moveToThread(&thread1);
thread1.start();//Starts in the same thread
statusdialog.setModal(true);
statusdialog.exec();
}
void MainWindow::getSelectedTreeItemSize()
{
QModelIndex index = ui->treeView->selectionModel()->selectedIndexes().takeFirst();
QString dirPath = dirmodel->filePath(index);
QDirIterator it(dirPath, QStringList() << "*.*", QDir::Files, QDirIterator::Subdirectories);
uint64_t t_size = 0;
while (it.hasNext()) {
QFile myFile(it.next());
if (myFile.open(QIODevice::ReadOnly)){
t_size += myFile.size();
myFile.close();
}
}
emit sizeCalculation(t_size);
}
pbt.cpp
#include "pbt.h"
pBT::pBT(QObject *parent) : QObject(parent)
{
}
void pBT::startThreadAction()
{
this->fp1();
}
void pBT::setFP(void (*fp1)())
{
this->fp1 = fp1;
}
statusdialog.cpp
#include "statusdialog.h"
#include "ui_statusdialog.h"
statusDialog::statusDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::statusDialog)
{
ui->setupUi(this);
}
statusDialog::~statusDialog()
{
delete ui;
}
void statusDialog::on_pushButton_clicked()
{
this->close();
}
void statusDialog::setProgressbarMax(uint64_t size)
{
ui->progressBar->setMaximum(size);
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
To see more info of what I am doing you can look this topic(It is all about prograssbar and threaded execution of job). Theoretically I whant to run a member function of mainwindow(which use member variables of mainwindow) into new thread(the function is not static) inside slot dirSize()(also member slot of the same class mainwindow), but it seems with QThread it is necessary to create new class(no matter if I will inherit QThread class or use moveToThread function of QObject) and run that class in new thread. If I use C++ thread.h the function I run must be static, nevermind I have tried to create pBT class in which I have function pointer fp1 and public slot startThreadedAction, but when try to buil this error occures:
C:\Users\niki\Documents\EPsimple\mainwindow.cpp:54: error: C3867:
'MainWindow::getSelectedTreeItemSize': function call missing argument
list; use '&MainWindow::getSelectedTreeItemSize' to create a pointer
to member
I don`t want to create function pointer to static function! How can I fix this?

How to create object widget in other widgets in QT

In my application im having three widgets named as "Widget" , "one" and "two" . i tried to create the objects of the widget in main function as pass it as an argument to another widgets . it compiles successfully but application crashed before running , refer my code below and guide me,
//main.cpp
#include <QtGui/QApplication>
#include "widget.h"
#include "one.h"
#include "two.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget *w;
One *one;
Two *two;
w->GetObject(one,two);
one->GetObject(w,two);
two->GetObject(one,w);
w->show();
return a.exec();
}
//widget.cpp
#include "widget.h"
Widget::Widget(QWidget *parent) :QWidget(parent)
{
setupUi(this);
}
void Widget::GetObject(One *onee, Two *twoo)
{
one=onee;
two=twoo;
}
//widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include "ui_widget.h"
class One;
class Two;
class Widget : public QWidget, private Ui::Widget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
One *one;
Two *two;
void GetObject(One *onee, Two *twoo);
};
#endif // WIDGET_H
//one.cpp
#include "one.h"
One::One(QWidget *parent) :QWidget(parent)
{
setupUi(this);
}
void One::GetObject(Widget *widgett, Two *twoo)
{
widget = widgett;
two = twoo;
}
void One::on_pushButton_clicked()
{
widget->show();
}
//one.h
#ifndef ONE_H
#define ONE_H
#include "ui_one.h"
class Widget;
class Two;
class One : public QWidget, private Ui::One
{
Q_OBJECT
public:
explicit One(QWidget *parent = 0);
Widget *widget;
Two *two;
void GetObject(Widget *widgett, Two *twoo);
private slots:
void on_pushButton_clicked();
};
#endif // ONE_H