I'm working on a gui app with cpp and gtkmm3.
In this app, some widgets require the singleton pattern to implement such as window (because i want just one window in all over the app)
this is my header file:
class MyWindow : public Gtk::ApplicationWindow {
public:
MyWindow(BaseObjectType *pWindow, Glib::RefPtr<Gtk::Builder> builder);
~MyWindow();
MyWindow(MyWindow const&) = delete;
void operator=(MyWindow const&) = delete;
static MyWindow* getInstance();
private:
MyWindow();
};
and source file is :
MyWindow::MyWindow(){}
MyWindow::MyWindow(BaseObjectType *pWindow, Glib::RefPtr<Gtk::Builder> refBuilder)
: Gtk::ApplicationWindow(pWindow),
builder(refBuilder) {
}
MyWindow::~MyWindow() {}
MyWindow *MyWindow::getInstance() {
static MyWindow *window;
return window;
}
my question is:
Is there a more appropriate and reasonable pattern instead singleton pattern ?
Is using this pattern suitable for the interface widgets and gui app ?
The major problem with the Singleton design pattern is that it gives you:
a single instance AND
global access.
The single instance aspect of the singleton is what people usually are looking for (like in your case), but not global access.
The usual "alternative" to this is to declare a MyWindow instance and then inject it to anyone who needs it. This is known as dependency injection. So you have something like:
void DoSomeThingOnWindow(MyWindow& p_window)
{
p_window.DoSomething();
}
// At the beginning:
MyWindow window;
// Everywhere else:
DoSomeThingWithTheWindow(window);
instead of:
void DoSomeThingOnWindow()
{
// Global access:
MyWindow* window = MyWindow::getInstance();
window->DoSomething();
}
// Everywhere:
DoSomeThingWithTheWindow();
The "bad" side of dependency injection over a singleton is that it will not enforce the single instance. However, if you use it everywhere and carefully, you can pass a single instance all around and not have global access, which will have so much more benefits.
Related
I've just begun to learn Qml.Altought i read too many qt tutorial, still struggling with some problems.
I want to make multipages desktop application using OpenGL.
First of all, in main function of the program, i am transmitting class instance so that i could access them in qml by using below code snippet.
QQmlApplicationEngine engine;
Foo foo;
engine.rooContext()->setContextProperty(QStringLiteral("foo"),&foo);
But if i must instance all of classes that i want to use in qml, it means there will be a hundred of instances in main function. I think there must be more proper way to do it.
Secondly, if we register object by using qmlRegisterType and import in qml file, can i reach property of bar class after active qml changed ? Because as far as i know, object of bar class is created when corresponding qml is loaded.
Project.cpp
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
qmlRegisterType<bar>("MyLib", 1, 0, "Comp");
qmlRegisterType<bar2>("MyLib2", 1, 0, "Comp2");
QQmlApplicationEngine engine;
Foo foo;
engine.rooContext()->setContextProperty(QStringLiteral("foo"),&foo);
.
.
.
}
GlWindow.qml
import QtQuick 2.0
import MyLib 1.0
Comp
{
id:sample
}
GlWindow2.qml
import QtQuick 2.0
import MyLib2 1.0
Comp2
{
id:sample2
}
bar.h
class bar: public QObject
{
Q_OBJECT
public:
Product* product;
void initialize();//Initialize Gl
void render(); //paint product's context
}
bar2.h
class bar2: public QObject
{
Q_OBJECT
public:
Product* product2;
void initialize();//Initialize Gl
void render(); //paint product's context
}
I painted content of product on GlWindow.qml after that closed this qml and showed GlWindow2.qml. My problem starts here, how to transmit content of product to product2?
For your first concern you can create a "main model" with properties for each of your models you would otherwise have added to the rootContext:
Class MainModel : public QObject
{
Q_OBJECT
Q_PROPERTY(Foo1 *foo1 READ foo1 CONSTANT)
Q_PROPERTY(Foo2 *foo2 READ foo2 CONSTANT)
....
Q_PROPERTY(FooN *fooN READ fooN CONSTANT)
}
If you fancy some design patterns, you can also go the kinda dependency injection rout:
Class Injector : public QObject
{
public:
Q_INVOKABLE QObject* getFoo(const QString& fooName);
}
This has the downside of losing the strong typed return value, but on the plus side you can use caching etc.
About your second question: you are correct, programming it like that it's hard to gain access from the C++ side (assuming that's what you mean) unless you make it a singleton:
class bar : public QObject
{
public:
bar *instance()
{
static bar theInstance;
return &theInstance;
}
};
//main.cpp
qmlRegisterSingleton<bar>("MyLib", 1, 0, "Comp", [](QQmlEngine *eng, QJSEngine *js) -> QObject*
{
return bar::instance();
});
But you probably tried that route because you didn't see the "main model" idea.
Also your last question about passing information between models can likely be easily solved by having a nice "main model" where classes know about each other, or can signal and the "main model" connects the signals and slots.
I am trying to create a standard JS library that is mostly shaped like Qbs (which uses deprecated QScriptEngine) with QJSEngine, so people who make Qt software can add things like file-operations to their plugin JS environment.
You can see the repo here
I've got basic classes exposed to the JS engine, like this:
QJSEngine jsEngine;
jsEngine.installExtensions(QJSEngine::AllExtensions);
jsEngine.globalObject().setProperty("BinaryFile", jsEngine.newQMetaObject(&Qbs4QJS::BinaryFile::staticMetaObject));
but I can's seem to figure out how to get a reference to the QJSEngine, inside a function, so I can throw an error:
Q_INVOKABLE BinaryFile(const QString &filePath, QIODevice::OpenModeFlag mode = QIODevice::ReadOnly) {
m_file = new QFile(filePath);
if (!m_file->open(mode)) {
// how do I get jsEngine, here
jsEngine->throwError(m_file->errorString());
}
}
I'd like it if I could somehow derive the calling engine from inside the function, so the class could be exposed to several separate engine instances, for example.
I saw QScriptable and it's engine() method, but couldn't figure out how to use it.
I added
Depends { name: "Qt.script" }
in my qbs file, and
#include <QtScript>
but it still isn't throwing the error with this (just fails silently):
#include <QObject>
#include <QString>
#include <QFile>
#include <QIODevice>
#include <QFileInfo>
#include <QtScript>
namespace Qbs4QJS {
class BinaryFile : public QObject, protected QScriptable
{
Q_OBJECT
public:
Q_ENUM(QIODevice::OpenModeFlag)
Q_INVOKABLE BinaryFile(const QString &filePath, QIODevice::OpenModeFlag mode = QIODevice::ReadOnly) {
m_file = new QFile(filePath);
// should check for false and throw error with jsEngine->throwError(m_file->errorString());
if (!m_file->open(mode)){
context()->throwError(m_file->errorString());
}
}
private:
QFile *m_file = nullptr;
};
} // end namespace Qbs4QJS
I may be confused about it, too, but it seems like it's using QScriptEngine, which I'm trying to get away from.
What is the best way to accomplish the task of adding a class that QJSEngine can use, which has cpp-defined methods that can throw errors in the calling engine?
The object under construction does not have any association with QJSEngine yet. So you can only do one of the following alternatives:
Store the engine instance in a static variable if you can ensure that there is only ever one instance of QJSEngine in your whole application.
Store the engine instance in a thread-local variable (QThreadStorage) if you can ensure that there is only one engine per thread.
Set the current active engine in the current thread right before evaluating your JS code since. This might be the easiest and yet robust solution.
Retrieve the engine from a QJSValue parameter.
Implement a JS wrapper for the constructor
Solution 4.: Passing the engine implicitly via a QJSValue parameter.
I assume that your throwing constructor always has a parameter. QJSValue has a (deprecated) method engine() which you then could use. You can replace any parameter in a Q_INVOKABLE method with QJSValue instead of using QString and friends.
class TextFileJsExtension : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE TextFileJsExtension(const QJSValue &filename);
};
TextFileJsExtension::TextFileJsExtension(const QJSValue &filename)
{
QJSEngine *engine = filename.engine();
if (engine)
engine->throwError(QLatin1String("blabla"));
}
I guess there is a reason why it is deprecated, so you could ask the QML team, why and what alternative you could use.
Solution 5 Implement a JS wrapper for the constructor
This builds upon solution 4. and works even for parameter-less constructors. Instead of registering your helper class directly like this:
engine->globalObject().setProperty("TextFile", engine->newQMetaObject(&TextFile::staticMetaObject));
You could write an additional generator class and a constructor wrapper in JS. Evaluate the wrapper and register this function as the constructor for your class. This wrapper function would pass all desired arguments to the factory method. Something like this:
engine->evaluate("function TextFile(path) { return TextFileCreator.createObject(path);
TextFileCreator is a helper class that you would register as singleton. The createObject() method would then finally create the TextFile object and pass the engine as a paremter:
QJSValue TextFileCreator::createObject(const QString &path)
{
QJSEngine *engine = qmlEngine(this);
return engine->createQObject(new TextFile(engine, filePath));
}
This gives you access to the QJSEngine in the TextFile constructor and you can call throwError().
I am currently implementing a small soft, I want this soft work on Mac OS and Window OS, so I want use GLFW for Mac environment and Window API for Windows environment (I know GLFW is cross platform but that's not the point..)
My problem is a design implementation problem:
I have created a windowManager class that keeps an instance of a Window class. This Window keeps an instance of an object that is a PatternWindow, where PatternWindow is an interface. I have an object PatternGLFW3_VULKAN that implements PatternWindow. This PatternGLFW3_VULKAN has a member GLFWwindow * _window, and PatternGLFW3_VULKAN initializes _window with glfwCreateWindow(...).
class Window : public Singleton<Window>
{
public:
somefunction(...)
initializePatternWindow(unique_ptr<PatternWindow>&& patternWindow)
unique_ptr<PatternWindow> getPatternWindow(){return _patternWindow;}
private:
unique_ptr<PatternWindow> _patternWindow;
}
class PatternWindow
{
public:
PatternWindow();
virtual ~PatternWindow();
virtual void initialize() = 0;
virtual void destroy () = 0;
};
class PatternGLFW3_VULKAN : public PatternWindow
{
public:
PatternGLFW3_VULKAN ();
~PatternGLFW3_VULKAN();
virtual void initialize();
virtual void destroy();
const GLFWwindow& getWindow() const {return *_window;}
private:
GLFWwindow * _window;
};
My question is about the getWindow() function in my PatternGLFW3_VULKAN class; how I can create a virtual getWindow() function in my PatternWindow class in order to get my GLFWwindow* window of the PatternGLFW3_VULKAN at run time. If I am on Mac OS environment, I can create a virtual function GLFWwindow& getWindow() in my PatternWindow, but if I run my software in a Window environment, the type GLFWwindow of the virtual function getWindow() of the patternWindow class won't be correct...
How can I do in order to have a virtual getWindow() in PatternWindow my that returns GLFWwindow or a instance the Windows API screen at run time ?
EDIT:
class PatternWindow
{
public:
PatternWindow();
virtual ~PatternWindow();
virtual void initialize() = 0;
virtual void destroy () = 0;
virtual /*UNKNOW TYPE AT THE COMPILATION*/ getWindow() = 0;
};
/*UNKNOW TYPE AT THE COMPILATION*/
is my problem I do not know how to deal with it, for getting a GLFWwindow* when i am in Mac OS and Windows instance for the windows API when I am compiling in the Windows environment..
In the main loop of my software in want something like that
int main(int argc, char** argv)
{
//initialisation of all my managers ans the data ect..
while(!WindowClosed(Window::getPatternWindow()->getWindow()))
{
//DO SOME STUFF
}
}
The pattern you are heading towards can be done, but you might regret it later. I would infer from your setup that you have two overloads of WindowClosed() – one whose parameter is a GLFWwindow, and one whose parameter is a WinAPI type. The former would use GLFW methods to detect if the window is closed, while the latter would use the Windows API. One problem is that one of organization: how many files contain GLFW-specific methods? Maybe you even have a file with both GLFW methods and Win API methods? That's not necessarily wrong, but it could be a pain in the long run. Another problem is that this approach diverges from the traditional object-oriented approach.
Still, let's not force you down one path through lack of knowledge. To make this approach work, you could use the preprocessor and a typedef. If compiling for Mac, you would use a line like typedef PatternGLFW3_VULKAN WindowType;. If compiling for Windows, you'd use a line defining WindowType to be the corresponding Windows type. Choosing between these lines would be accomplished via #ifdef WINDOWS (or whatever condition is most appropriate). Then getWindow() could be declared to return WindowType.
A better approach (which you realized in the comments) is to shift the functionality to the window objects. Instead of function(object), use object.function(). This requires more virtual functions in your interface class, but there is a benefit that you have fewer files that are OS-specific.
class PatternWindow
{
public:
PatternWindow();
virtual ~PatternWindow();
virtual void initialize() = 0;
virtual void destroy () = 0;
virtual bool closed () = 0; // <-- New pure virtual function
};
class PatternGLFW3_VULKAN : public PatternWindow
{
public:
PatternGLFW3_VULKAN ();
~PatternGLFW3_VULKAN();
virtual void initialize();
virtual void destroy();
virtual bool closed(); // <-- OS-specific code is no longer in an extra file
private:
GLFWwindow * _window;
};
Then in your main function, the call would be:
while(!Window::getPatternWindow()->closed())
There is a further step you might consider. (The question appropriately does not have enough details to determine if this is a viable option.) You might not need polymorphism for what you are trying to do. Suppose you were to use the following declaration.
class PatternWindow
{
#ifdef WINDOWS // Or whatever test is appropriate
typedef PatternGLFW3_VULKAN * WindowType;
#else
typedef /* Windows API type */ WindowType;
#endif
public:
PatternWindow();
~PatternWindow();
void initialize();
void destroy ();
bool closed ();
private:
WindowType _window;
};
This interface no longer supports polymorphism. Is that a bad thing? Do you need multiple classes derived from PatternWindow under a single operating system? Perhaps not. Here is a potential implementation file for this class.
#include "PatternWindow.h"
#ifdef WINDOWS // Or whatever test is appropriate
#include "PatternWinAPI.src" // <-- File with an implementation based on Win API
#else
#include "PatternGLFW.src" // <-- File with an implementation based on GLFW
#endif
If you don't like the .src extension, use something else. Just don't make those files look like something to be compiled on their own. Each file would have an implementation appropriate for the API it uses. For example, PatternGLFW.src might contain a function definition like the following.
void PatternWindow::initialize()
{
_window = glfwCreateWindow(...);
// Etc.
}
This eliminates the overhead of polymorphism and does not seem to introduce a coding burden. Also, you don't have to keep track of which files are needed for which operating systems (simpler build setup). The organization of PatternWindow.cpp is uncommon, though.
I am writing a program in QT, which currently has a GameEngine (data handling) class and a MainWindow (GUI) class.
The single instances of both GameEngineand MainWindow classes are owned by the int main function.
The MainWindow instance has a User Action-button, which will open an instance of a QDialog class called Dialog_UserAction. The instance of this QDialog is owned by the MainWindow, which is also the parent of the QDialog (to disable the MainWindow GUI while the Dialog_UserAction instance is open).
My issue is that many events (signals) need to be connected between the QDialog and the GameEngine instance.
Is there any simple way that I can achieve this?
I have already tried by forwarding the signals from Dialog_UserAction to GameEngine via the MainBoard and vice versa. This works, but it is quite a messy solution for this task.
I have also tried letting the Dialog_UserAction be owned by Main, but I don't know how to react on the User Action Button clicked-event in main context.
Finally, I have also tried letting the Dialog_UserAction be owned by the GameEngine instance, which would the easy solution (except that the MainBoard GUI will not be disabled, while Dialog_UserAction is opened). But, I would really prefer that all GUI related instances were kept out of the GameEngine context.
GameEngine.h:
class GameEngine : public QObject
{
Q_OBJECT
signals:
void someSignalToDialog(void);
public slots:
void on_someSignalFromDialog();
}
Dialog_UserAction.h:
class Dialog_UserAction: public QObject
{
Q_OBJECT
signals:
void someSignalToGameEngine(void);
public slots:
void on_someSignalFromGameEngine();
}
Main.cpp:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QApplication::setWindowIcon(QIcon(":/images/MageKnightLogo.jpg"));
GameEngine gameEngine;
Window_MainBoard mainBoard;
mainBoard.showFullScreen();
return a.exec();
}
MainBoard.cpp:
#include "Dialog_UserAction.h"
...
void Window_MainBoard::on_pushButton_enterUserAction_clicked() {
Dialog_UserAction actionDialog(this);
// connect signals and slots here?
if (actionDialog.exec() == QDialog::Accepted)
{
// Send signal with data to GameEngine
}
}
...
So, what I'm really asking is:
Is there any simple way I can setup the signal-slot connections in this setup where I can connect Dialog_UserAction with GameEngine without forwarding the signals in the MainBoard context?
If not, do you have any suggestions on how I could approach this in a better way in general? Thanks in advance.
Since the GameEngine object is a singleton (only one instance exists), you can have the Dialog_UserAction object connect its signals directly to the GameEngine object. You can do that in the Dialog_UserAction constructor.
To get easy access to the GameEngine object, simply add a static member function to it that returns a static GameEngine* member.
GameEngine.h
class GameEngine
{
public:
GameEngine()
{
Q_ASSERT(instance_ == nullptr); // Only one instance allowed.
instance_ = this;
}
static GameEngine* instance() noexcept
{ return instance_; }
private:
static GameEngine* instance_;
};
GameEngine.cpp
GameEngine* GameEngine::instance_ = nullptr;
You can now connect the Dialog_UserAction signals to GameEngine::instance().
So, just for clarification, I ended using the Singleton design pattern as suggested by Nikos C.
But I implemented the class a little differently, and therefore wanted to share this as a standalone answer.
I found that I needed to trigger the constructor of the the object somehow, and figured that this could be done using the so-called (I believe) Lazy Initialization method. Also, the constructor of the class should be private, such that only the instance itself will be able to call this, and thus making sure that the constructor is only called once.
Furthermore, I made the GameEngine::Instance()method as a const static GameEngine*-type in order to let the access to the object be read-only.
GameEngine.h
class GameEngine
{
public:
const static GameEngine* instance() { // Singleton instance reference getter
if (instance_ == nullptr)
instance_ = new GameEngine(); // This triggers the constructor of the object
return instance_;
}
private:
GameEngine(); // The constructor is made private!
};
GameEngine.cpp
// Place this declaration in the top of the file to create the global class instance pointer
// The initial value of the pointer must be nullptr to let the constructor be correctly triggered at the first instance()-call
GameEngine* GameEngine::instance_ = nullptr;
Then in Main and Dialog_UserAction (the clients) the access to the Singleton GameEngine instance is used by creating a const class instance pointer in the each context.
Main.cpp
#include "GameEngine.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Window_MainBoard mainBoard;
const GameEngine* gameEngine = GameEngine::instance(); // Const pointer to the Singleton instance of the GameEngine class (global object)
QObject::connect(gameEngine, SIGNAL(someSignalToDialog), &mainBoard, SLOT(on_someSignalFromGameEngine));
}
Dialog_UserAction.cpp
#include "GameEngine.h"
// Constructor
Dialog_UserAction::Dialog_UserAction(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog_UserAction) {
ui->setupUi(this);
// Const pointer to the Singleton instance of the GameEngine class (global object)
const GameEngine* gameEngine = GameEngine::instance();
connect(this, SIGNAL(someSignalToGameEngine), gameEngine, SLOT(on_someSignalFromDialog) );
}
I am trying to create a global reference of an object but it seems fails or I am getting another error in Qt C++.
I have a class called 'System' which holds many objects as members. I want to access System's members from everywhere include members of System. Here is my code below:
// System.h
class System
{
public:
Obj1* m_obj1;
Obj2* m_obj2;
System();
~System();
static System* GetGlobalReference();
}
// System.cpp
static System* GlobalReference = 0;
System::System()
{
if (!GlobalReference) GlobalReference = this;
m_obj1 = new Obj1();
m_obj2 = new Obj2();
}
System* System::GetGlobalReference()
{
return GlobalReference;
}
// main.cpp
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
System* system = new System();
MainWindow window;
window.showMaximized();
return app.exec();
}
//Obj1.h
class Obj1 : public QObject
{
Q_OBJECT
public:
Obj1() : QObject() {}
~Obj1();
public slots:
void Import();
}
// Obj1.cpp
void Obj1::Import()
{
QString path = QFileDialog::getOpenFileName(
0,
QString("Import file..."),
QString("C:\\"),
QString("JPEG File (*.jpg)"),
0,
0);
if (System::GetGlobalReference())
System::GetGlobalReference()->m_obj2->Import(path); // error here
else
// System::GlobalReference is null
}
It seems reference is not null but I get an error during runtime "Access violation reading location..." What is wrong?
Btw Obj1 is a QObject and Import method is a public slot, can the error be related with this?
Edit: Debuugger last step is here in QGenericAtomic.h
T load(const T &_q_value) Q_DECL_NOTHROW
{
return _q_value; // -> Debugger stops here
}
Edit2: I've used Singleton pattern as the answers says but my problem still continues.
System::GetInstance()->GetObj1()->Import(path); // after this line
in "_q_value" it says ""
If you wish to have global variables, I would recommend using a singleton instead.
Global variables in C++ are declared using extern, not static. See the reference for more information.
If you want only one instance of your System class, you should use the Singleton pattern.
But, the Singleton pattern should be used when you want an unique instance of a class, the reason should not be when you want to have an object global. Even if using this pattern, your instance is accessible from everywhere.
Look at this article about Singleton design pattern, it may be useful in your case.
Also, in C++ the declaration of global variable is done with extern, not static.
I've solved my problem. The problem was caused by Obj1->Import method but during debug in qt, debugger is not accessing inside the method when I press F11(Step Into). I cannot figure it out why?