I'm looking for a way to check how long a button is pressed! My idea was starting a counter which starts when pressed() is emitted and stops when released() is emitted. But I currently don't know how to wait for the released- or similar events. Normally I would connect() a signal with a slot but in this case both are slots. Maybe you've got a better idea maybe this one is good enough.
When pressed. Start a timer. When released check for how long the timer has been running (and stop it). Save the elapsed time in a variable in the class.
That's one way to do it at least.
When the pressed signal is sent, start the timer. When the relesed signal is sent, read how much time has elapsed on the timer.
This is a complete example using Qt 5 and a C++ compiler that's not prehistoric:
// https://github.com/KubaO/stackoverflown/tree/master/questions/button-timer-38645219
#include <QtWidgets>
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QWidget w;
QFormLayout layout{&w};
QPushButton button{"Press Me"};
QLabel label;
layout.addRow(&button);
layout.addRow(&label);
QElapsedTimer timer;
QObject::connect(&button, &QPushButton::pressed, [&]{ timer.start(); });
QObject::connect(&button, &QPushButton::released, [&]{
label.setText(QStringLiteral("Pressed for %1 ms").arg(timer.elapsed()));
});
w.show();
return app.exec();
}
Of course you can shove all the variables into a class. You'll notice that C++11 makes this transformation almost a no-brainer: it's by design, not by coincidence.
#include <QtWidgets>
class Widget : public QWidget {
QFormLayout layout{this};
QPushButton button{"Press Me"};
QLabel label;
QElapsedTimer timer;
public:
Widget() {
layout.addRow(&button);
layout.addRow(&label);
connect(&button, &QPushButton::pressed, [&]{ timer.start(); });
connect(&button, &QPushButton::released, [&]{
label.setText(QStringLiteral("Pressed for %1 ms").arg(timer.elapsed()));
});
}
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
Widget w;
w.show();
return app.exec();
}
It is generally frowned upon to have "business logic" in UI objects, so we can separate out the functionality into that of a Timer, a Widget, and of a Controller. The code external to all of these objects sets up the requisite connections.
#include <QtWidgets>
class Timer : public QObject {
Q_OBJECT
QElapsedTimer timer;
public:
Q_SLOT void start() { timer.start(); }
Q_SLOT void stop() { emit elapsed(timer.elapsed()); }
Q_SIGNAL void elapsed(qint64);
};
class Widget : public QWidget {
Q_OBJECT
QFormLayout layout{this};
QPushButton button{"Press Me"};
QLabel label;
public:
Widget() {
layout.addRow(&button);
layout.addRow(&label);
connect(&button, &QPushButton::pressed, this, &Widget::pressed);
connect(&button, &QPushButton::released, this, &Widget::released);
}
Q_SIGNAL void pressed();
Q_SIGNAL void released();
Q_SLOT void setText(const QString & text) { label.setText(text); }
};
class Controller : public QObject {
Q_OBJECT
public:
Q_SLOT void elapsed(qint64 ms) {
emit hasText(QStringLiteral("Pressed for %1 ms").arg(ms));
}
Q_SIGNAL void hasText(const QString &);
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
Timer t;
Widget w;
Controller c;
w.show();
//
QObject::connect(&w, &Widget::pressed, &t, &Timer::start);
QObject::connect(&w, &Widget::released, &t, &Timer::stop);
QObject::connect(&t, &Timer::elapsed, &c, &Controller::elapsed);
QObject::connect(&c, &Controller::hasText, &w, &Widget::setText);
return app.exec();
}
#include "main.moc"
Of course you can scream that the controller, even if not really coupled to the other code, is still somewhat dependent on the design of the rest of the code. Thankfully, it doesn't have to be so: lambdas make simple adaptations simple.
We can use a "foreign" controller, provided by our big business vendor, too:
// use Timer and Widget from preceding example
#include <sstream>
#include <string>
#include <functional>
class Controller {
public:
using callback_t = std::function<void(const std::string&)>;
Controller(callback_t && callback) : callback{std::move(callback)} {}
void onElapsed(int ms) {
std::stringstream s;
s << "Pressed for " << ms << " ms";
callback(s.str());
}
private:
callback_t callback;
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
Timer t;
Widget w;
Controller c{ [&](const std::string & s){ w.setText(QString::fromStdString(s)); } };
QObject::connect(&w, &Widget::pressed, &t, &Timer::start);
QObject::connect(&w, &Widget::released, &t, &Timer::stop);
QObject::connect(&t, &Timer::elapsed, [&](qint64 ms) { c.onElapsed(ms); });
w.show();
return app.exec();
}
#include "main.moc"
All of the examples above are compileable: put any one of them into main.cpp, rebuild the project, and go.
When you're posting test cases for questions, you should go backwards: you start somewhere towards the end of this answer, and work your way towards the beginning, minimal setup. It'll help you understand your own code better, too, since the verbosity is minimized. It's telling, I hope, that both the first and the last version have same functionality.
Related
I have this very simple Qt code:
void thread_func()
{
int a1 = 1;
const char* a2[] = { "dummy_param" };
QApplication app(a1, (char**)a2);
QMessageBox msg(QMessageBox::NoIcon, "MyTitle", "Foo bar Foo bar", QMessageBox::Ok);
msg.exec();
}
If I call the above function from my main in a std::thread, it brings up the dialog:
int main()
{
std::thread t(thread_func);
t.join();
}
...but when I close it, I get the warning message:
QObject::~QObject: Timers cannot be stopped from another thread
I've checked that the thread affinity of both QApplication instance and msg is the same. Calling the thread_func function directly from my main() (without creating a std::thread) removes that message.
I am using Qt 5.15.1 on Windows 10.
What am I missing here? Thanks
It's not allowed to operate Qt GUI directly outside the main thread(GUI thead). You can emit signals.
The warning message says it all. Use a signal/slot mechanism to accomplish the same thing.
#include <QApplication>
#include <QMessageBox>
#include <QObject>
#include <QThread>
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(){}
public slots:
void displayMessageBox()
{
QMessageBox msg(QMessageBox::NoIcon, "MyTitle", "Foo bar Foo bar", QMessageBox::Ok);
msg.exec();
this->close();
}
};
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker() {}
void start() { emit askForMessageBox(); }
signals:
void askForMessageBox();
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget *widget;
Worker *worker;
QThread *thread(nullptr);
widget = new Widget();
worker = new Worker();
thread = new QThread(nullptr);
QObject::connect(worker, &Worker::askForMessageBox, widget, &Widget::displayMessageBox);
QObject::connect(thread, &QThread::started, worker, &Worker::start);
widget->show();
worker->moveToThread(thread);
thread->start();
return a.exec();
}
Two.h
#ifndef TWO_H
#define TWO_H
#include <QObject>
#include <QThread>
#include <QDebug>
#include <QTimer>
class Two : public QObject
{
Q_OBJECT
private:
QTimer abc;
public:
QString m_xyz;
Two();
signals:
void emitThisSignal( int x, QString &y );
public slots:
void mySlot();
};
class Controller : public QObject
{
Q_OBJECT
private:
Two objTwo;
QThread objQThread;
Controller();
public slots:
void mySlot( int x, QString &y)
{
qDebug() << "\nWWWWWWWWWWWWW: " << y;
}
};
#endif // TWO_H
Two.cpp
#include "two.h"
Two::Two()
{
m_xyz = "aksja";
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &Two::mySlot);
timer->start(1000);
}
void Two::mySlot()
{
emit emitThisSignal(4, m_xyz);
qDebug()<< "FFFFFFFFFFF " << m_xyz;
}
Controller::Controller()
{
objTwo.moveToThread( &objQThread );
connect( &objTwo, &Two::emitThisSignal, this, &Controller::mySlot );
connect( &objQThread, &QThread::finished, &objQThread, &QThread::deleteLater );
objQThread.start();
}
Controller::~Controller()
{
delete objTwo;
objQThread.wait();
}
I can see that the signal is being emitted because of the print statement but the slot of the Controller class is not getting called.
void Two::mySlot()
{
emit emitThisSignal(4, m_xyz);
qDebug()<< "FFFFFFFFFFF " << m_xyz;
}
Why is that so?
int main( int argc, char* argv[])
{
QCoreApplication app(argc, argv);
Controller o;
return app.exec();
}
See documentation of QObject::connect, note last argument with default value: Qt::AutoConnection.
Its documentation says:
(Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
Now you are fall in into Qt::QueuedConnection scenario:
The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
So basically you need something which will provide an event loop.
In this code you need that:
int main( int argc, char* argv[])
{
QCoreApplication app{argc, argv};
Controller o;
// note you need something what will stop this event loop to terminate application
return app.exec();
}
One more thing.
Now I noticed that your signals and slot argument is quite unusual. Problem might be second argument which type is QString&.
It might be source of problems I do not know if Qt is able to marshal non const references. If you will add const then it will be able to marshal QString and should work (if I didn't missed other pitfall).
I want to update UI from the second thread, I have created slots which are going to be called from other thread by signaling, but somehow it is not being called from the other thread. Below is the code:
WorkerThread.h
class WorkerThread: public QObject
{
Q_OBJECT
public:
WorkerThread();
~WorkerThread();
public slots:
void onStart();
signals:
void sendMessage(const QString& msg, const int& code);
};
WorkerThread.cpp
#include "workerwhread.h"
WorkerThread::WorkerThread(){}
void WorkerThread::onStart(){
emit sendMessage("start", 100);
}
Usage:
MyWidget.h
namespace Ui {
class MyWidget;
}
class MyWidget: public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0);
~MyWidget();
private slots:
void onGetMessage(const QString &msg, const int& code);
private:
Ui::MyWidget *ui;
QThread *thread = nullptr;
WorkerThread *wt = nullptr;
};
MyWidget.cpp
MyWidget::MyWidget(QWidget *parent) : QWidget(parent), ui(new Ui::MyWidget)
{
ui->setupUi(this);
wt = new WorkerThread;
thread = new QThread;
connect(thread, &QThread::finished, wt, &QObject::deleteLater);
connect(ui->btStart, &QPushButton::clicked, wt, &WorkerThread::onStart);
connect(wt, &WorkerThread::sendMessage, this, &MyWidget::onGetMessage);
wt->moveToThread(thread);
thread->start();
}
void MyWidget::onGetMessage(const QString &msg, const int& code)
{
qDebug() << "message" << msg; // this never being called ????
}
Note: When I pass the connection type Qt::DirectConnectoin, then it is working, but the problem is it is not the GUI thread.
connect(wt, &WorkerThread::sendMessage, this, &MyWidget::onGetMessage, Qt::DirectConnection);
Main
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
w.setWindowIcon(QIcon(":/icons/system.png"));
return a.exec();
}
After a lot of trying and checking the code line by line, I finally found the problem. The reason was with overriding the event() function of QWidget, the return value of event() function is bool, so if you return a true it is OK and working well without throwing any runtime or compile-time error. But it will prevent signal-slot events to happen.
So NOT return true, but return QWidget::event(event); then it will slove the problem.
I'm brand new to c++ and QML, and am struggling to call and run a threaded loop. I'd like to add an integer to a QML propery value every x milliseconds.
I'll omit my main.qml code for now, as I'm able to access the desired property; this question pertains more to c++.
void fn(QQuickItem x)
{
for (;;)
{
std::this_thread::sleep_for(std::chrono.milliseconds(100));
x->setProperty("value", x->property("value").toReal() + 10);
}
}
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
//QScopedPointer<TachometerDemo> Tacho(new TachometerDemo);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
QQuickItem *item = engine.rootObjects().at(0)->findChild<QQuickItem*>
("circularGauge");
thread t1(fn, item);
return app.exec();
}
Any guidance on the most efficient means for achieving the above desired functionality would be appreciated. Whilst I'm currently testing on a win32 platform, a cross-platform approach is required.
Better use Qt's event loop mechanism and SIGNAL/SLOTS. And QThreads if needed. Also if you need to update value in QML in msecconds duration don't do it over setProperty, this function call takes too long. You can update your value directly in QML using JS. But if you need to update QML value from C++ you can do it this way:
test.h
#include <QObject>
#include <QTimer>
class Test : public QObject
{
Q_OBJECT
public:
Test();
Q_PROPERTY(int value READ value NOTIFY valueChanged)
int value(){return this->m_value;}
signals:
void valueChanged();
private slots:
void timeout();
private:
int m_value;
QTimer * m_timer;
};
test.cpp
#include "test.h"
Test::Test():m_value(0)
{
this->m_timer = new QTimer(this);
this->m_timer->setInterval(100);
connect(this->m_timer, &QTimer::timeout, this, &Test::timeout);
this->m_timer->start();
}
void Test::timeout()
{
this->m_value += 10;
emit valueChanged();
}
in your main.cpp
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty(QStringLiteral("Test"), new Test());
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
Somewhere in your QML:
Label
{
text: Test.value
anchors.centerIn: parent
}
This is the fastest way to update QML value from C++
I am writing to ask for advice on how best to implement my code using QT library. I have a class called Action class that every one second retrieve the PC time (with gettimeofday), this value shall be displayed in the GUI. So I have a class widget that defines all the widgets necessary for the GUI. The value (expressed in seconds) will be displayed with a QLineEdit.
So my question is, how I have to implement Signal and slot to update the value in QLineEdit?
Should I emit a signal every time the function retreiveTimetoSend is called?
action.h
class Action: public object
{
Q_OBJECT
private:
Qtimer timer;
unisgned int timetosend;
private:
void retreiveTimetoSend();
public:
Action();
~Action();
public slots:
void doWork();
}
action.cpp
void retreiveTimetoSend()
{
struct timeval Now;
unsigned int Sec;
gettimeofday(&Now, NULL);
Sec = Now.tv_sec;
time.value =Sec;
}
void Action::Action()
{
timer.setInterval(1000);
connect(&timer, SIGNAL(timeout()), this, SLOT (doWork()));
timer.start();
}
void Action::doWork()
{
retreiveTimetoSend()
}
widget.h
class widgets: public QWidget
{
Q_OBJECT
private:
QLineEdit *displayTime;
public:
widget(action *w_test);
}
widget.cpp
widgets::widgets(action *w_test)
{
displayTime= new QLineEdit();
displayTime->setText(QString::number(w_test->timetosend,10));
displayTC->setStyleSheet("color: blue; background-color: red");
}
main.cpp
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Action *test = new Action;
Thread *threadtest = new QThread;
test->moveToThread(threadtest);
QObject::connect(threadtest, SIGNAL(started()), test ,SLOT(doWork()));
widget *mainwindows = new widget(test);
mywindow->show();
threadtest->start();
return app.exec();
}
Instead using gettimeofday use QTime::currentTime then convert it to string (chose the format) and emit result. This signal should be connected to slot QLineEdit::setText.
Using thread is completely obsolete here.