I have this simplified code:
class MyCustomObject {
};
class DeviceConnection : public QObject {
Q_OBJECT
public:
explicit DeviceConnection(QObject* const parent = nullptr);
signals:
void readFinished(MyCustomObject result);
public slots:
void readFromDevice();
};
DeviceConnection::readFromDevice() {
/* ... */
emit readFinished(MyCustomObject());
}
void MainWindow::on_actionRead_triggered() {
QThread* const thread = new QThread(this);
DeviceConnection* const connection = new DeviceConnection();
connection->moveToThread(thread);
thread->start();
connect(connection, &DeviceConnection::readFinished, this, [=](MyCustomObject data) {
/* This never runs. */
connection->deleteLater();
thread->quit();
});
QTimer::singleShot(0, connection, &DeviceConnection::readFromDevice);
}
This starts reading just fine. I can see in the debugger that I am getting to the emit line, and I am getting there in the thread. But I can also see in the debugger, and in the behavior of the code, that the readFinished lambda is never called. This is also true with slots that aren't lambdas. What's the problem?
Edit: This code runs fine when I don't use an extra thread, but of course it blocks the main thread while readFromDevice() runs.
I figured it out. Unfortunately I simplified the important bit away when I first asked the question, but I just edited it back in.
The problem is that MyCustomObject cannot be enqueued in the Qt message queue. To do that, you need to run this:
qRegisterMetaType<MyCustomObject>("MyCustomObject");
or
// ideally just after the definition for MyCustomObject
Q_DECLARE_METATYPE(MyCustomObject);
// any time before you want to enqueue one of these objects
qRegisterMetaType<MyCustomObject>();
your defined signal should take an argument of QString type.
Related
I've got the following MQL code:
class Collection {
public: void *Get(void *_object) { return NULL; }
};
class Timer {
protected:
string name;
uint start, end;
public:
void Timer(string _name = "") : name(_name) { };
void TimerStart() { start = GetTickCount(); }
void TimerStop() { end = GetTickCount(); }
};
class Profiler {
public:
static Collection *timers;
static ulong min_time;
void Profiler() { };
void ~Profiler() { Deinit(); };
static void Deinit() { delete Profiler::timers; };
};
// Initialize static global variables.
Collection *Profiler::timers = new Collection();
ulong Profiler::min_time = 1;
void main() {
// Define local variable.
static Timer *_timer = new Timer(__FUNCTION__); // This line doesn't.
//Timer *_timer = new Timer(__FUNCTION__); // This line works.
// Start a timer.
((Timer *) Profiler::timers.Get(_timer)).TimerStart();
/* Some code here. */
// Stop a timer.
((Timer *) Profiler::timers.Get(_timer)).TimerStop();
}
which defines a Timer class which is used as a timer to profile the functions how long it took. The original version uses a list of timers to store time separately on each call, however, the code has been simplified to provide a minimum working example and focus on the actual compilation problem.
The problem is when I'm using the following line in order to initialize a static variable:
static Timer *_timer = new Timer(__FUNCTION__); // Line 30.
the compilation fails with:
'Timer' - local variables cannot be used TestProfiler.mqh 30 30
When I drop static word, the code compiles fine.
But it doesn't help me, as I want to define this variable as a static pointer to the class, as I don't want to destroy my object each time when the same function is called over and over again, so the timers can be added to the list which can be read later on. I don't really see why the MQL compiler would prevent from compiling the above code. I also believe this syntax worked fine in the previous builds.
I'm using MetaEditor 5.00 build 1601 (May 2017).
What is wrong with my static variable declaration and how can I correct it, so it can point to a Timer class?
Keyword static has two different meanings in MQL4/5: it indicates that a member of a class is static (which is obvious), and it also says that a variable is static... for instance, if you have a variable that is used only in one function, you probably do not need to declare it globally but as a static. You can find an example of isNewBar() function that has static datetime lastBar=0; in the articles about new bar at mql5.com. This keyword in such a function says that the variable is not deleted after function is finished, but remains in memory and is used with the next call. And if you need a variable in OnTick() function - it does not make sence to have it static, declare it globally.
I am having a hard time getting to understand the non-standard C++ world that is qt. I have a class that can emit a 'login' signal, that I want to listen to from QML, this simply segfaults.
class Service : public QObject
Q_OBJECT
{
public:
Service()
{
// get the context, snipped for brevity
rootContext->setContextProperty("service", this);
}
public signals:
void login(bool succcess);
public slots:
void method();
};
I can successfully call 'service.method' from the QML, but if I add a Connections section to listen for the login event, I get a segfault whenever that component is displayed.
Page {
Component {
Column {
...
Connections {
target: service
onLogin: {
console.login("TEST");
}
}
}
}
}
I have tried moving the 'Connections' section out of the columns, but this results in a runtime-error and a white page, because it fails to parse the QML. What am I missing here?
I am using QT Creator 4.2.1 if that is in any way relevant.
Found the problem. Apparantly you cannot have a slot and a signal by the same name - even if they have wildly different function signatures. It doesn't give a compile error, it simply crashes.
After changing the name of the signal it magically started working.
Let's say we have some basic timer and a slot which is invoked periodically.
SomeObject::SomeObject()
{
QTimer *timer = new QTimer;
connect(timer , SIGNAL(timeout()), this, SLOT(updateState()));
}
void SomeObject::updateState()
{
// some operations leading to update of updatedValue
}
I also have function from same object which forces updates and returns some value.
bool SomeObject::getLatestState()
{
updateState();
return updatedValue;
}
This function may be directly called from different threads. This brings question of thread safety to mind. Simple mutex lock in getLatestState will not help as in some rare cases getLatestState is called from another thread that starts updateState. And at the same time timer's timeout may occur. Can you help me handle this situation properly?
QMutexLocker can be used in such situations
this my exampl
static QMutex mainMutex;
.....
MainController* MainController::s_instance = NULL;
.....
MainController* MainController::getInstance()
{
if(!s_instance){
QMutexLocker lock(&mainMutex);
if(!s_instance){
s_instance = new MainController;
}
}
return s_instance;
}
getInstance() function directly called from different threads.
(C++/Qt) I have a smart pointer to a QObject. Let's say a QWeakPointer. For some external reason (something that might happen in another object or due to an event), it is possible that the pointed object gets destroyed. Since I have a smart pointer there will be no dangling reference, so there's no problem. But I always have to check if the pointer is null or not.
I'm thinking of using the null pattern in order to avoid checking this all the time but I'm not sure if this is possible or convenient with a QObject. The idea would be that the pointer points to the object and in case it gets destroyed, the smart pointer changes its pointed object to a null object. Is this a good idea or should I forget it and just check if the pointer is NULL all the time?
Let's show you an example. We have a worker who uses a tool to do its work:
class Worker : public QObject
{
Q_OBJECT
public:
Worker(QObject *parent = 0);
void work()
{
if(m_tool)
m_tool->use();
emit workCompleted();
};
signals:
workCompleted();
public slots:
void setTool(QWeakPointer<Tool> tool);
private:
QWeakPointer<Tool> m_tool;
};
class Tool : public QObject
{
Q_OBJECT
public:
Tool();
public slots:
void use() =0;
};
class Screwdriver : public Tool
{
Q_OBJECT
public:
Screwdriver() : Tool();
public slots:
void use()
{
// do something
};
};
class Hammer : public Tool;
class Saw : public Tool;
...
In this case, the Tool is a public domain object of a library, which is used by the Worker. I'm developing such library. So the worker is using a screwdriver but it gets broken and gets destroyed. No problem:
if(m_tool)
m_tool->use();
emit workCompleted();
m_tool is 0 so it simply does nothing. But we have to check that it's not null everytime.
Now let's say we had a NullTool object:
class NullTool : public Tool
{
Q_OBJECT
public:
NullTool() : Tool();
public slots:
void use()
{
// does nothing
};
};
When the tool was destroyed, our pointer would be smart and would know it should point to a NullTool instance. So Worker::work() could be implemented like this:
void Worker::work()
{
m_tool->use();
emit workCompleted();
};
m_tool->use() would then get called on the NullTool which does nothing, so there would be no need to check the pointer is not null.
Is this a good idea? Is it possible with the smart pointer classes Qt provides or should I subclass QWeakPointer?
I think the null object pattern makes most sense for value-like classes. Examples are QString or QVariant, were you don't want to have code like if ( str && !str->isEmpty() ) but just do if ( !str.isEmpty() ). For QObjects, which are not values but have "an identity", I never found this useful.
I don't understand clearly your use case, but your program can be signaled when the object has been destroy by connecting the following signal from QObject:
void destroyed ( QObject * obj = 0 );
I don't see any problem in your idea. You just have to compare the work that it takes to implement it compared to the work for checking the pointer every time. Let's your checking the pointer 10.000 times it's a good idea to use your approach. Side note: Your null object pattern rely on the fact that Tool::use() has no side effects whatsoever.
Take care that possible side affects in Tool::use() don't get in the way when you replace it polymorphically with NullTool::use(). In other words: Be sure you don't break the Liskov Substitution Principle.
I'm writing an application using Qt4.
I need to download a very short text file from a given http address.
The file is short and is needed for my app to be able to continue, so I would like to make sure the download is blocking (or will timeout after a few seconds if the file in not found/not available).
I wanted to use QHttp::get(), but this is a non-blocking method.
I thought I could use a thread : my app would start it, and wait for it to finish. The thread would handle the download and quit when the file is downloaded or after a timeout.
But I cannot make it work :
class JSHttpGetterThread : public QThread
{
Q_OBJECT
public:
JSHttpGetterThread(QObject* pParent = NULL);
~JSHttpGetterThread();
virtual void run()
{
m_pHttp = new QHttp(this);
connect(m_pHttp, SIGNAL(requestFinished(int, bool)), this, SLOT(onRequestFinished(int, bool)));
m_pHttp->setHost("127.0.0.1");
m_pHttp->get("Foo.txt", &m_GetBuffer);
exec();
}
const QString& getDownloadedFileContent() const
{
return m_DownloadedFileContent;
}
private:
QHttp* m_pHttp;
QBuffer m_GetBuffer;
QString m_DownloadedFileContent;
private slots:
void onRequestFinished(int Id, bool Error)
{
m_DownloadedFileContent = "";
m_DownloadedFileContent.append(m_GetBuffer.buffer());
}
};
In the method creating the thread to initiate the download, here is what I'm doing :
JSHttpGetterThread* pGetter = new JSHttpGetterThread(this);
pGetter->start();
pGetter->wait();
But that doesn't work and my app keeps waiting. It looks lit the slot 'onRequestFinished' is never called.
Any idea ?
Is there a better way to do what I'm trying to do ?
Instead of using a thread you can just go into a loop which calls processEvents:
while (notFinished) {
qApp->processEvents(QEventLoop::WaitForMore | QEventLoop::ExcludeUserInput);
}
Where notFinished is a flag which can be set from the onRequestFinished slot.
The ExcludeUserInput will ensure that GUI related events are ignored while waiting.
A little late but:
Do not use these wait loops, the correct way is to use the done() signal from QHttp.
The requestFinished signal from what I have seen is just for when your application has finished the request, the data may still be on its way down.
You do not need a new thread, just setup the qhttp:
httpGetFile= new QHttp();
connect(httpGetFile, SIGNAL(done(bool)), this, SLOT(processHttpGetFile(bool)));
Also do not forget to flush the file in processHttpGetFile as it might not all be on the disk.
you have to call QThread::quit() or exit() if you are done - otherwise your thread will run forever...
I chose to implement David's solution, which seemed to be the easiest.
However, I had handle a few more things :
I had to adapt the QEventLoop enum values for Qt4.3.3 (the version I'm using);
I had to track the request Id, to make sure to exit the while loop when the download request is finished, and not when another request is finished;
I added a timeout, to make sure to exit the while loop if there is any problem.
Here is the result as (more or less) pseudo-code :
class BlockingDownloader : public QObject
{
Q_OBJECT
public:
BlockingDownloaderBlockingDownloader()
{
m_pHttp = new QHttp(this);
connect(m_pHttp, SIGNAL(requestFinished(int, bool)), this, SLOT(onRequestFinished(int, bool)));
}
~BlockingDownloader()
{
delete m_pHttp;
}
QString getFileContent()
{
m_pHttp->setHost("www.xxx.com");
m_DownloadId = m_pHttp->get("/myfile.txt", &m_GetBuffer);
QTimer::singleShot(m_TimeOutTime, this, SLOT(onTimeOut()));
while (!m_FileIsDownloaded)
{
qApp->processEvents(QEventLoop::WaitForMoreEvents | QEventLoop::ExcludeUserInputEvents);
}
return m_DownloadedFileContent;
}
private slots:
void BlockingDownloader::onRequestFinished(int Id, bool Error)
{
if (Id == m_DownloadId)
{
m_DownloadedFileContent = "";
m_DownloadedFileContent.append(m_GetBuffer.buffer());
m_FileIsDownloaded = true;
}
}
void BlockingDownloader::onTimeOut()
{
m_FileIsDownloaded = true;
}
private:
QHttp* m_pHttp;
bool m_FileIsDownloaded;
QBuffer m_GetBuffer;
QString m_DownloadedFileContent;
int m_DownloadId;
};
I used QNetworkAccsessManager for same necessity. Because this class managing connections RFC base (6 proccess same time) and non-blocking.
http://qt-project.org/doc/qt-4.8/qnetworkaccessmanager.html
How about giving the GUI some amount of time to wait on the thread and then give up.
Something like:
JSHttpGetterThread* pGetter = new JSHttpGetterThread(this);
pGetter->start();
pGetter->wait(10000); //give the thread 10 seconds to download
Or...
Why does the GUI thread have to wait for the "downloader thread" at all? When the app fires up create the downloader thread, connect the finished() signal to some other object, start the downloader thread, and return. When the thread has finished, it will signal the other object which can resume your process.