I am using Qt5.15.2.
I have a QObject used in my GUI and defined as below:
#pragma once
#include "actionstep.h"
#include "anotherthread.h"
#include <QTableWidget>
class TableWidget : public QTableWidget {
Q_OBJECT
public:
TableWidget(QWidget *parent = nullptr) : QTableWidget(4, 4, parent) {
int id = qRegisterMetaType<ActionStep::ActionStatusInfos>();
std::cout << id << std::endl;
connect(this, &TableWidget::SigUpdateActionStatusInfos, this,
&TableWidget::SlotUpdateActionStatusInfos,
Qt::ConnectionType::QueuedConnection);
th.start();
}
void methodCalledByAnotherThread(ActionStep::ActionStatusInfos ActionStepInfosObj)
{
emit SigUpdateActionStatusInfos(ActionStepInfosObj);
}
signals:
void SigUpdateActionStatusInfos(ActionStep::ActionStatusInfos as);
private slots:
void SlotUpdateActionStatusInfos(ActionStep::ActionStatusInfos as) {
}
private:
AnotherThread th;
};
The idea is to be able to send my custom object of type ActionStep::ActionStatusInfos through the signal/slot service.
Content of "actionstep.h", which contains my custom object:
#pragma once
#include <iostream>
#include <QMetaType>
class ActionStep {
public:
class ActionStatusInfos {
public:
// Default constructor
ActionStatusInfos() : Progress(0) {
}
// Default destructor
~ActionStatusInfos() = default;
// Copy constructor
ActionStatusInfos(ActionStatusInfos &source) {
SetProgress(source.GetProgress());
}
// Copy assignment
ActionStatusInfos &operator=(ActionStatusInfos &source) {
SetProgress(source.GetProgress());
return *this;
}
// move constructor
ActionStatusInfos(ActionStatusInfos &&source) noexcept
{
SetProgress(source.GetProgress());
}
//move assignment
ActionStatusInfos &operator=(ActionStatusInfos &&source) noexcept
{
SetProgress(source.GetProgress());
return *this;
}
void SetProgress(int pg) {
Progress = pg;
}
int GetProgress() {
return Progress;
}
private:
int Progress;
};
};
Q_DECLARE_METATYPE(ActionStep::ActionStatusInfos)
I've added both Q_DECLARE_METATYPE(ActionStep::ActionStatusInfos) and qRegisterMetaType<ActionStep::ActionStatusInfos>(), and my class seems to meet the minimum requirements needed by Qt for registering a custom class (default ctor, dtor and copy ctor).
At runtime, methodCalledByAnotherThread is called by a different thread than the GUI. After a few cycles, I get a SIGFAULT, and the debugger shows that there is a dangling reference when the Qt stuff is executed.
Am I missing something obvious?
Related
I have a class with an interface that is doing some uploading, which is done async, when the upload finishes, it fires a signal to inform the consumer of this class that the work has been done. I'm trying to write a test for the consumer class that gets a mock injected and the basic idea was when the upload method is called, the mock should trigger the finished signal on itself. Problem is that the tested consumer doesn't get the signal. I'm either missing something or this doesn't work.
For simplicity reasons, here are some fake implementations:
The interface of the uploader:
#include <QObject>
class IUploader : public QObject
{
Q_OBJECT
public:
IUploader() = default;
~IUploader() override = default;
virtual void upload(int i) = 0;
signals:
void finished(int i);
};
The mock:
#include <gmock/gmock.h>
#include "IUploader.h"
class UploaderMock : public IUploader
{
public:
MOCK_METHOD(void, upload, (int i), (override));
};
The test:
#include <gtest/gtest.h>
#include "Consumer.h"
#include "UploaderMock.h"
TEST(Consumer, UploaderFinished_Should_TriggerCallback)
{
// arrange
UploaderMock uploader;
ON_CALL(uploader, upload(11)).WillByDefault([&uploader](int i) {
uploader.finished(i * 2);
});
Consumer consumer(&uploader);
// act
consumer.doUpload(11);
// assert
EXPECT_EQ(consumer.uploadResult(), 22);
}
Consumer.h
#include
#include "IUploader.h"
class Consumer : public QObject
{
Q_OBJECT
public:
explicit Consumer(IUploader *uploader);
~Consumer() override = default;
void doUpload(int i);
int uploadResult() const;
private:
IUploader *mUploader = nullptr;
int mResult = -1;
private slots:
void setResult(int i);
};
Consumer.cpp
#include "Consumer.h"
Consumer::Consumer(IUploader *uploader) :
mUploader(uploader)
{
connect(uploader, &IUploader::finished, this, &Consumer::setResult);
}
void Consumer::doUpload(int i)
{
mUploader->upload(i);
}
int Consumer::uploadResult() const
{
return mResult;
}
void Consumer::setResult(int i)
{
mResult = i;
}
What happens is that I do see the action being triggered in the ON_CALL but I don't see any signal received by the Consumer object.
Is such a test case possible with Qt and GMock? Could it be a timing problem that the signal is processed after the test method finishes?
When I try to compile the demo file from This tutorial, I get a no operator "=" matches these operands error. I've tried including string (advice from similar questions), but that doesn't seem to make sense since it should already be included in JuceHeader.h.
Code issue:
void initialise (const String& commandLine) override
{
// Add your application's initialisation code here..
mainWindow = new MainWindow (getApplicationName());
}
Full Code:
#include "../JuceLibraryCode/JuceHeader.h"
#include <string>
//==============================================================================
class MainWindowTutorialApplication : public JUCEApplication
{
public:
//==============================================================================
MainWindowTutorialApplication() {}
const String getApplicationName() override { return ProjectInfo::projectName; }
const String getApplicationVersion() override { return ProjectInfo::versionString; }
bool moreThanOneInstanceAllowed() override { return true; }
//==============================================================================
void initialise (const String& commandLine) override
{
// Add your application's initialisation code here..
mainWindow = new MainWindow (getApplicationName());
}
void shutdown() override
{
// Add your application's shutdown code here..
mainWindow = nullptr;
}
//==============================================================================
void systemRequestedQuit() override
{
// This is called when the app is being asked to quit: you can ignore this
// request and let the app carry on running, or call quit() to allow the app to close.
quit();
}
void anotherInstanceStarted (const String& commandLine) override
{
// When another instance of the app is launched while this one is running,
// this method is invoked, and the commandLine parameter tells you what
// the other instance's command-line arguments were.
}
class MainWindow : public DocumentWindow
{
public:
MainWindow(String name) : DocumentWindow(name,
Colours::lightgrey,
DocumentWindow::allButtons)
{
centreWithSize(300, 200);
setVisible(true);
}
void closeButtonPressed() override
{
JUCEApplication::getInstance()->systemRequestedQuit();
}
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainWindow)
};
private:
std::unique_ptr<MainWindow> mainWindow;
};
//==============================================================================
// This macro generates the main() routine that launches the app.
START_JUCE_APPLICATION (MainWindowTutorialApplication)
The compiler sais you that you cannot assign a pointer to unique_ptr, and it's true: std::unique_ptr::operator=. You can only move another unique_ptr or assign nullptr. There are two possible solutions:
mainWindow.reset(new MainWindow(getApplicationName()));
or
mainWindow = std::make_unique<MainWindow>(getApplicationName());
I try to get a QObject-subclassed object from a Qt shared library to a Qt application dynamically.
I have tried to apply a previous answer about this subject : QLibrary - import a class
Here is my common interface tabappinterface.h:
#ifndef TABAPP_H
#define TABAPP_H
#include <QObject>
#include <QWidget>
class TabAppInterface : public QObject
{
Q_OBJECT
public:
virtual ~TabAppInterface()
{
}
QWidget *app;
QString title;
};
#endif // TABAPP_H
My class dll-side mytabapp.h:
#ifndef MYTAB_H
#define MYTAB_H
#include "tabapp_global.h"
#include "tabappinterface.h"
class MYTABSHARED_EXPORT MyTabApp: public TabAppInterface
{
public:
MyTabApp();
virtual ~MyTabApp();
QWidget *app;
QString title;
};
extern "C" MYTABSHARED_EXPORT TabAppInterface *getTabApp();
and its implementation mytabapp.cpp:
#include "mytabapp.h"
MyTabApp::MyTabApp()
{
app = new AppWidget();
title = QStringLiteral("My Tab App");
}
MyTabApp::~MyTabApp()
{
}
TabAppInterface *getTabApp()
{
return new MyTabApp();
}
My app-side implementation:
void ContainerMainWindow::loadLibraries()
{
QLibrary myLib("mytabapp.dll");
if(myLib.isLoaded())
{
qDebug() << "Loaded!";
}
typedef TabAppInterface *(*tabAppGetProt)();
auto tabAppGetter = (tabAppGetProt) myLib.resolve("getTabApp");
if(tabAppGetter)
{
auto *tabApp = tabAppGetter(); // not null
qDebug() << tabApp->title; // print empty string
qDebug() << (QWidget *)(tabApp->app); // SEGFAULT
}
}
As stated in comment in the last lines, the object members are not retrieved although tabApp is not null.
Any idea?
Thanks!
You're accessing the base class variables (fields) title and app, which nobody ever initialized. These variables aren't virtual at all, so those in the derived class just hide those in the base class. As a solution, you can declare them as protected in the base class and encapsulate them in getters and setters.
This way, your base class is like:
class TabAppInterface : public QObject
{
Q_OBJECT
public:
virtual ~TabAppInterface(){}
QWidget *getApp() const { return app; }
void setApp(QWidget *value) { app = value; }
QString getTitle() const { return title; }
void setTitle(const QString &value) { title = value; }
protected:
QWidget *app;
QString title;
};
and the derived class is just like:
class MYTABSHARED_EXPORT MyTabApp: public TabAppInterface
{
public:
MyTabApp();
virtual ~MyTabApp();
};
You can still directly access the variables inside the derived class (i.e. initialize them in constructor) and through the getters/setters methods from outside:
auto *tabApp = tabAppGetter();
qDebug() << tabApp->getTitle();
qDebug() << tabApp->getApp();
I have a class which I'd like to hide using PIMPL type approach. This is because it is a UI form which introduces uic generated header dependancies that I don't want other parts of code to require.
So far I have renamed it PrivateClass, for illustration:
PrivateClass: public QWidget, public Ui_Form
{
Q_OBJECT:
public: // doesn't need to be public but I'm trying to leave as-is apart from name change
PrivateClass(QWidget *parent=0) : QWidget(parent)
{
setupUi(this); // Ui_Form function
}
// etc
void do_something();
};
MyClass: public QWidget
{
Q_OBJECT:
public:
MyClass(QWidget *parent=0) : QWidget(parent)
{
_prvt = new PrivateClass(this); // or pass in parent?
}
~MyClass()
{
delete _prvt;
}
// a bunch of interface functions like this
void do_something(){ _prvt->do_something();}
private:
PrivateClass *_prvt;
};
I am aware that Qt provides a macro based PIMPL implementation, but I'd like to do this manually here, it's not a huge class.
So the question is what to do about the QWidget side of things. To leave PrivateClass unchanged but still allow the new wrapper MyClass to slot in, they both have to be QWidgets. Any QWidget calls on MyClass won't get propagated to _prvt unless I code an interface for QWidget, which doesn't sound right to me.
I have temporarily reconfigured PrivateClass so that it is no longer a QWidget and takes a pointer to MyClass as a constructor argument, any improvements on this?
See this question for an example of how to do it using Qt's PIMPL macros. Since we don't use these macros in the code below, there's some code that has to be written by hand to maintain type safety.
Suppose you started with this class:
Original Interface
#include <QWidget>
#include "ui_widget.h"
class Widget : public QWidget, Ui::Widget {
int m_something;
public:
explicit Widget(QWidget * parent = nullptr);
void do_something();
int something() const;
~Widget();
};
Original Implementation
#include "widget.h"
Widget::Widget(QWidget * parent) :
QWidget{parent},
m_something{44}
{
setupUi(this);
}
void Widget::do_something() {
hide(); // just an example of doing something
}
int Widget::something() const {
return m_something;
}
Widget::~Widget() {}
Can I wrap a QWidget subclass PIMPL style without modifying it
Perhaps. Let's see how it'd work. We can leave Widget alone, treat it as an implementation detail, and "expose" it via a Public interface. We need to use an intervening layout to forward resizing and size constraints from the interface to implementation.
Wrapper Widget Interface
#include <QWidget>
class Widget;
class Public : public QWidget {
Widget * const d_ptr;
Widget * d();
const Widget * d() const;
public:
explicit Public(QWidget * parent = nullptr);
void do_something();
int something() const;
};
Wrapper Widget Implementation
#include "public.h"
#include "widget.h"
Public::Public(QWidget * parent) :
QWidget{parent},
d_ptr{new Widget{this}}
{
auto const layout = new QVBoxLayout{this};
layout->setMargin(0);
}
Widget * Public::d() { return d_ptr.data(); }
const Widget * Public::d() const { return d_ptr.data(); }
void Public::do_something() {
d()->do_something();
}
int Public::something() const {
return d()->something();
}
This has some problems:
You're paying the price of an extra widget and layout instances.
The intervening layout can subtly break the behavior of the enclosed and enclosing widget. Qt layouts aren't perfect; due to their design they suffer from numerically approximate behavior and imperfect forwarding of the encapsulated entities' behavior. Adding additional layers underscores this deficiency.
Instead, you really want to modify the original class. It's much simpler to just PIMPL it and be done with it. If you prepare yourself right, it can be a very mechanical code transformation that will generate a sensible diff.
So, now you want it PIMPL-ed. It will be simplest to push all methods from Widget to WidgetPrivate, and only add forwarder methods to the public interface.
The interface loses all private members, and gets d_ptr and d() added.
PIMPL-ed Interface
#include <QWidget>
class WidgetPrivate;
class Widget : public QWidget {
QScopedPointer<WidgetPrivate> const d_ptr;
WidgetPrivate* d();
const WidgetPrivate* d() const;
public:
explicit Widget(QWidget * parent = nullptr);
void do_something();
int something() const;
~Widget();
};
The PIMPL accesses the QWidget via the q-pointer.
PIMPL-ed Implementation
#include "widget.h"
#include "ui_widget.h"
class WidgetPrivate : public Ui::Widget {
public:
Widget * const q_ptr;
inline Widget * q() { return q_ptr; }
inline const Widget * q() const { return q_ptr; }
int m_something;
WidgetPrivate(Widget * q)
void init();
void do_something();
int something() const;
};
///vvv This section is from "original.cpp" with simple changes:
WidgetPrivate(Widget * q) :
q_ptr{q},
m_something{44}
{}
/// Can only be called after the QWidget is fully constructed.
void WidgetPrivate::init() {
auto const q = q(); // Widget * - we can use a local `q`
// to save on typing parentheses
setupUi(q);
}
void WidgetPrivate::do_something() {
q()->hide(); // we can use q() directly
}
int WidgetPrivate::something() const {
return m_something;
}
///^^^
WidgetPrivate * Widget::d() { return d_ptr.data(); }
const WidgetPrivate* Widget::d() const { return d_ptr.data(); }
Widget::Widget(QWidget * parent) :
QWidget{parent},
d_ptr{new WidgetPrivate{this}}
{
d()->init();
}
void Widget::do_something() {
d()->do_something();
}
int Widget::something() const {
return d()->something();
}
// If the compiler-generated destructor doesn't work then most likely
// the design is broken.
Widget::~Widget() {}
The d() and q() methods are needed to return the const-correct PIMPL and Q when accessed from const methods.
After you check in this rather mechanical change into your version control system, you can then optionally get rid of trivial methods from the PIMPL and move them into the interface:
Reworked PIMPL-ed Implementation
#include "widget.h"
#include "ui_widget.h"
class WidgetPrivate : public Ui::Widget {
public:
Widget * const q_ptr;
inline Widget * q() { return q_ptr; }
inline const Widget * q() const { return q_ptr; }
int m_something;
WidgetPrivate(Widget * q) : q_ptr{q} {}
void init();
};
WidgetPrivate * Widget::d() { return d_ptr.data(); }
const WidgetPrivate* Widget::d() const { return d_ptr.data(); }
WidgetPrivate(Widget * q) :
q_ptr{q},
m_something{44}
{}
/// Can only be called after the QWidget is fully constructed.
void WidgetPrivate::init() {
setupUi(q());
// let's pretend this was a very long method that would have
// much indirection via `d->` if it was moved to `Widget`'s constructor
}
void Widget::do_something() {
hide();
}
int Widget::something() const {
return d()->m_something;
}
Widget::Widget(QWidget * parent) :
QWidget{parent},
d_ptr{new WidgetPrivate{this}}
{
d()->init();
}
Widget::~Widget() {}
I need to create a thread to run the Networking portion of my game. I would prefer to use SFML threads as my compiler doesn't yet support C++11 threads. However the class which contains the thread is created with make_shared(). Here is the code:
Game.cpp (not all the code just the declaration of GameScreen)
std::shared_ptr<Screen> Game::screen = std::make_shared<GameScreen>();
Screen is just a base class containing pure virtual functions. You should be able to figure out which ones are virtual based off the override keywords.
GameScreen.h
#ifndef GAMESCREEN_H
#define GAMESCREEN_H
#include <SFML/Graphics.hpp>
#include "Events.h"
#include "Screen.h"
#include "Map.h"
#include "Network.h"
class GameScreen : public Screen
{
public:
GameScreen();
void handleInput(sf::RenderWindow&) override;
void update(sf::RenderWindow&, sf::View&) override;
void render(sf::RenderWindow&) override;
private:
Map m_map;
Network network;
Events eventManager;
sf::Thread networkThread;
};
#endif // GAMESCREEN_H
GameScreen.cpp
#include <memory>
#include <iostream>
#include "GameScreen.h"
#include "Game.h"
GameScreen::GameScreen()
: networkThread(network.receive(eventManager))
{
network.Connect();
}
void GameScreen::handleInput(sf::RenderWindow& window)
{
/*Code*/
}
void GameScreen::update(sf::RenderWindow& window, sf::View& view)
{
/*Code*/
}
void GameScreen::render(sf::RenderWindow& window)
{
/*Code*/
}
Network.cpp (receive function only)
void Network::Recieve(Events& eManager)
{
sf::Packet m_rPacket;
m_socket.receive(m_rPacket, m_serverIP, port);
m_rPacket >> /*Data*/
eManager.addEvent(tmp);
}
You can use this in the constructor's initialization list:
MyClass::MyClass()
: AClass(&MyFunction(*this))
{
/*do stuff*/
}
However, this doesn't make sense in your example, because you are trying to pass a pointer to MyFunction (or its non-existent return value) to AClass(), and you can't quality a pointer with parameters. You can only pass parameters to MyFunction() when actually calling MyFunction(). Are you sure you don't actually mean something more like this instead:
MyClass::MyClass()
: AClass()
{
/*do stuff*/
MyFunction(*this);
}
Without seeing what AClass() actually is, or what it expects as input, it is difficult to know for sure what you are trying to do.
Update clearly you have not read the SFML documentation or SFML Tutorial on threading. The Thread constructor takes a pointer to a function/method as one input parameter, and an optional input value for the function/method as a separate parameter. Try this instead:
class MyClass : public sf::Thread
{
private:
static void MyFunction(MyClass &cls);
public:
MyClass();
};
MyClass::MyClass()
: sf::Thread(&MyClass::MyFunction, *this)
{
/*do stuff*/
}
void MyClass::MyFunction(MyClass &cls)
{
/*do stuff with 'cls'*/
}
Or this, as you can use a non-static class method with an SFML thread:
class MyClass : public sf::Thread
{
private:
void MyFunction();
public:
MyClass();
};
MyClass::MyClass()
: sf::Thread(&MyClass::MyFunction, *this)
{
/*do stuff*/
}
void MyClass::MyFunction()
{
/*do stuff with 'this'*/
}
Update: based on your new code, you are still not even close to constructing the sf::Thread object correctly (did you read the documentation/tutorial I linked to?). Also, your thread needs access to multiple objects owned by GameScreen, so you can't pass them all to the sf::Thread constructor. You need to do something more like this instead:
class GameScreen : public Screen
{
public:
GameScreen();
...
private:
...
Network network;
Events eventManager;
sf::Thread networkThread;
void networkThreadFunc();
};
GameScreen::GameScreen()
: networkThread(&GameScreen::networkThreadFunc, *this)
{
network.Connect();
}
void GameScreen::networkThreadFunc()
{
network.Receive(eventManager);
}