Singleton thread-safe programs - c++

I'm trying to write a simple app with singleton design in Qt. Below is the header file:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
static MainWindow *getInstance();
~MainWindow();
private:
explicit MainWindow(QWidget *parent = 0);
static MainWindow *uniqueInstance;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
And here is implementation file:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow* MainWindow::uniqueInstance = new MainWindow();
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
MainWindow* MainWindow::getInstance()
{
return uniqueInstance;
}
Finally here is the main function:
#include <QApplication>
#include "mainwindow.h"
#include "QThread"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow *w = MainWindow::getInstance();
w->show();
return a.exec();
}
Building of my program is OK. But I receive a run-time error "QWidget: Must construct a QApplication before a QWidget". What should I do for solving this problem? I want to use this form of singleton to have a thread-safe program.
Thanks in advance for your helps.
Reza

The Qt-idiomatic way of holding a global object instance thread-safely is through Q_GLOBAL_STATIC. The instance is created on the first use. This way, your singleton instance will be created when needed, after QApplication instance exists.
Instead of MainWindow* MainWindow::uniqueInstance = new MainWindow(), you'd write:
Q_GLOBAL_STATIC(MainWindow, uniqueInstance);

Based on previous answers and also http://doc.qt.io/qt-5/qglobalstatic.html#Q_GLOBAL_STATIC, the answer is like below:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
friend class myClass;
public:
static MainWindow *getInstance();
~MainWindow();
private:
explicit MainWindow(QWidget *parent = 0);
Ui::MainWindow *ui;
};
class myClass : public MainWindow
{
};
#endif // MAINWINDOW_H
.cpp file is like below:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGlobalStatic>
Q_GLOBAL_STATIC(myClass,uniqueInstance)
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
MainWindow* MainWindow::getInstance()
{
return uniqueInstance;
}
finally main file is like below:
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow *w = MainWindow::getInstance();
w->show();
return a.exec();
}
And that works and is thread-safe.

MainWindow* MainWindow::uniqueInstance = new MainWindow();
this is global instance, it happens before the main function, so this constructor is earlier than the main function, which is not allowed. Qt needs to construct QApplication first, then the widget. so you need to move this after constructor the QApplication in main, or just remove it.
MainWindow* MainWindow::uniqueInstance = 0;
then constructor the object after QApplication.
As I said, you should NOT constructor the uniqueInstance before main, modified some code basing on your POST, it should work.
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow* MainWindow::uniqueInstance = 0;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
MainWindow* MainWindow::getInstance()
{
if (0 == MainWindow::uniqueInstance){
MainWindow::uniqueInstance = new MainWindow();
}
return MainWindow::uniqueInstance;
}
Basing on Kuba's POST, there is introduced a new global MACRO for creating this kind of SINGLETON (Q_GLOBAL_STATIC http://qt-project.org/forums/viewthread/13977), it is more elegant, however, this macro only exists in Qt5, not Qt4, and also has some usage limit you should notice. Basically it is also a macro for wrapping code to create singleton at runtime.

Related

How to access contents of ui from a external function?

.h
class MainWindow: public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
Ui::MainWindowClass ui;
private slots:
void on_pushButton_clicked();
};
.cpp
void Test()
{
MainWindow mw;
mw.ui.pushButton->move(QPoint(200, 200));
qDebug() << "test" << "\n";
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
QShortcut *shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this);
QObject::connect(shortcut, &QShortcut::activated, this, &Test);
return;
}
How to access the contents of ui from the class MainWindow in the function Test without making Test a child/inherit MainWindow?
I think the way i did is not working as when the function is called with the shortcut the button isnt moved.
Qt compiles ui files into ui_<ui_name>.h (you can see them in your build folder).
So you can use ui just include ui_<ui_name>.h
Example
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
Ui::MainWindow *ui;
private:
};
#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);
}
MainWindow::~MainWindow()
{
delete ui;
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include "ui_mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
w.ui->progressBar->setValue(30);
return a.exec();
}

How to access other class's object in Qt?

In the program, I want to click a button in the main window and trigger the sub-window to display the image. But I cannot access ui->graphsView in the main window.cpp, how can I do that? In the main.cpp. the click-button function is assumed to do such thing. The QGraphicsView is placed in the ShowPic class.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileSystemModel>
#include "showpic.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QFileSystemModel *model;
ShowPic *showpic;
QString filesPath;
};
#endif // MAINWINDOW_H
showpic.h
#ifndef SHOWPIC_H
#define SHOWPIC_H
#include <QWidget>
namespace Ui {
class ShowPic;
}
class ShowPic : public QWidget
{
Q_OBJECT
public:
explicit ShowPic(QWidget *parent = 0);
~ShowPic();
private:
Ui::ShowPic *ui;
};
#endif // SHOWPIC_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QFileDialog>
#include<QFileSystemModel>
#include<QStringList>
#include <QTreeView>
#include <QGraphicsScene>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
showpic = new ShowPic();
showpic->show();
QGraphicsScene scene;
QPixmap pixmap("C:\test\\image.jpg");
scene.addPixmap(pixmap);
ui->graphicsView->setScene(&scene); ///????
}
showpic.cpp
#include "showpic.h"
#include "ui_showpic.h"
ShowPic::ShowPic(QWidget *parent) :
QWidget(parent),
ui(new Ui::ShowPic)
{
ui->setupUi(this);
}
ShowPic::~ShowPic()
{
delete ui;
}
The first thing is that you have to add the QGraphicsScene only once, and a suitable place is in the constructor:
ShowPic::ShowPic(QWidget *parent) :
QWidget(parent),
ui(new Ui::ShowPic)
{
ui->setupUi(this);
ui->graphicsView->setScene(new QGraphicsScene);
}
Then we create a method that receives the pixmap and adds it to the scene:
showpic.h
[...]
explicit ShowPic(QWidget *parent = 0);
~ShowPic();
void addPixmap(const QPixmap &pixmap);
[...]
showpic.h
[...]
void ShowPic::addPixmap(const QPixmap &pixmap){
ui->graphicsView->scene()->addPixmap(pixmap);
}
[...]
And we use that method in the slot on_pushButton_clicked:
void MainWindow::on_pushButton_clicked()
{
showpic = new ShowPic();
QPixmap pixmap("C:\test\\image.jpg");
showpic->addPixmap(pixmap);
showpic->show();
}

How correctly to call a function from another file?

OK, let's start again...
I've created an project (Qt Widget Application) with Qt Creator.
My project structure:
myproject.pro
Headers
dialogform.h
mainwindow.h
Sources
dialogform.cpp
main.cpp
mainwindow.cpp
Forms
dialogform.h
mainwindow.h
When I click on DialogForm pushbutton, I need to call the clear() function from MainWindow
In my code below, my project is running, but, the clear() function does not clear the lineedit.
Do anyone known how can i fix this?
Thank you very much!
dialogform.h
#ifndef DIALOGFORM_H
#define DIALOGFORM_H
#include <QDialog>
namespace Ui {
class DialogForm;
}
class DialogForm : public QDialog
{
Q_OBJECT
signals:
void clearMainWindow();
public:
explicit DialogForm(QWidget *parent = 0);
~DialogForm();
private slots:
void on_pbClearLineEdit_clicked();
private:
Ui::DialogForm *ui;
};
#endif // DIALOGFORM_H
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();
public slots:
void clear();
private slots:
void on_pbCallDialog_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
dialogform.cpp
#include "dialogform.h"
#include "ui_dialogform.h"
#include "mainwindow.h"
DialogForm::DialogForm(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogForm)
{
ui->setupUi(this);
}
DialogForm::~DialogForm()
{
delete ui;
}
void DialogForm::on_pbClearLineEdit_clicked()
{
connect(); // need help here. I'm using Qt 5.6.1
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialogform.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pbCallDialog_clicked()
{
DialogForm *dialogForm = new DialogForm(this);
dialogForm->show();
}
void MainWindow::clear()
{
ui->lineEdit->clear();
}
myfunction accesses an attribute of class myfile. Therefore it either needs to be a method of myfile as well, or it could be a friend function of the class myfile. In the latter case, however, you would need to give the relevant instance of myfile to myfunction as an argument. All usages of myfunction would need to be updated in either case.
The solution:
DialogForm::DialogForm(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogForm)
{
ui->setupUi(this);
connect(ui->pbClearLineEdit, &QPushButton::clicked, static_cast<MainWindow*>(parent), &MainWindow::clear);
}

Using Signals and Slots to Comunicate a QDialog with MainWindow in Qt

Ok I think is time to get some help, I have been practicing with signals and slots in Qt and I got stocked. What I want is to be able to change a label in mainwindow when a button in a QDialog is clicked. I have been searching and apparently the only way to do this is basically using signals and slots, here is what I have...
I have a mainwindow.ui with a button called "pushButton_OpenWindow" and a QLabel label_ShowText", I also have a externaldialog.ui that contains a QLineEdit called lineEdit_ExternalInput" and a QPushButton called "pushButton_SendText", and what I want is to change "label_ShowText" to whatever value "lineEdit_ExternalInput" is when pushButton_SendText" is clicked but it doesn't work, when I click the button nothing happens no errors, no warnings nothing.
Here is the code that doesn't work...
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();
private slots:
void on_pushButton_OpenWindow_clicked();
void textValue(const QString &newText);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "externaldialog.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ExternalDialog *externalDialog = new ExternalDialog;
// connecting signals and slots
QObject::connect(externalDialog, SIGNAL(textChanged(QString)), this, SLOT(textValue(QString)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_OpenWindow_clicked()
{
ExternalDialog mDialog;
mDialog.setModal(true);
mDialog.exec();
}
void MainWindow::textValue(const QString &newText)
{
ui->label_ShowText->setText(newText);
qDebug()<<"Message from textValue Function \n";
}
externaldialog.h
#ifndef EXTERNALDIALOG_H
#define EXTERNALDIALOG_H
#include <QDialog>
namespace Ui {
class ExternalDialog;
}
class ExternalDialog : public QDialog
{
Q_OBJECT
public:
explicit ExternalDialog(QWidget *parent = 0);
~ExternalDialog();
private:
Ui::ExternalDialog *ui;
signals:
void textChanged(const QString&);
public slots:
void on_pushButton_SendText_clicked();
};
#endif // EXTERNALDIALOG_H
externaldialog.cpp
#include "externaldialog.h"
#include "ui_externaldialog.h"
#include <QDebug>
ExternalDialog::ExternalDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ExternalDialog)
{
ui->setupUi(this);
}
ExternalDialog::~ExternalDialog()
{
delete ui;
}
void ExternalDialog::on_pushButton_SendText_clicked()
{
emit textChanged(ui->lineEdit_ExternalInput->text());
qDebug()<<"Sent Message";
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Any idea what I'm I doing wrong? Any suggestion will be appreciated. Sorry I posted the whole code but sometimes is better to see the whole picture.
Thanks a lot
change function MainWindow::on_pushButton_OpenWindow_clicked() into this
void MainWindow::on_pushButton_OpenWindow_clicked()
{
externalDialog->setModal(true);
externalDialog->exec();
}
You have just create a new unconnected dialog in the original function.

Add new tab after file -> new

I am writing a simple editor i Qt and C++. I want to have tabs, so after creating a new document, I want to open this in a new tab. My code:
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle("emacs");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionExit_triggered()
{
qApp->exit(0);
}
void MainWindow::on_actionNew_triggered()
{
// what to write here?
}
// main.cpp
#include <QtGui/QApplication>
#include "mainwindow.h"
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>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_actionExit_triggered();
void on_actionNew_triggered();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
I have successfully managed to create an action to exit the program. But when I try something like this: tabWidget->addTab(new QWidget(),"new tab"); is complaints that tabWidget was not declared in the scope. Anybody? Thanks!
tabWidget is not a member of your MainWindow class, I'm guessing its an object you defined in your ui file, so try:
ui->tabWidget->addTab(...);