Did I correctly implement this pattern? The idea of my example is that there are document and application (app performs an observer role). At the beginning each document should attach the observer. Further, document could close all documents except himself by emitting a signal to observer (application).
Requirement - example should use an event model.
class Application
{
std::vector<Document *> docs;
public:
void add_document(Document *doc)
{
docs.push_back(doc);
}
public slots:
void close_non_active_docs_button_pressed(Document *active_doc)
{
for (auto idoc: this->docs)
{
if (idoc == active_doc)
continue;
idoc->close();
}
}
}
class Document
{
Application *app;
public:
void attach_to_app(Application *app)
{
this->curr_app = app;
app->add_document(this);
}
void close(){...};
public signals:
void close_non_active_docs_button_pressed(Document *active_doc);
...
emit close_non_active_docs_button_pressed(this);
}
///CONNECT(...)
Related
I exposed a pointer variable to qml like this:
Fruit:
class Fruit : public QObject
{
Q_OBJECT
Q_PROPERTY(int qualityGrade READ qualityGrade WRITE setQualityGrade NOTIFY qualityGradeChanged)
Q_PROPERTY(bool organic READ organic WRITE setOrganic NOTIFY organicChanged)
public:
int qualityGrade() const
{
return m_qualityGrade;
}
bool organic() const
{
return m_organic;
}
public slots:
void setQualityGrade(int qualityGrade)
{
if (m_qualityGrade == qualityGrade)
return;
m_qualityGrade = qualityGrade;
emit qualityGradeChanged(m_qualityGrade);
}
void setOrganic(bool organic)
{
if (m_organic == organic)
return;
m_organic = organic;
emit organicChanged(m_organic);
}
signals:
void qualityGradeChanged(int qualityGrade);
void organicChanged(bool organic);
private:
int m_qualityGrade = -1;
bool m_organic = false;
};
MyClass.h:
class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(Fruit* featuredFruit READ featuredFruit WRITE setFeaturedFruit NOTIFY featuredFruitChanged)
public:
explicit MyClass(QObject *parent = nullptr);
~MyClass();
Fruit* featuredFruit() const
{
return m_featuredFruit;
}
public slots:
void setFeaturedFruit(Fruit* featuredFruit)
{
if (m_featuredFruit == featuredFruit)
return;
m_featuredFruit = featuredFruit;
emit featuredFruitChanged(m_featuredFruit);
}
signals:
void featuredFruitChanged(Fruit* featuredFruit);
private:
Fruit* m_featuredFruit = nullptr;
};
MyClass.cpp:
MyClass::MyClass(QObject *parent) : QObject(parent)
{
m_featuredFruit = new Fruit();
m_featuredFruit->setQualityGrade(2);
QTimer *timer = new QTimer();
connect(timer, &QTimer::timeout, this, [=]() {
//m_featuredFruit->deleteLater(); //<--- activating these two lines causes to force working featuredFruitChanged signal
//m_featuredFruit = new Fruit();
m_featuredFruit->setQualityGrade(5);
emit featuredFruitChanged(m_featuredFruit);
delete timer;
});
timer->start(5000);
}
MyClass::~MyClass()
{
m_featuredFruit->deleteLater();
m_featuredFruit = nullptr;
}
and I used it in QML as follow:
MyClass {
id: classObj
onFeaturedFruitChanged: console.log("original property shows an change");//<--- called as expected
}
Item {
property Fruit selectedFruit: classObj.featuredFruit //<--- binding qml defined property to C++ property
onSelectedFruitChanged: {
console.log("binded property recieved change signal");//<--- not called after changes!!!
alertAnimation.restart(); //<--- an example of usage
}
}
The problem is whenever I emit featuredFruitChanged, the binding qml property does not received change signal.
What is wrong?! Is this a Qt Framework bug? Any suggestion?
Also I tried overloading equality operator in C++ without success
Update:
OK, I add some more precisions to my sample code in order to reproduce problem easier.
A typo in my sample code fixed (thanks #ihor-drachuk). The problem exist yet.
Because you misspelled featuredFruit and wrote featuedFruit. Fix it and it will work.
Update: It should work if call setFeaturedFruit or if change it from QML. It will not work as you expect if change some property of featuredFruit even if it is selected
Update 2: QML call onChanged if changed value, value is pointer to object. So if pointer changed - then onChanged will be called. If something behind pointer changed - no.
But you can handle it with help of Connections:
Connections {
target: classObj.featuredFruit
onTargetChanged: console.warn("Target changed!");
onQualityGradeChanged: console.warn("onQualityGradeChanged!");
onOrganicChanged: console.warn("onOrganicChanged!");
}
Also you can add to Fruit some special signal like somethingChangedInMe and emit it in each setter. So, you can write in Connections just this signal handler:
Connections {
target: classObj.featuredFruit
onTargetChanged: console.warn("Target changed!");
onSomethingChangedInMe: console.warn("onSomethingChangedInMe!");
}
I am fairly new to Qt / QtQuick and I have to develop an application, which uses some sensor data that is received in a different thread over network periodically. This data should be used inside c++ for calculations and the latest data should also be displayed in QML. Everything is setup to be thread-safe inside c++ by using a mutex for protection and the data is visibly updated inside QML.
However, I have some concerns about thread-safety on the QML side and I cannot find information or an example on the web about this topic. Specifically I am concerned about returning a pointer (which was the only way to return a C++ object to QML I guess) instead of a value and therefore a copy of the object. Here is a minimal example demonstrating the concern:
// File data.h
#include <QObject>
class Data : public QObject {
Q_OBJECT
Q_PROPERTY(QString someData READ someData WRITE setSomeData NOTIFY someDataChanged)
public:
explicit Data(QObject* parent = nullptr)
:QObject(parent)
{
}
QString someData() const {
return _someData;
}
void setSomeData(const QString& value) {
if (_someData != value) {
_someData = value;
emit someDataChanged();
}
}
signals:
void someDataChanged();
private:
QString _someData;
}; // Data
// File: controller.h
#include <QObject>
#include <thread>
class Controller : public QObject {
Q_OBJECT
Q_PROPERTY(Data data READ data NOTIFY dataChanged)
public:
explicit Controller(QObject* parent = nullptr)
:QObject(parent)
,_running(false)
,_data(nullptr)
{
_data = new Data();
}
virtual ~Controller() {
delete _data;
}
void start() {
_running = true;
_thread = std::thread([this]() { _threadFunc(); });
}
void stop() {
_running = false;
if (_thread.joinable()) {
_thread.join();
}
}
Data* data() {
return _data;
}
signals:
void dataChanged();
private:
void _threadFunc() {
while (_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
_data.setSomeData("foo");
emit dataChanged();
}
}
bool _running;
std::thread _thread;
Data* _data;
}; // Controller
// File main.qml
import QtQuick 2.0
Rectangle {
width: 100
height: 100
Text {
anchors.centerIn: parent
text: Controller.data.someData
}
}
Data is a simple container holding a QString as property. The controller contains the property data and starts a thread that periodically updates data and emits changes as signal. The output will be displayed correctly, but it feels pretty unsafe to return a raw pointer. So my questions here are:
What happens if the data is written too fast and the thread manipulates the data at the same time when QML is using the pointer to update the visuals?
Are there alternatives to returning a raw pointer, e.g., something Qt offers for this purpose and something I have not found yet?
Is my kind of thinking wrong when it comes to using Qt/QML? I first developed the C++ backend (without any Qt parts) and now I am trying to connect it to the GUI. Maybe I should better design the backend around Qt or QML-friendly from start respectively?
Well, I think I found a solution to my problem: I am still sure that working on the same object will cause issues. I read a bit about QML ownership and found out that by using a Property, the ownership remains at the C++ side. By using a function returning a pointer, QML takes over ownership and will take care to delete the object later on. So what I did here was following if someone encounters the same issue some day:
// File data.h
#include <QObject>
class Data : public QObject {
Q_OBJECT
Q_PROPERTY(QString someData READ someData WRITE setSomeData NOTIFY someDataChanged)
public:
explicit Data(QObject* parent = nullptr)
:QObject(parent)
{
}
Data(const Data& data)
:QObject(data.parent)
,_someData(data.someData)
{
}
QString someData() const {
return _someData;
}
void setSomeData(const QString& value) {
if (_someData != value) {
_someData = value;
emit someDataChanged();
}
}
signals:
void someDataChanged();
private:
QString _someData;
}; // Data
// File: controller.h
#include <QObject>
#include <thread>
#include <mutex> // New
class Controller : public QObject {
Q_OBJECT
//Q_PROPERTY(Data data READ data NOTIFY dataChanged) // Removed
public:
explicit Controller(QObject* parent = nullptr)
:QObject(parent)
,_running(false)
,_data(nullptr)
{
_data = new Data();
}
virtual ~Controller() {
delete _data;
}
void start() {
_running = true;
_thread = std::thread([this]() { _threadFunc(); });
}
void stop() {
_running = false;
if (_thread.joinable()) {
_thread.join();
}
}
Q_INVOKABLE Data* data() { // Modified to be an invokable function instead of a property getter
std::lock_guard<std::mutex> lock(_mutex); // New
return new Data(*_data); // New
}
signals:
void dataChanged();
private:
void _threadFunc() {
while (_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::lock_guard<std::mutex> lock(_mutex); // New
_data.setSomeData("foo");
emit dataChanged();
}
}
bool _running;
std::thread _thread;
std::mutex _mutex; // New
Data* _data;
}; // Controller
// File main.qml
// NOTE: Controller is registered as context property alias 'controller'
import QtQuick 2.0
// Import the datatype 'data' to be used in QML
//import ...
Rectangle {
id: myRect
width: 100
height: 100
property Data data
Connections {
target: controller
onDataChanged: {
myRect.data = controller.data()
}
}
Text {
anchors.centerIn: parent
text: data.someData
}
}
Basically, I make sure to lock the object and to take a copy. This copy can then safely be used by QML and the QML engine will take care to delete the memory after usage. Furthermore, I create an instance of the Data object in QML and register the signal to fetch and assign the latest copy.
My main objective is to receive signals from singleton objects while defining QML component in *.qml file.
Let's say I defined a singleton object in C++ code like this:
class MySingleton : public QObject
{
Q_OBJECT
Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged)
typedef QObject Base;
public:
static MySingleton* instance();
const QString& value() const;
void setValue(const QString& value);
signals:
void valueChanged();
private:
MySingleton(QObject* parent = nullptr);
QString m_value;
};
In MySingleton.cpp:
MySingleton* MySingleton::instance()
{
static MySingleton* obj = new MySingleton();
return obj;
}
const QString& MySingleton::value() const
{
return m_value;
}
void MySingleton::setValue(const QString& value)
{
if (value != m_value) {
m_value = value;
emit valueChanged();
}
}
MySingleton::MySingleton(QObject* parent)
: Base(parent),
m_value("SomeInitialValue")
{
}
The singleton is successfully registered with QML engine:
QObject *getMySingleton(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
return MySingleton::instance();
}
void qmlRegisterMySingleton()
{
qmlRegisterSingletonType<MySingleton>("MySingleton", 1, 0, "MySingleton", &getMySingleton);
}
int main(int argc, const char** argv)
{
...
qmlRegisterMySingleton();
...
}
Now, I try to use signals from the singleton. Somewhere in ".qml" file:
import QtQuick 2.1
import MySingleton 1.0
Rectangle {
id: someRectangle
property string singletonValue : MySingleton.value
MySingleton.onValueChanged: {
consol.log("Value changed")
}
}
Using this syntax I receive the "Non-existent attached object" error for the line containing "MySingleton.onValueChanged:". Note that the assignment to the "singletonValue" property was successful.
I also tried to change a syntax to the following:
import QtQuick 2.1
import MySingleton 1.0
Rectangle {
id: someRectangle
property string singletonValue : MySingleton.value
MySingleton {
onValueChanged: {
consol.log("Value changed")
}
}
}
The error message is "Element is not creatable", which is kind of expected.
My questions are:
Is it possible to connect to a singleton signals when defining some QML component?
If yes, what is the correct syntax?
If not, what is the correct / accepted way to receive a notifications about core data change events (defined in some singleton object) while defining UI elements (widgets) in QML files?
Try this:
Connections {
target: MySingleton
onValueChanged: {
console.log("Value changed")
}
}
Also
I guess your have a problem with deletion of singleton object.
You have typo in onValueChanged: - there is no consol object in QML
I’m using this connector to RabbitMQ:
https://github.com/fuCtor/QAMQP
I need performance and multi-thread in my application. Please, can I use multi-thread with this connector?
I tried:
void Test::newMessage(QAMQP::Queue * q) {
while (q->hasMessage()) {
QAMQP::MessagePtr message = q->getMessage();
MyEvent *me = new MyEvent();
me->message = message;
poolThreadPosicao->start(me);
}
}
class MyEvent : public QRunnable {
public:
QAMQP::MessagePtr message;
void run() {
s.queue->ack(this->message);
}
};
In some messages the RabbitMQ say: “Unacked 10 messages”. The 10 messages is my qos in broker message. What I need solve this? How to do?
First of all I recommend that you switch to https://github.com/mbroadst/qamqp, as it is the replacement for the original project (which is no longer in active development). The updated code contains many performance and memory enhancements, as well as more complete support for RabbitMQ. Having said that, currently both versions of the project are aimed at having one connection per thread. This means that any of the Channels that you create (an Exchange, or a Queue), will be parented to the connection (Client) which created it and therefore are bound to the creating thread.
One way to handle the problem you are facing would be to inherit from QRunnable and QObject, emitting the message when you have completed your task (NOTE: this is untested, I'm just giving the basic structure):
using namespace QAMQP;
class MessageJob : public QRunnable, public QObject
{
Q_OBJECT
public:
MessageJob(const Message &message)
: m_message(message)
{
}
virtual void run() {
// process the message
// when you are done, emit the finished signal
Q_EMIT finished(m_message);
}
Q_SIGNALS:
void finished(const Message &message);
private:
Message m_message;
};
class Test : public QObject
{
Q_OBJECT
public:
Test(QObject *parent = 0)
: QObject(parent)
{
// setup and connect client
// create queue and start consuming
}
private Q_SLOTS:
void messageReceived(const Message &message)
{
MessageJob *job = new MessageJob; // no parent, this will be autodeleted
connect(job, SIGNAL(finished(Message)), this, SLOT(jobFinished(Message)), Qt::QueuedConnection);
// NOTE: Qt::QueuedConnection is very important as it allows the signal to
// cross threads
QThreadPool::globalInstance()->start(job);
}
void jobFinished(const Message &message) {
m_queue->ack(message);
}
private:
Client m_client;
Queue *m_queue;
};
Following case:
Let's say there is a binary library which defines the class "Base", and many subclasses ("Derivative1", "Derivative2" etc) of it.
I want to extend these subclasses in my own code, but because my extensions are the same for all subclasses as they only deal with parts of Base, it would be tedious to subclass every Derivative class and add the same code over and over again.
My first idea was to simply write a class template which would do the work for me, but because the library I'm dealing with is Qt, QObject has foiled me.
My second idea was to use macros to generate each class structure, but this was also thwarted by moc.
The "reparent" in the title is because I thought of deriving from Base and creating BaseExtended, and then somehow tell the compiler to reparent every Derivative to this extended class. Isn't there a way to for example declare the "Base" in "BaseExtended" virtual, and then just write
class Derivative1Extended : public Derivative1, public BaseExtended {}
and have the virtual Base in BaseExtended point to the Base in Derivative1, thus basically "squeezing ing" my extensions between Base and Derivative1?
(By the way, I tried to keep the above as generic as possible, but what I'm actually doing is trying add signals for "focusIn" and "focusOut" to every QWidget derivative without writing the same code over and over again for every QWidget subclass I use)
EDIT:
For reference, here's my current implementation:
// qwidgetfs.h
class QLineEditFS : public QLineEdit
{
Q_OBJECT
private:
void focusInEvent(QFocusEvent *);
void focusOutEvent(QFocusEvent *);
public:
QLineEditFS(QWidget *parent = 0);
signals:
void focusReceived(QWidgetFS::InputType);
void focusLost();
};
// qwidgetfs.cpp
QLineEditFS::QLineEditFS(QWidget *parent /*= 0*/)
: QLineEdit(parent)
{}
void QLineEditFS::focusInEvent(QFocusEvent *e)
{
QLineEdit::focusInEvent(e);
emit focusReceived(QWidgetFS::InputText);
}
void QLineEditFS::focusOutEvent(QFocusEvent *e)
{
QLineEdit::focusOutEvent(e);
emit focusLost();
}
And this repeated for QSpinBoxFS, QComboBoxFS, QCheckBoxFS and so on...
Instead I would like to just define this logic in a common class QWidgetFS, and then "inject" it into other classes derived from QWidget
I'm not sure you'll really be able to do what you are suggesting without modifying Qt and recompiling it.
Perhaps to do what you want, you could use event filters installed on the objects that you want to handle focus events from?
little test app:
header:
class FocusEventFilter : public QObject
{
Q_OBJECT
public:
FocusEventFilter(QObject* parent)
: QObject(parent)
{}
Q_SIGNALS:
void focusIn(QWidget* obj, QFocusEvent* e);
void focusOut(QWidget* obj, QFocusEvent* e);
protected:
bool eventFilter(QObject *obj, QEvent *e);
};
class testfocus : public QMainWindow
{
Q_OBJECT
public:
testfocus(QWidget *parent = 0, Qt::WFlags flags = 0);
~testfocus();
public Q_SLOTS:
void onFocusIn(QWidget*, QFocusEvent*);
void onFocusOut(QWidget*, QFocusEvent*);
private:
Ui::testfocusClass ui;
};
Implementation
#include <QFocusEvent>
#include "testfocus.h"
bool FocusEventFilter::eventFilter(QObject *obj, QEvent *e)
{
if (e->type() == QEvent::FocusIn) {
bool r = QObject::eventFilter(obj, e);
QFocusEvent *focus = static_cast<QFocusEvent*>(e);
QWidget* w = qobject_cast<QWidget*>(obj);
if (w) {
emit focusIn(w, focus);
}
return r;
}
else if (e->type() == QEvent::FocusOut) {
bool r = QObject::eventFilter(obj, e);
QFocusEvent *focus = static_cast<QFocusEvent*>(e);
QWidget* w = qobject_cast<QWidget*>(obj);
if (w) {
emit focusOut(w, focus);
}
return r;
}
else {
// standard event processing
return QObject::eventFilter(obj, e);
}
}
testfocus::testfocus(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
FocusEventFilter* filter = new FocusEventFilter(this);
ui.lineEdit->installEventFilter(filter);
ui.lineEdit_2->installEventFilter(filter);
connect(filter, SIGNAL(focusIn(QWidget*, QFocusEvent*)), this, SLOT(onFocusIn(QWidget*, QFocusEvent*)));
connect(filter, SIGNAL(focusOut(QWidget*, QFocusEvent*)), this, SLOT(onFocusOut(QWidget*, QFocusEvent*)));
}
testfocus::~testfocus()
{
}
void testfocus::onFocusIn(QWidget* obj, QFocusEvent*)
{
obj->setStyleSheet("background-color:#aaaaff;");
}
void testfocus::onFocusOut(QWidget* obj, QFocusEvent*)
{
obj->setStyleSheet("background-color:#ffaaaa;");
}
Of course, YMMV. You could always have a separate filter per object. This method means you can avoid deriving from everything. Not as efficient but it should work.
You may be able to do what you want in the event filter itself rather than using signals/slots.
I have done stuff like this in the past with templates. The problem is that you can't use signals.
I'm typing this up without a compiler so please be kind :):
template<typename T>
class FSWidget: public T
{
public:
FSWidget()
{
_delegate = NULL;
}
setDelegate(FSDelegate *delegate)
{
_delegate = delegate;
}
protected:
virtual void focusInEvent(QFocusEvent *e)
{
T::focusInEvent(e);
if (_delegate) {
_delegate->focusInEvent(this);
}
}
virtual void focusOutEvent(QFocusEvent *e)
{
T::focusOutEvent(e);
if (_delegate) {
_delegate->focusOutEvent(this);
}
}
private:
FSDelegate *_delegate;
};
So, the advantage is when you need to use this you can basically create a class like this:
FSWidget<QLineEdit *> lineEdit = new FSWidget<QLineEdit *>;
lineEdit->setDelegate(delegate);
You can put in whatever you want instead of QLineEdit and it will work.
And then teh FSDelegate could be just an interface that you mix into whatever class needs to act on the info. It could be one of these:
class FSDelegate
{
public:
virtual void focusInEvent(QWidget *w) = 0;
virtual void focusOutEvent(QWidget *w) = 0;
};
If you're always doing the same thing in on focusInEvent and focusOutEvents, you can implement these functions and make a real Mixin class.
Hopefully this can avoid some code duplication for you.