Using a Singleton Class across a Qt Application and its Plugins - qt

I'm trying to use a Singleton Class (its a program-wide debug logger called 'PrisLog') across my Qt Application. The program also has plugins. I want to make my singleton class available to those plugins, but this doesn't work. From what I can tell, trying to use the class in the plugin results in another instance being created.
-The singleton class is just a *.cpp and *.h file, nothing else. I've linked both my main application and the plugin to these files individually... is this the right way to do it?
-I've attached my singleton class's code below, though I think I've created the class correctly. If I use it from within separate classes in my main application, it works as expected (one instance).
EDIT: Linking both the application and plugin to the same static lib (the singleton class) works. Here's how my qmake *.pro files looked:
MySingletonLib.pro
TEMPLATE = lib
CONFIG += staticlib
HEADERS += \
mysingletonlib.h
SOURCES += \
mysingletonlib.cpp
MyPlugin.pro (also incl #include mysingletonlib.h in myplugin.h)
INCLUDEPATH += path/to/MySingletonLib
LIBS += -Lpath/to/MySingletonLib -lMySingletonLib
MyPlugin.pro (also incl #include mysingletonlib.h in myapp.h)
INCLUDEPATH += path/to/MySingletonLib
LIBS += -Lpath/to/MySingletonLib -lMySingletonLib
And the original code:
#ifndef PRISLOG_H
#define PRISLOG_H
#include <QFile>
#include <QDir>
#include <QString>
#include <QMutex>
#include <QDebug>
#include <QMutexLocker>
#include <QTextStream>
#include <QDateTime>
// PrisLog (singleton) class definition
class PrisLog
{
public:
static PrisLog* Instance();
void SetLogsPath(QString);
QString GetLogsPath();
void SetDebugDestination(QString);
void SetElmRxDestination(QString);
void SetElmTxDestination(QString);
void SetDlgDestination(QString);
QTextStream* GetDebugStream();
QTextStream* GetElmRxStream();
QTextStream* GetElmTxStream();
QTextStream* GetDlgStream();
QMutex* GetDebugMutex();
private:
PrisLog(); // private constructor
PrisLog(const PrisLog&); // prevent copy constructor
PrisLog& operator=(const PrisLog&); // prevent assignment
static PrisLog* m_Instance;
static bool m_InitFlag;
QString m_appPath;
QFile m_DebugFile;
QTextStream m_DebugStream;
QMutex m_DebugMutex;
QFile m_ElmRxFile;
QTextStream m_ElmRxStream;
QFile m_ElmTxFile;
QTextStream m_ElmTxStream;
QFile m_DlgFile;
QTextStream m_DlgStream;
};
// thread-UNSAFE writer, but less expensive
// use: single stream <--> single thread!
class PrisLogWriter
{
public:
PrisLogWriter(QTextStream*);
~PrisLogWriter();
QTextStream* m_stream;
};
// thread-UNSAFE writer, but less expensive
// this version does not include any formatting
// use: single stream <--> single thread!
class PrisLogRawWriter
{
public:
PrisLogRawWriter(QTextStream*);
~PrisLogRawWriter();
QTextStream* m_stream;
};
// thread-safe writer
// use: single stream <--> many threads
class PrisLogSafeWriter
{
public:
PrisLogSafeWriter(QTextStream*, QMutex*);
~PrisLogSafeWriter();
QTextStream* m_stream;
private:
QMutex* m_mutex;
};
#define PRISLOGDEBUG (*(PrisLogSafeWriter(PrisLog::Instance()->GetDebugStream(), PrisLog::Instance()->GetDebugMutex()).m_stream))
#define PRISLOGELMRX (*(PrisLogWriter(PrisLog::Instance()->GetElmRxStream()).m_stream))
#define PRISLOGELMTX (*(PrisLogWriter(PrisLog::Instance()->GetElmTxStream()).m_stream))
#define PRISLOGDLG (*(PrisLogRawWriter(PrisLog::Instance()->GetDlgStream()).m_stream))
#endif // PRISLOG_H

I think you should take this class to a statically linked, but separeted shared dll/so.
If your host application does not use this class, the linker simply won't link it into the binary and your plugin could not use it. Additionally: your binary has no library class interface.

You need to make sure, that only one instance exists. The safest is, that the cpp is compiled only once in the overall exe.
To make sure that the other DLLs can call PrisLog::Instance, this class/function (i.e. all public methods if PrisLog) needs to be declared with __declspec(dllexport), even if it is located within the exe.
The DLLs can then dynamically find the object and method.
BTW: Why don't you use the logging from Qt?

Related

Testing Qt application in Visual Studio - Qt files giving 'cannot open source file' error when including project files in test file

I'm trying to write tests for a Qt application in visual studio. I've added a new test project to the existing solution that has the project I'm wanting to test, and added a reference to said project as shown here. When I try to run a test file, I get errors saying 'cannot open source file "x"' for a bunch of Qt and Qt generated files like QWidget and 'ui_x.h' (x is a placeholder). I'm using Google Test, but the same issue occurs when using the 'Native Unit Test Project' option.
Image of problem
Settings.h
#pragma once
#include <string>
#include <QWidget>
#include <QSettings>
#include <QFileDialog>
#include "ui_Settings.h"
extern const std::string MODS_FOLDER_PATH;
extern const std::string PROFILE_PATH;
class Settings : public QWidget
{
Q_OBJECT
public:
Settings(QWidget *parent = Q_NULLPTR, QString testHook = "");
QString getModsFolderPath();
public slots:
void browseProfilePath();
void browseModsPath();
void openSettingsWidget();
signals:
void modsFolderPathChanged(const QString &newPath);
void profilePathChanged();
private:
Ui::Options ui;
QString testHook;
QString fileBrowser(QFileDialog::FileMode fileMode, const std::string = "");
bool changeFileSetting(QLineEdit * const settingInput, const std::string setting, const QString &fileName);
void loadValuesFromSettings();
};
test.cpp
#include "pch.h"
#include "../FileOverwriteManager/Settings.h"
TEST(TestCaseName, TestName) {
EXPECT_EQ(1, 1);
EXPECT_TRUE(true);
}
I had to edit the 'Additional Include Directories' under 'C/C++' in the test project's properties as suggested by user vahancho. If you only include the directories where the .h files are, i.e. C:\Qt\5.10.0\msvc2017_64\include\QtCore for qsettings.h, then it complains like so, so you have to also include one directory higher, i.e. C:\Qt\5.10.0\msvc2017_64\include\

Export QObject-based class to DLL

I'm composing a class which derives from QObject, and I want to export this class into a DLL file so other applications can use it. But I got some mysterious problem here:
The code is shown below:
mydll.h:
#ifndef MYDLL_H
#define MYDLL_H
#include "mydll_global.h"
#include <QObject>
#include <QDebug>
class MYDLLSHARED_EXPORT MyDll : public QObject
{
Q_OBJECT
public:
explicit MyDll(QObject * parent = 0);
void test() const;
};
#endif // MYDLL_H
mydll_global.h:
#ifndef MYDLL_GLOBAL_H
#define MYDLL_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(MYDLL_LIBRARY)
# define MYDLLSHARED_EXPORT Q_DECL_EXPORT
#else
# define MYDLLSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // MYDLL_GLOBAL_H
mydll.cpp:
#include "mydll.h"
MyDll::MyDll(QObject * parent) :
QObject(parent)
{
}
void MyDll::test() const {
qDebug() << "Hello from dll!";
}
and the dll is used in another application. The dll is compiled successfully. I've add LIBS += "myDll.dll" in the .pro file of the application using this dll, and I've copied myDll.dll to the working directory of the application.
The compiler reports:
C4273: "MyDll::qt_static_metacall" : inconsistent dll linkage.
C2491: "MyDll::staticMetaObject": definition of dllimport static data member not allowed
What's the problem here?
Your code for mydll_global.h checks whether MYDLL_LIBRARY is defined, but none of the code you have posted defines MYDLL_LIBRARY. Is this declared in a file that you have not shared on the question? If not, you need to add a #define MYDLL_LIBRARY in your build project, or your PCH.

How to send data to and from the browser with a Qt HTML5 Application

None of the tutorials available online show how to create a Qt HTML5 application. Ideally, I just need a way to send data (a string will do) between webkit and Qt.
When I create a Qt HTML5 Application It generates
myApp.pro
html5applicationviewer.pri // comments say dont touch this file
html5applicationviewer.h // comments say dont touch this file
html5applicationviewer.cpp // comments say dont touch this file
main.cpp
index.html
So how do I add a function in C++ to communicate with the browser and how do I add a function in the browser to communicate with C++?
This example is old but still work and is very simple and clean.
Also you may want to take a look to qtwebkit-bridge and the tutorial.
edit
add a file called myclass.h
#include "html5applicationviewer/html5applicationviewer.h"
class MyClass : public Html5ApplicationViewer
{
Q_OBJECT
public:
explicit MyClass(QWidget *parent=0);
private slots:
void addToJavaScript();
public slots:
QString test(const QString &param);
};
add a file called myclass.cpp
#include <QDebug>
#include <QGraphicsWebView>
#include <QWebFrame>
#include "myclass.h"
MyClass::MyClass(QWidget *parent) : Html5ApplicationViewer(parent) {
QObject::connect(webView()->page()->mainFrame(),
SIGNAL(javaScriptWindowObjectCleared()), SLOT(addToJavaScript()));
}
void MyClass::addToJavaScript() {
webView()->page()->mainFrame()->addToJavaScriptWindowObject("MyClass", this);
}
QString MyClass::test(const QString &param) {
qDebug() << "from javascript " << param;
return QString("from c++");
}
in your .pro add
SOURCES += main.cpp myclass.cpp
HEADERS += myclass.h
in your .html add
try {
alert(MyClass.test("test string"));
} catch(err) {
alert(err);
}
in your main.cpp add include:
#include "myclass.h"
and change:
Html5ApplicationViewer viewer;
to:
MyClass viewer;

QT the glBegin not declared?

i'm following a tutorial to write a small piece of code of opengl in qt.here's the link
http://www.youtube.com/watch?v=1nzHSkY4K18
but in the 6:13 when I bluid the code it show a couple of error that
..\testopgl\glwidget.cpp: In member function 'virtual void GLWidget::paintGL()':
..\testopgl\glwidget.cpp:17:20: error: 'glColor3f' was not declared in this scope
..\testopgl\glwidget.cpp:19:25: error: 'glBegin' was not declared in this scope
..\testopgl\glwidget.cpp:20:31: error: 'glVertex3f' was not declared in this scope
..\testopgl\glwidget.cpp:23:11: error: 'glEnd' was not declared in this scope
..\testopgl\glwidget.cpp: At global scope:
what I really don't understand is when I only put the glClear(GL_COLOR_BUFFER_BIT) it builds alright,but occurs error even i just put the glColor3f().Does the GLWidget not support the glColor*() or glBegin() command?
here's my code.
testopgl.pro
#-------------------------------------------------
#
# Project created by QtCreator 2013-03-28T09:48:44
#
#-------------------------------------------------
QT += core gui opengl
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = testopgl
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
glwidget.cpp
HEADERS += mainwindow.h \
glwidget.h
FORMS += mainwindow.ui
glwidget.h
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QGLWidget>
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QWidget *parent = 0);
void initializeGL();
void paintGL();
void resizeGL(int w,int h);
};
#endif // GLWIDGET_H
glwidget.cpp
#include "glwidget.h"
GLWidget::GLWidget(QWidget *parent) :
QGLWidget(parent)
{
}
void GLWidget::initializeGL(){
glClearColor(1,1,0,1);
}
void GLWidget::paintGL(){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1,0,0);
glBegin(GL_TRIANGLES);
glVertex3f(-0.5,-0.5,0);
glVertex3f(0.5,-0.5,0);
glVertex3f(0.0,0.5,0);
glEnd();
}
void GLWidget::resizeGL(int w,int h){
}
The functions you mention are simply not present in any modern version of GL, so the tutorial you are following sounds like it is quite out of date.
So probably the version of GL exposed through your build of QT does not have these functions. It may be possible to reconfigure/rebuild QT to use an older version of GL, but I would instead recommend getting to know and use the modern programmable interface.

Undefined references during build of plugin in Qt Creator

I'm trying to create plugin for Qt Creator, so I simply selected new file or project/Libraries/QtCreator plugin. I've specified the sources for Qt Creator as well as build of Qt Creator. When I've tried to build it I'm getting the following three errors:
*C:\...\mypluginplugin.cpp:20: error:
undefined reference to `vtable for MyPlugin::Internal::MyPluginPlugin'* //this is constructor
*C:\...\mypluginplugin.cpp:25: error:
undefined reference to `vtable for MyPlugin::Internal::MyPluginPlugin'* //this is destructor
C:\...\mypluginplugin.hpp:13: error:
undefined reference to `MyPlugin::Internal::MyPluginPlugin::staticMetaObject' //when I double click
on this error it moves me to my .hpp file to the Q_OBJECT macro:
This is my code:
namespace MyPlugin {
namespace Internal {
class MyPluginPlugin : public ExtensionSystem::IPlugin
{
Q_OBJECT// the last, third error moves me here
public:
MyPluginPlugin();
~MyPluginPlugin();
bool initialize(const QStringList &arguments, QString *errorString);
void extensionsInitialized();
ShutdownFlag aboutToShutdown();
private slots:
void triggerAction();
};
} // namespace Internal
} // namespace MyPlugin
Any idea how to solve this problem?
//EDIT
#include "mypluginplugin.hpp"
#include "mypluginconstants.hpp"
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/coreconstants.h>
#include <QAction>
#include <QMessageBox>
#include <QMainWindow>
#include <QMenu>
#include <QtPlugin>
using namespace MyPlugin::Internal;
MyPluginPlugin::MyPluginPlugin()
{
// Create your members
}
MyPluginPlugin::~MyPluginPlugin()
{
// Unregister objects from the plugin manager's object pool
// Delete members
}
bool MyPluginPlugin::initialize(const QStringList &arguments, QString *errorString)
{
// Register objects in the plugin manager's object pool
// Load settings
// Add actions to menus
// Connect to other plugins' signals
// In the initialize method, a plugin can be sure that the plugins it
// depends on have initialized their members.
Q_UNUSED(arguments)
Q_UNUSED(errorString)
QAction *action = new QAction(tr("MyPlugin action"), this);
Core::Command *cmd = Core::ActionManager::registerAction(action, Constants::ACTION_ID,
Core::Context(Core::Constants::C_GLOBAL));
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Meta+A")));
connect(action, SIGNAL(triggered()), this, SLOT(triggerAction()));
Core::ActionContainer *menu = Core::ActionManager::createMenu(Constants::MENU_ID);
menu->menu()->setTitle(tr("MyPlugin"));
menu->addAction(cmd);
Core::ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);
return true;
}
void MyPluginPlugin::extensionsInitialized()
{
// Retrieve objects from the plugin manager's object pool
// In the extensionsInitialized method, a plugin can be sure that all
// plugins that depend on it are completely initialized.
}
ExtensionSystem::IPlugin::ShutdownFlag MyPluginPlugin::aboutToShutdown()
{
// Save settings
// Disconnect from signals that are not needed during shutdown
// Hide UI (if you add UI that is not in the main window directly)
return SynchronousShutdown;
}
void MyPluginPlugin::triggerAction()
{
QMessageBox::information(Core::ICore::mainWindow(),
tr("Action triggered"),
tr("This is an action from MyPlugin."));
}
Q_EXPORT_PLUGIN2(MyPlugin, MyPluginPlugin)
I figured out what happened. Ok, here is the solution for others - qtcreator simply didn't attach .hpp files to the project, yet there were created. After adding those .hpp files via add existing files, it builds fine now.

Resources