Non-blocking reading in background Qt thread on Linux caused EAGAIN - c++

Here is the minimal example of background data reading in Qt (available in GitLab). The program open file and read data byte-by-byte. The flow is the following:
// Flow
//
// Widget Worker
// +
// | create thread
// | create worker +
// | move worker to thread |
// | start thread |
// | |
// | start onStart |
// |---------------------------------->|
// | |
// | onReady ready |
// |<----------------------------------| .--<--.
// | semaphore acquire | | |
// | print data | | ^
// | | v |
// | semaphore release | | |
// |---------------------------------->| `-->--
// | |
// | |
// | finished |
// | |
// | delete worker -
// | detete thread
// | quit application
// -
The following code sometimes (about 1:30) caused EAGAIN error code when reading data from regular file.
$ ./rdqt ../main.cpp
Success 32768
$ ./rdqt ../main.cpp
Resource temporarily unavailable 32768
How is it possible for regular file? Or is this result of incorrect multithreading implementation?
.
├── main.cpp
├── Widget.cpp
├── Widget.h
├── Worker.cpp
└── Worker.h
main.cpp
#include <QApplication>
#include "Widget.h"
int main (int argc, char * argv [])
{
QApplication application (argc, argv);
if (argc > 1) {
Widget widget (argv [1]);
widget.show ();
return application.exec ();
}
return EXIT_FAILURE;
}
Widget.h
#ifndef READ_DATA_WIDGET_H
#define READ_DATA_WIDGET_H
#include <QWidget>
#include <QThread>
#include <QSemaphore>
#include "Worker.h"
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget (const char *, QWidget * parent = nullptr);
virtual ~Widget ();
signals:
void start ();
public slots:
void onReady (char);
private:
QThread * thread;
QSemaphore * semaphore;
Worker * worker;
};
#endif//READ_DATA_WIDGET_H
Widget.cpp
#include "Widget.h"
#include <QDebug>
#include <QApplication>
Widget::Widget (const char * path, QWidget * parent)
: QWidget (parent)
, thread {new QThread}
, semaphore {new QSemaphore (1)}
, worker {new Worker (path, semaphore)}
{
connect (this, & Widget::start, worker, & Worker::onStart);
connect (worker, & Worker::ready, this, & Widget::onReady);
connect (worker, & Worker::finish, [this]() {
thread->quit ();
/*QApplication::quit ();*/
});
worker->moveToThread (thread);
thread->start ();
emit start ();
}
Widget::~Widget ()
{
worker->deleteLater ();
thread->deleteLater ();
}
void Widget::onReady (char /*c*/)
{
/*qDebug ("%c", c);*/
semaphore->release ();
}
Worker.h
#ifndef READ_DATA_WORKER_H
#define READ_DATA_WORKER_H
#include <QObject>
#include <QSemaphore>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker (const char *, QSemaphore *);
virtual ~Worker () = default;
signals:
void ready (char);
void finish ();
public slots:
void onStart ();
private:
const char * path;
QSemaphore * semaphore;
};
#endif//READ_DATA_WORKER_H
Worker.cpp
#include "Worker.h"
#include <QDebug>
#include <unistd.h>
#include <fcntl.h>
Worker::Worker (const char * path, QSemaphore * semaphore)
: QObject ()
, path {path}
, semaphore {semaphore}
{
}
void Worker::onStart ()
{
int file = open (path, O_RDONLY);
char b;
while (read (file, & b, 1) > 0) {
semaphore->acquire ();
emit ready (b);
}
qDebug () << strerror (errno) << (fcntl (file, F_GETFL) /*& O_NONBLOCK*/);
emit finish ();
}

Main answer
Ok, I finally got it. The errno is set internally when locking a mutex by Qt either when calling semaphore->acquire (); or when emitting a signal with emit ready (b); (Qt uses synchronisation objects for queued connections, obviously). Here's how to debug where errno change happens. I added the following line at the beginning of Worker::onStart:
qDebug() << QString("0x%1").arg(reinterpret_cast<quint64>(&errno), 0, 16);
and set a breakpoint on the next line in debugger. Having this address (e.g. 0x7fffda6ce668) I added a memory breakpoint in gdb with watch *0x7fffda6ce668 in the gdb console (if you use Qt Creator, enable Window -> Views -> Debugger Log). I immediately got the backtrace for the errno change:
#0 0x00007ffff63964ae in syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:42
#1 0x00007ffff6eb0610 in QBasicMutex::lockInternal() () from /home/(my-user-name)/apps/Qt5.5.0/5.5/gcc_64/lib/libQt5Core.so.5
#2 0x00007ffff70a7199 in QCoreApplication::postEvent(QObject*, QEvent*, int) () from /home/(my-user-name)/apps/Qt5.5.0/5.5/gcc_64/lib/libQt5Core.so.5
#3 0x00007ffff70d3286 in QMetaObject::activate(QObject*, int, int, void**) () from /home/(my-user-name)/apps/Qt5.5.0/5.5/gcc_64/lib/libQt5Core.so.5
#4 0x000000000040494f in Worker::ready (this=0x8d1550, _t1=0 '\\000') at moc_Worker.cpp:142
#5 0x0000000000403dee in Worker::onStart (this=0x8d1550) at ../qt/Worker.cpp:63
Now, QMutex is implemented in corelib/thread/qmutex_linux.cpp and uses a futex which causes errno == 11 sometimes. I've no idea why this happens, sorry, might be someone's bug ;) You can check the qmutex_linux.cpp code and try to find relevant info on the net for yourself. If you are interested if a specific API call produces an error you can set errno=0 before this call and check it after the call. Btw, I tested it without any file io just sending a dummy character with ready(0), the result was the same. So the problem is not file io.
Previous answer (mostly irrelevant after your code changes)
I think what you're trying to achieve with a QMutex alone is classically done with QMutex and QWaitCondition:
void Worker::onStart ()
{
// ...
while (true) {
QMutexLocker locker(&mutex);
if(read (file, & b, 1) <= 0)
break;
emit ready (b);
// waitCondition unlocks the mutex and
// waits till waitCondition wakeAll/wakeOne is called
// signalling that Widget has finished processing
waitCondition.wait(&mutex);
}
// ...
}
void Worker::onRequest ()
{
// re-locks the mutex and continues the while cycle
waitCondition.wakeAll();
}
Here waitCondition is a member variable like mutex. I haven't checked this code. It's just for illustration of the idea, you may need to change it a little. Links for reference: QWaitCondition description and usage example.

Related

Several Error with Implementing of Threads in QT [C++]

I'm new to implementing Threads in QT and even after reading the Documentation several times and watching Videos, I get some Error which not even Google can help me with.
thread.cpp:14: error: C2440: "Initialisierung": "QFuture" kann nicht in "QFuture" konvertiert werden
Error Codes are in German, tried to change QT Language, but didn't change the Language of the Errors. I can translate them if needed.
It seems the Error happens in this QFuture<int> future = QtConcurrent::run(&Thread::GenerateTable); command, even thought I wrote it 1:1 like from the QT Documentation.
Here is the Code I want to put in a Thread, as you can see it's writing a bit bunch of Numbers into a File, which takes around a Minute.
Thread.h
#ifndef THREAD_H
#define THREAD_H
#include <QObject>
#include <QFuture>
#include <QtConcurrent/QtConcurrent>
class Thread : public QObject
{
Q_OBJECT
public:
explicit Thread(QObject *parent = nullptr);
static bool start();
private:
int GenerateTable();
};
#endif // THREAD_H
Thread.cpp
#include "thread.h"
Thread::Thread(QObject *parent) : QObject(parent)
{
}
bool Thread::start()
{
QFuture<int> future = QtConcurrent::run(&Thread::GenerateTable);
if (future.result() == 0){
return true;
}
else
return false;
}
int Thread::GenerateTable(){
QString Path = QDir::currentPath();
QFile file(Path + "/Table.csv");
if (!file.open(QFile::WriteOnly | QFile::Text)){
return -1;
}
else{
QTextStream stream(&file);
constexpr uint64_t upper = 10'000'000;
QVector<uint64_t> rando(upper);
std::iota(rando.begin(), rando.end(), 1);
std::shuffle(rando.begin(), rando.end(),
std::mt19937(std::random_device{}()));
for (uint32_t i = 0; i < 10'000'000; ++i) {
stream << rando[i] << ',' << '\n';
}
return 0;
}
}
Thread::GenerateTable() is a member function. It needs an object to work on. You are calling it (er .. passing it to QtConcurrent::run()) from the (static) Thread::start() and there's no Thread object to speak of.
Although you've tagged Qt6, I'll point at the Qt5 documentation for calling member functions: you can pass an object (pointer) which you'll need to allocate from somewhere.

Why is QAudioRecorder not recording through the constructor?

header
#ifndef AUDIORECORD_H
#define AUDIORECORD_H
#include <QMediaRecorder>
#include <QAudioRecorder>
#include <QUrl>
class AudioRecorder : public QAudioRecorder
{
Q_OBJECT
public:
AudioRecorder(QObject * parent);
~AudioRecorder(){}
};
#endif // AUDIORECORD_H
source
#include "audiorecord.h"
#include<iostream>
using namespace std;
AudioRecorder::AudioRecorder(QObject * parent = 0)
{
this->setOutputLocation(QUrl::fromLocalFile("test.mp3"));
int x = 0;
while ( x > 10000)
{
this->record();
x++;
}
this->stop();
std::cout<<"\ndsffsdf\n";
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "audiorecord.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QObject p;
AudioRecorder obj(&p);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
This does not produce any error but it does not record also. I am not expecting any quality or full fledged recording.
I just want to see how this recorder works.
That test.mp3 is not getting saved.
What bare minimum can I add or subtract to it to make it record something and save?
Cause
What would be if I tell you 10 000 times: Go buy some milk, while firmly holding your hand, then just before I let you go to say: Ah, forget it? Would you be able to buy the milk?
You are doing the same with your code:
int x = 0;
while ( x > 10000)
{
this->record();
x++;
}
this->stop();
You are calling 10 000 times QAudioRecorder::record, but you do not let Qt get to the event loop and actualy execute your command. Then just before Qt gets to the event loop, you say: stop.
Solution
First of all, you do not need to subclass QAudioRecorder, because you do not add any new functionality to it. Just create an instance of the class and use it.
Second, record and stop are slots. Connect them to the clicked signal of the corresponding push buttons in you GUI, e.g.:
auto *audioRecorder = new QAudioRecorder(this);
...
connect(btnRecord, &QPushButton::clicked, audioRecorder, &QAudioRecorder::record);
connect(btnStop, &QPushButton::clicked, audioRecorder, &QAudioRecorder::stop);
Note: For more information, please take a look at the example from the documentation.

Qt SLOT not triggered by the SIGNAL emitted from std::async in QTest environment

I was investigating the topic of async programming with Qt and I reached the conclusion that it is safe to emit signals from whatever kind of threads (although QT docs only mention QThread), as more or less described here. Now I faced the problem testing my application. To simplify as much as possible: I have the async operation, which might notify MainWindow by emitting the SIGNAL. It works fine in the production, but it doesn't work in unit-test environment with QTest. Complete example (project structure flat, no subdirs):
CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(QtFailure)
enable_testing()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
if(CMAKE_VERSION VERSION_LESS "3.7.0")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
endif()
find_package(Qt5 COMPONENTS Core Widgets Test REQUIRED)
add_library(QtFailure source.cpp header.hpp)
target_include_directories(QtFailure PUBLIC .)
target_link_libraries(QtFailure
pthread
Qt5::Core
Qt5::Widgets
)
add_executable(main main.cpp)
target_link_libraries(main QtFailure)
add_executable(QtFailureTest test.cpp)
target_link_libraries(QtFailureTest
QtFailure
Qt5::Test
)
header.hpp
#pragma once
#include <QMainWindow>
#include <QWidget>
#include <future>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = nullptr);
~MainWindow();
void start();
int counter_value();
signals:
void sendSignal();
private slots:
bool triggerSlot();
private:
bool stop_;
std::future<void> async_oper_;
};
source.cpp
#include "header.hpp"
#include <QMainWindow>
#include <QWidget>
#include <QObject>
#include <QDebug>
#include <future>
#include <chrono>
#include <thread>
static int counter = 0;
MainWindow::MainWindow(QWidget* parent):
QMainWindow(parent),
stop_(false),
async_oper_()
{
QObject::connect(this, SIGNAL(sendSignal()), this, SLOT(triggerSlot()));
}
MainWindow::~MainWindow()
{
stop_ = true;
}
int MainWindow::counter_value()
{
return counter;
}
void MainWindow::start()
{
if (async_oper_.valid()) return;
emit sendSignal(); // this one works
async_oper_ = std::async(std::launch::async, [this]()
{
while (!stop_)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
emit sendSignal(); // this one doesn't work in tests
}
});
}
bool MainWindow::triggerSlot()
{
qDebug() << "triggerSlot: " << counter;
counter++;
}
test.cpp
#include "header.hpp"
#include <QSignalSpy>
#include <QDebug>
#include <QtTest/QtTest>
#include <memory>
#include <chrono>
#include <thread>
class MyFixture: public QObject
{
Q_OBJECT
private:
std::unique_ptr<MainWindow> sut_;
private slots:
void init()
{
qDebug("MyFixture init");
sut_.reset(new MainWindow);
}
void cleanup()
{
qDebug("MyFixture cleanup");
sut_.reset();
}
void example_test()
{
QSignalSpy spy(sut_.get(), SIGNAL(sendSignal()));
sut_->start();
std::this_thread::sleep_for(std::chrono::seconds(1));
qDebug() << "num signals: " << spy.count();
qDebug() << "counter value: " << sut_->counter_value();
}
};
QTEST_MAIN(MyFixture)
#include "test.moc"
main.cpp
#include <QApplication>
#include "header.hpp"
int main(int argc, char** argv)
{
QApplication a(argc, argv);
MainWindow w;
w.start();
w.show();
return a.exec();
}
The output from my test is
PASS : MyFixture::initTestCase()
QDEBUG : MyFixture::example_test() MyFixture init
QDEBUG : MyFixture::example_test() triggerSlot: 0
QDEBUG : MyFixture::example_test() num signals: 10
QDEBUG : MyFixture::example_test() counter value: 1
QDEBUG : MyFixture::example_test() MyFixture cleanup
PASS : MyFixture::example_test()
PASS : MyFixture::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 1003ms
which means that the slot was triggered only once, by the signal emitted from the main thread.
The output from main is:
...
triggerSlot: 25
triggerSlot: 26
triggerSlot: 27
etc ...
which is the expected behavior. Why is there a difference between QTest environment and normal QApplication in main? What should I do to correct tests behavior?
I must use standard C++ threads, because my GUI is just a facade to real non-Qt related system, which has different kinds of async opers, callbacks etc.
Sorry for the amount of code, but with QT I cannot really squeeze it in a few lines.
=== EDIT ===
Specifying Qt::DirectConnection connection attribute will "fix" the issue in the QTest environment. But this is something I cannot do in most cases, because GUI actions must take place in the main thread (e.g. scync oper emits signal to trigger QPixmap refresh);
The signal emit code is correct. Queued Signal-Slot connection requires event loop to be running in the receiver thread for signal delivery:
Events to that object are dispatched by that (receiver) thread's event loop.
Event loop of the receiver thread aren't working because you block it in the line
// just suspends current thread without running any event loop
std::this_thread::sleep_for(std::chrono::seconds(1));
That is, event loop of the receiver thread are blocking throughout the whole example_test() method body. There is no one line which runs an event loop within itself. That is not Qt Test or QTEST_MAIN() issue.
Here is how you can fix that:
void example_test()
{
QSignalSpy spy(sut_.get(), SIGNAL(sendSignal()));
sut_->start();
QElapsedTimer timer;
timer.start();
while(timer.elapsed() < 1000)
{
spy.wait(10); // event loop runs here
}
qDebug() << "num signals: " << spy.count();
qDebug() << "counter value: " << sut_->counter_value();
}
QSignalSpy::wait():
Starts an event loop that runs until the given signal is received.
Optionally the event loop can return earlier on a timeout (in
milliseconds).
Returns true if the signal was emitted at least once in timeout milliseconds, otherwise returns false.

netcat command in c++

I am a newbee when it comes to coding in C++.
I am currently using qt to make a simple GUI, where I want to send a command to a device via TCP/IP.
When i connect my computer to the device and via the terminal send the command:
echo '3b00010000001b010001000000120000013000002713000300030101' | xxd -r -p | nc 192.168.1.101 30013
The device does correspondently.
I need to be able to send this command in qt as a function. Can anyone help me? This is what i have so far (does not work)
Header:
#ifndef SOCKET_H
#define SOCKET_H
#include <QObject>
#include <QTcpSocket>
#include <QtDebug>
#include <string>
using namespace std;
class Socket : public QObject
{
Q_OBJECT
public:
explicit Socket(QObject *parent = nullptr);
void Connect(const QString &host, const string &cmd);
private:
QTcpSocket *socket;
};
#endif // SOCKET_H
Cpp:
#include "socket.h"
Socket::Socket(QObject *parent) : QObject(parent)
{
}
void Socket::Connect(const QString &host, const string &cmd)
{
//connect
socket = new QTcpSocket(this);
socket->connectToHost(host,30013);
if(socket->waitForConnected(1500))
{
qDebug() << "Connected";
//send
socket->write(cmd.c_str(), cmd.size());
socket->waitForBytesWritten(1000);
//close
socket->close();
}
else
qDebug() << "Not Connected";
}
Then I want to send the command by:
Socket.Test
Test.Connect("192.168.1.101","3b00010000001b010001000000120000013000002713000300030101")
Any help would be much appreciated. Thanks.
As your command is a fixed string you can simply enter the characters directly:
const char data[] = "\x3b\x00\x01\x00\x00\x00\x1b\x01\x00\x01\x00\x00\x00\x12\x00\x00\x01\x30\x00\x00\x27\x13\x00\x03\x00\x03\x01\x01";
Test.Connect("192.168.1.101",string(data, sizeof(data)-1));
Note that as your data has embedded null characters you can't simply pass the string literal to std::string as it would truncate the string before the first null character.

QML custom item state does not change when binded variable changes on C++ state

I have following custom QML item with two states:
import QtQuick 2.0
import si.testfirm 1.0
Item
{
id: ueDatabaseStatusIndicator
property string ueParamImageStatusOn
property string ueParamImageStatusOff
state: ueApplicationStatus.m_ueBluetoothPrinterConnectionStatus===UeTypeBluetootPrinterConnectionStatus.NOT_PAIRED?
"ueStatusIndicatorBluetoothNotConnected":
"ueStatusIndicatorBluetoothConnected"
Image
{
id: ueStatusIndicatorCurrentImage
smooth: true
fillMode: Image.PreserveAspectFit
width: 96
height: 96
sourceSize.width: 96
sourceSize.height: 96
} // Image
states:
[
State
{
name: "ueStatusIndicatorBluetoothConnected"
PropertyChanges
{
target: ueStatusIndicatorCurrentImage
source: ueParamImageStatusOn
} // PropertyChanges
}, // State
State
{
name: "ueStatusIndicatorBluetoothNotConnected"
PropertyChanges
{
target: ueStatusIndicatorCurrentImage
source: ueParamImageStatusOff
} // PropertyChanges
} // State
] // states
} // Item
In first state, named ueStatusIndicatorBluetoothNotConnected, it shows red icon, which resembles bluetooth printer is not paired. In second state, named ueStatusIndicatorBluetoothConnected, it shows blue icon, which resembles bluetooth printer is paired with app. Now, when I run this app with following main.cpp file:
#include <QtQml>
#include <QApplication>
#include <QQmlApplicationEngine>
#include "database/uepeoplemodel.h"
#include "core/ueapplicationstatus.h"
#include "core/uedatabaseconnectionstatus.h"
#include "core/uebluetoothmanager.h"
#include "core/uebluetoothprinterconnectionstatus.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeApplicationStatus* ueApplicationStatus=new UeApplicationStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
UeBluetoothManager* ueBtManager=new UeBluetoothManager(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSlotDatabaseConnectionChanged(UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus)));
QObject::connect(ueBtManager,
SIGNAL(ueSignalBtPrinterConnectionChanged(UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus)),
ueApplicationStatus,
SLOT(ueSlotBtPrinterConnectionChanged(UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus)));
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.rootContext()->setContextProperty("ueBtManager",
ueBtManager);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
qmlRegisterUncreatableType<UeDatabaseConnectionStatus>("si.testfirm",
1,
0,
"UeTypeDatabaseConnectionStatus",
"Database Connection Status");
qmlRegisterUncreatableType<UeBluetoothPrinterConnectionStatus>("si.testfirm",
1,
0,
"UeTypeBluetootPrinterConnectionStatus",
"Bluetooth Printer Connection Status");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
uePeopleModel->ueConnectToDatabase();
ueBtManager->ueStartPairing();
ueApplicationStatus->ueUpdate(uePeopleModel->ueFetchUsers());
return app.exec();
}
in the app red icon is showed, which is ok, since printer is not paired, however, with the line ueBtManager->ueStartPairing(); I start searching for bluetooth printer and the printer is found and paired, since slot void UeBluetoothManager::ueSlotPairingFinished(const QBluetoothAddress& address,QBluetoothLocalDevice::Pairing pairing) gets called as you can see from screenshot:
In the last line, as you can see from screenshot, I emit signal UeBluetoothManager::void ueSignalBtPrinterConnectionChanged(const UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus& newStatus); which is called in main.cpp by ueApplicationStatus object to update its status. Here is UeApplicationStatus header:
#ifndef UEAPPLICATIONSTATUS_H
#define UEAPPLICATIONSTATUS_H
#include <QObject>
#include <QList>
#include <QDebug>
#include "../core/uetypes.h"
#include "../core/uedatabaseconnectionstatus.h"
#include "../core/uebluetoothprinterconnectionstatus.h"
class UeApplicationStatus : public QObject
{
Q_OBJECT
Q_PROPERTY(UeTypeUsers* m_ueUsers
READ ueUsers
WRITE ueSetUsers
NOTIFY ueSignalUsersChanged)
Q_PROPERTY(UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus m_ueDatabaseConnectionStatus
READ ueDbConnectionStatus
WRITE ueSetDbConnectionStatus
NOTIFY ueSignalDatabaseConnectionChanged)
Q_PROPERTY(UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus m_ueBluetoothPrinterConnectionStatus
READ ueBtPrinterConnectionStatus
WRITE ueSetBtPrinterConnectionStatus
NOTIFY ueSignalBtPrinterConnectionChanged)
private:
UeTypeUsers* m_ueUsers;
UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus m_ueDatabaseConnectionStatus;
UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus m_ueBluetoothPrinterConnectionStatus;
public:
explicit UeApplicationStatus(QObject *parent = 0);
~UeApplicationStatus();
inline UeTypeUsers* ueUsers() const
{ return this->m_ueUsers; }
inline UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus ueDbConnectionStatus() const
{ return this->m_ueDatabaseConnectionStatus; }
inline UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus ueBtPrinterConnectionStatus() const
{ return this->m_ueBluetoothPrinterConnectionStatus; }
inline void ueSetUsers(UeTypeUsers* const users)
{ this->m_ueUsers=users; }
inline void ueSetDbConnectionStatus(const UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus& status)
{ this->m_ueDatabaseConnectionStatus=status; }
inline void ueSetBtPrinterConnectionStatus(const UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus status)
{ this->m_ueBluetoothPrinterConnectionStatus=status; }
signals:
void ueSignalUsersChanged();
void ueSignalDatabaseConnectionChanged(const UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus& newStatus);
void ueSignalBtPrinterConnectionChanged(const UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus& newStatus);
public slots:
void ueSlotDatabaseConnectionChanged(const UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus& newStatus);
void ueSlotBtPrinterConnectionChanged(const UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus& newStatus);
void ueUpdate(UeTypeUsers* const users);
};
#endif // UEAPPLICATIONSTATUS_H
and its implementation:
#include "ueapplicationstatus.h"
UeApplicationStatus::UeApplicationStatus(QObject *parent)
: QObject(parent)
{
this->ueSetUsers(new UeTypeUsers());
this->ueSetDbConnectionStatus(UeDatabaseConnectionStatus::NOT_CONNECTED);
this->ueSetBtPrinterConnectionStatus(UeBluetoothPrinterConnectionStatus::NOT_PAIRED);
connect(this,
SIGNAL(ueSignalDatabaseConnectionChanged(UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus)),
this,
SLOT(ueSlotDatabaseConnectionChanged(UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus)));
connect(this,
SIGNAL(ueSignalBtPrinterConnectionChanged(UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus)),
this,
SLOT(ueSlotBtPrinterConnectionChanged(UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus)));
} // constructor
UeApplicationStatus::~UeApplicationStatus()
{
delete this->ueUsers();
} // destructor
void UeApplicationStatus::ueSlotDatabaseConnectionChanged(const UeDatabaseConnectionStatus::UeTypeDatabaseConnectionStatus& newStatus)
{
this->ueSetDbConnectionStatus(newStatus);
} // ueSignalDatabaseConnectionChanged
void UeApplicationStatus::ueSlotBtPrinterConnectionChanged(const UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus& newStatus)
{
this->ueSetBtPrinterConnectionStatus(newStatus);
} // ueSlotBtPrinterConnectionChanged
void UeApplicationStatus::ueUpdate(UeTypeUsers* const users)
{
this->ueSetUsers(users);
} // ueUpdate
The question is, why images are not switched on QML side inside custom item ueDatabaseStatusIndicator, which code is listed first?
It could be because of the way you are initialising your application. You are starting the event loop after emitting the signals. Try this.
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QTimer::singleshot(150, this, [&]() {
uePeopleModel->ueConnectToDatabase();
ueBtManager->ueStartPairing();
ueApplicationStatus->ueUpdate(uePeopleModel->ueFetchUsers());
});
return app.exec();
This is just my guess. Best of luck.
update
inline void ueSetBtPrinterConnectionStatus(const UeBluetoothPrinterConnectionStatus::UeTypeBluetootPrinterConnectionStatus status)
{
m_ueBluetoothPrinterConnectionStatus=status;
emit ueSignalBtPrinterConnectionChanged(m_ueBluetoothPrinterConnectionStatus);
}
You must remove the connect calls as this creates a infinite loop.