I want to launch a SCPI command in my device using netcat utility under Ubuntu 10.04 LTS with Qt. My code looks like:
env = "echo TRIG | nc 192.168.1.100 23 -q1";
process1.execute(env);
process1.waitForFinished(1000);
This command does not return any data but simply triggers the data acquisition.
If using terminal with same "echo TRIG | nc 192.168.1.100 23 -q1" command, everything works fine.
From Qt, it does not work. The debug output is "TRIG | nc 10.0.3.250 23 -q1" ... so without an "echo". My device does not receive the TRIG command.
Could you please advise what I'm doing wrong?
Many thanks.
The code below shows a fairly complete, asynchronous implementation of this functionality. It demonstrates how it can be done without launching external processes, and how to leverage C++11 lambdas in Qt 5. For Qt 4, the slots from main() would need to live in their own QObject-derived class.
#include <QtWidgets>
#include <QtNetwork>
class SocketSignaler : public QObject
{
Q_OBJECT
Q_SLOT void stateChanged(QAbstractSocket::SocketState state) {
if (state == QAbstractSocket::UnconnectedState) emit unconnected();
else emit busy();
emit hasState(this->state());
}
public:
explicit SocketSignaler(QAbstractSocket * socket) : QObject(socket) {
connect(socket, &QAbstractSocket::stateChanged, this, &SocketSignaler::stateChanged);
connect(&(const QObject&)QObject(), &QObject::destroyed, this, // defer signal emission
[=]{ emit stateChanged(socket->state()); }, Qt::QueuedConnection);
}
Q_SIGNAL void busy();
Q_SIGNAL void unconnected();
Q_SIGNAL void hasState(const QString &);
QString state() const {
switch (static_cast<QAbstractSocket*>(parent())->state()) {
case QAbstractSocket::UnconnectedState: return "Disconnected";
case QAbstractSocket::HostLookupState: return "Looking up host";
case QAbstractSocket::ConnectingState: return "Connecting";
case QAbstractSocket::ConnectedState: return "Connected";
case QAbstractSocket::ClosingState: return "Closing";
default: return {};
}
}
};
class Ui : public QWidget {
Q_OBJECT
Q_PROPERTY(bool busy WRITE setBusy)
QVBoxLayout m_layout{this};
QFormLayout m_form;
QLineEdit m_target{"192.168.1.100"};
QLineEdit m_message{"TRIG"};
QLabel m_state;
QDialogButtonBox m_box;
QPushButton * const m_send = m_box.addButton("Send", QDialogButtonBox::AcceptRole);
QPushButton * const m_cancel = m_box.addButton(QDialogButtonBox::Cancel);
QMessageBox m_msgBox{this};
public:
Ui() {
m_form.addRow("Target Host", &m_target);
m_form.addRow("Command", &m_message);
m_layout.addLayout(&m_form);
m_layout.addWidget(&m_state);
m_layout.addWidget(&m_box);
m_msgBox.setIcon(QMessageBox::Critical);
connect(m_send, &QPushButton::clicked, this, &Ui::send);
connect(m_cancel, &QPushButton::clicked, this, &Ui::cancel);
}
void setState(const QString & text) { m_state.setText(text); }
QString target() const { return m_target.text(); }
QString message() const { return m_message.text(); }
void showError(const QString & text) {
m_msgBox.setText(text);
m_msgBox.show();
}
void setBusy(bool busy) {
m_send->setEnabled(!busy);
m_cancel->setEnabled(busy);
}
Q_SIGNAL void send();
Q_SIGNAL void cancel();
};
int main(int argc, char *argv[])
{
const int targetPort = 23;
QApplication app{argc, argv};
Ui ui;
ui.show();
QTcpSocket socket;
SocketSignaler socketSig{&socket};
QObject::connect(&socketSig, &SocketSignaler::hasState, &ui, &Ui::setState);
QStateMachine machine;
QState sReady{&machine};
QState sBusy{&machine};
sReady.assignProperty(&ui, "busy", false);
sBusy.assignProperty(&ui, "busy", true);
sReady.addTransition(&socketSig, &SocketSignaler::busy, &sBusy);
sBusy.addTransition(&socketSig, &SocketSignaler::unconnected, &sReady);
QObject::connect(&ui, &Ui::send, [&](){
socket.connectToHost(ui.target(), targetPort);
});
QObject::connect(&ui, &Ui::cancel, [&](){ socket.abort(); });
QObject::connect(&socket,
static_cast<void (QAbstractSocket::*)(QAbstractSocket::SocketError)>
(&QAbstractSocket::error), [&]()
{
ui.showError(socket.errorString());
});
QObject::connect(&socket, &QAbstractSocket::connected, [&](){
auto msg = ui.message().toLatin1();
msg.append('\n');
if (socket.write(msg) >= msg.size()) socket.close();
});
QObject::connect(&socket, &QAbstractSocket::bytesWritten, [&](){
if (!socket.bytesToWrite()) socket.close();
});
machine.setInitialState(&sReady);
machine.start();
return app.exec();
}
#include "main.moc"
You can't use the pipe command (|) with QProcess that way.
There are a few ways to tackle this: -
You can call the first command and retrieve its output before processing it either in Qt or with another call to QProcess.
Or, create a script that you call from QProcess and retrieve the output.
Finally, assuming you're using linux / OSX, you can call QProcess with /bin/bash and pass the command to that. For example: -
env = "/bin/bash \"echo TRIG | nc 192.168.1.100 23 -q1\"";
process1.execute(env);
You can probably find an equivalent to /bin/bash for windows, perhaps cmd.exe
Related
When I try to downloading file up to 50mb example, no problem, but with a big files give the following error
void MainWindow::downloadFile() {
QNetworkRequest requests;
requests.setUrl(QUrl("https://urlToFile"));
QSslConfiguration configSsl = QSslConfiguration::defaultConfiguration();
configSsl.setProtocol(QSsl::AnyProtocol);
requests.setSslConfiguration(configSsl);
QNetworkAccessManager *manager5 = new QNetworkAccessManager(this);
QNetworkReply *reply5;
reply5 = manager5->get( requests );
connect(manager5, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadFinished(QNetworkReply*)));
}
void MainWindow::downloadFinished(QNetworkReply *data) {
QFile localFile("fileName");
if (!localFile.open(QIODevice::WriteOnly))
return;
localFile.write(data->readAll());
localFile.close();
}
In your code, You are holding the whole file in memory until the download process finishes (that is when QNetworkAccessManager::finished() signal gets emitted). Of course, this is not the best way to deal with large files.
Remember that QNetworkReply is a QIODevice. This means that you should use the readyRead() signal to save data chunks to the disk as soon as they are received from the network, in order to avoid holding the whole file in memory until the download is finished.
Here is a minimal complete example:
#include <QtNetwork>
int main(int argc, char* argv[]){
QCoreApplication a(argc, argv);
QNetworkAccessManager nam;
QFile file("downloadedFile.xxx");
if(!file.open(QIODevice::ReadWrite)) return 1;
QNetworkRequest request(QUrl("http://download_url/..."));
QNetworkReply* reply = nam.get(request);
QObject::connect(reply, &QNetworkReply::readyRead, [&]{
//this will be called every time a chunk of data is received
QByteArray data= reply->readAll();
qDebug() << "received data of size: " << data.size();
file.write(data);
});
//use the finished signal from the reply object to close the file
//and delete the reply object
QObject::connect(reply, &QNetworkReply::finished, [&]{
qDebug() << "finished downloading";
QByteArray data= reply->readAll();
file.write(data);
file.close();
reply->deleteLater();
a.quit();
});
return a.exec();
}
Update:
I have wrapped the whole thing in a class FileDownloader, which can be used to download a file using QNetworkAccessManager, Here is an example of using this class:
#include <QtWidgets>
#include <QtNetwork>
//downloads one file at a time, using a supplied QNetworkAccessManager object
class FileDownloader : public QObject{
Q_OBJECT
public:
explicit FileDownloader(QNetworkAccessManager* nam, QObject* parent= nullptr)
:QObject(parent),nam(nam)
{
}
~FileDownloader(){
//destructor cancels the ongoing dowload (if any)
if(networkReply){
a_abortDownload();
}
}
//call this function to start downloading a file from url to fileName
void startDownload(QUrl url, QString fileName){
if(networkReply) return;
destinationFile.setFileName(fileName);
if(!destinationFile.open(QIODevice::WriteOnly)) return;
emit goingBusy();
QNetworkRequest request(url);
networkReply= nam->get(request);
connect(networkReply, &QIODevice::readyRead, this, &FileDownloader::readData);
connect(networkReply, &QNetworkReply::downloadProgress,
this, &FileDownloader::downloadProgress);
connect(networkReply, &QNetworkReply::finished,
this, &FileDownloader::finishDownload);
}
//call this function to abort the ongoing download (if any)
void abortDownload(){
if(!networkReply) return;
a_abortDownload();
emit backReady();
}
//connect to the following signals to get information about the ongoing download
Q_SIGNAL void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
Q_SIGNAL void downloadSuccessful();
Q_SIGNAL void downloadError(QString errorString);
//the next two signals are used to indicate transitions between busy and
//ready states of the file downloader, they can be used to update the GUI
Q_SIGNAL void goingBusy();
Q_SIGNAL void backReady();
private:
Q_SLOT void readData(){
QByteArray data= networkReply->readAll();
destinationFile.write(data);
}
Q_SLOT void finishDownload(){
if(networkReply->error() != QNetworkReply::NoError){
//failed download
a_abortDownload();
emit downloadError(networkReply->errorString());
} else {
//successful download
QByteArray data= networkReply->readAll();
destinationFile.write(data);
destinationFile.close();
networkReply->deleteLater();
emit downloadSuccessful();
}
emit backReady();
}
//private function, cleans things up when the download is aborted
//(due to an error or user interaction)
void a_abortDownload(){
networkReply->abort();
networkReply->deleteLater();
destinationFile.close();
destinationFile.remove();
}
QNetworkAccessManager* nam;
QUrl downloadUrl;
QFile destinationFile;
QPointer<QNetworkReply> networkReply;
};
//A sample GUI application that uses the above class
class Widget : public QWidget{
Q_OBJECT
public:
explicit Widget(QWidget* parent= nullptr):QWidget(parent){
layout.addWidget(&lineEditUrl, 0, 0);
layout.addWidget(&buttonDownload, 0, 1);
layout.addWidget(&progressBar, 1, 0);
layout.addWidget(&buttonAbort, 1, 1);
layout.addWidget(&labelStatus, 2, 0, 1, 2);
lineEditUrl.setPlaceholderText("URL to download");
connect(&fileDownloader, &FileDownloader::downloadSuccessful,
this, &Widget::downloadFinished);
connect(&fileDownloader, &FileDownloader::downloadError,
this, &Widget::error);
connect(&fileDownloader, &FileDownloader::downloadProgress,
this, &Widget::updateProgress);
connect(&buttonDownload, &QPushButton::clicked,
this, &Widget::startDownload);
connect(&buttonAbort, &QPushButton::clicked,
this, &Widget::abortDownload);
showReady();
//use goingBusy() and backReady() from FileDownloader signals to update the GUI
connect(&fileDownloader, &FileDownloader::goingBusy, this, &Widget::showBusy);
connect(&fileDownloader, &FileDownloader::backReady, this, &Widget::showReady);
}
~Widget() = default;
Q_SLOT void startDownload(){
if(lineEditUrl.text().isEmpty()){
QMessageBox::critical(this, "Error", "Enter file Url", QMessageBox::Ok);
return;
}
QString fileName =
QFileDialog::getSaveFileName(this, "Destination File");
if(fileName.isEmpty()) return;
QUrl url= lineEditUrl.text();
fileDownloader.startDownload(url, fileName);
}
Q_SLOT void abortDownload(){
fileDownloader.abortDownload();
}
Q_SLOT void downloadFinished(){
labelStatus.setText("Download finished successfully");
}
Q_SLOT void error(QString errorString){
labelStatus.setText(errorString);
}
Q_SLOT void updateProgress(qint64 bytesReceived, qint64 bytesTotal){
progressBar.setRange(0, bytesTotal);
progressBar.setValue(bytesReceived);
}
private:
Q_SLOT void showBusy(){
buttonDownload.setEnabled(false);
lineEditUrl.setEnabled(false);
buttonAbort.setEnabled(true);
labelStatus.setText("Downloading. . .");
}
Q_SLOT void showReady(){
buttonDownload.setEnabled(true);
lineEditUrl.setEnabled(true);
buttonAbort.setEnabled(false);
progressBar.setRange(0,1);
progressBar.setValue(0);
}
QGridLayout layout{this};
QLineEdit lineEditUrl;
QPushButton buttonDownload{"Start Download"};
QProgressBar progressBar;
QPushButton buttonAbort{"Abort Download"};
QLabel labelStatus{"Idle"};
QNetworkAccessManager nam;
FileDownloader fileDownloader{&nam};
};
int main(int argc, char* argv[]){
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#include "main.moc"
I'm trying to create a test that will use a QNetworkAccessManager to talk with our RESTful api. All I want to do is grab a simple JSon object using a QNetworkAccessManager. My code looks like this:
Connection::Connection(QString const &username, QString const &password, QString const &url, QString const &api) :
_user(username), _pass(password), _url(url) {
_manager = new QNetworkAccessManager(this);
QObject::connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveReply(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(QUrl(_url.append(api)));
request.setRawHeader("Authorization", QString("Basic ").append(QString("%1:%2").arg(_user).arg(_pass)).toUtf8());
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
QNetworkReply *reply = _manager->get(request);
}
void Connection::Connection(QNetworkReply *reply) {
//do some validation of the reply...
_data = QJsonDocument::fromJson(reply->readAll());
}
QJsonDocument Connection::data() const {
return _data;
}
...
#include <gtest/gtest.h>
#include "Connection.h"
#include <QApplication>
TEST(ConnectionTest, creation) {
int argc = 0;
char *argv = 0;
QApplication a(argc, &argv);
Connection *connect = new Connection("user","abc123", https://mytest.com/", "api/");
connect->deleteLater();
while (connect->data().isEmpty()) {
//loop forever
}
}
Originally I was testing by having Connection also be a QWidget. The finished signal would only show if I called connection->show(); Then I have to close the widget manually and the test completes. However, this isn't really useful for automated unit testing.
If I use the above while loop to wait until _data has been set to something then nothing ever happens with the QNetworkAccessManager and it loops forever.
Is there some call that needs to happen before anything will move forward? Why was ->show() 'working?'
You're not spinning the event loop, so don't expect anything asynchronous to work at all.
You need to add a signal to the Connection class that indicates when it's done, and use that signal to quit the event loop:
TEST(ConnectionTest, creation) {
int argc = 0;
char *argv = 0;
QCoreApplication app(argc, &argv);
// No need to allocate the connection on the heap!
Connection connection("user", "abc123", "https://mytest.com/", "api/");
QObject::connect(&connection, &Connection::finished,
&app, &QCoreApplication::quit());
app.exec();
}
You could add the QApplication instance as a member of the ConnectionTest class.
There's also no need to double the number of heap allocations by having the QNetworkAccessManager * manager member. You can have it as a regular member:
class Connection : public QObject {
Q_OBJECT
QNetworkAccessManager manager;
Q_SLOT void receiveReply(QNetworkReply *) {
...
emit finished();
}
public:
explicit
Connection(const QString & user, const QString & password,
const QUrl & url, const QString & path,
QObject * parent = 0) : QObject(parent) { ... }
Q_SIGNAL void finished();
};
I'm a bit confused about how to test a QStateMachine.
I have a project well organized with source code in one side and test code on the other side.
header
class Foo
{
signals:
void sigGoToStateOne();
void sigGoToStateTwo();
void sigGoToStateThree();
private:
QStateMachine *stateMachine;
QState *state1;
QState *state2;
void initStateMachine();
}
And in the source file
Foo::initStateMachine()
{
// constructors
state1->addTransition(this,SIGNAL(sigGoToStateTwo()),this->state2);
state2->addTransition(this,SIGNAL(sigGoToStateOne()),this->state1);
}
I would like to know if there is a beautiful way to test if my stateMachine is right. In other words, how my state machine reacts if I emit sigGoToStateThree() if I'm there, etc..
Solutions i see:
1 - Get the address of stateMachine (and eventually all other states) and test it (But i don't know how)
2 - Simulate signals (sigGoToStateX()) from a test file (Again, don't know if it's possible to emit signals of my class Foo in an other class)
My unique demand is I don't want to modify the core of my source file.
Thank's in advance.
In Qt 5, signals are always public methods. To make your code compatible with Qt 4, you can make the signals explicitly public like so:
class Foo {
public:
Q_SIGNAL void sigGoToStateOne();
...
}
Alternatively, you can keep arbitrary signal visibility, and declare a friend test class:
class Foo {
friend class FooTest;
...
}
Finally, you can create a test project where you use the Qt's test framework to test the Foo class's behavior. The code below works in both Qt 4 and Qt 5.
// main.cpp
#include <QCoreApplication>
#include <QStateMachine>
#include <QEventLoop>
#include <QtTest>
#include <QTimer>
class Waiter {
QTimer m_timer;
public:
Waiter() {}
Waiter(QObject * obj, const char * signal) {
m_timer.connect(obj, signal, SIGNAL(timeout()));
}
void stop() {
m_timer.stop();
QMetaObject::invokeMethod(&m_timer, "timeout");
}
void wait(int timeout = 5000) {
QEventLoop loop;
m_timer.start(timeout);
loop.connect(&m_timer, SIGNAL(timeout()), SLOT(quit()));
loop.exec();
}
};
class SignalWaiter : public QObject, public Waiter {
Q_OBJECT
int m_count;
Q_SLOT void triggered() {
++ m_count;
stop();
}
public:
SignalWaiter(QObject * obj, const char * signal) : m_count(0) {
connect(obj, signal, SLOT(triggered()), Qt::QueuedConnection);
}
int count() const { return m_count; }
};
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
typedef QSignalSpy SignalSpy;
#else
class SignalSpy : public QSignalSpy, public Waiter {
public:
SignalSpy(QObject * obj, const char * signal) :
QSignalSpy(obj, signal), Waiter(obj, signal) {}
};
#endif
class Foo : public QObject {
Q_OBJECT
friend class FooTest;
QStateMachine m_stateMachine;
QState m_state1;
QState m_state2;
Q_SIGNAL void sigGoToStateOne();
Q_SIGNAL void sigGoToStateTwo();
public:
explicit Foo(QObject * parent = 0) :
QObject(parent),
m_state1(&m_stateMachine),
m_state2(&m_stateMachine)
{
m_stateMachine.setInitialState(&m_state1);
m_state1.addTransition(this, SIGNAL(sigGoToStateTwo()), &m_state2);
m_state2.addTransition(this, SIGNAL(sigGoToStateOne()), &m_state1);
}
Q_SLOT void start() {
m_stateMachine.start();
}
};
class FooTest : public QObject {
Q_OBJECT
void call(QObject * obj, const char * method) {
QMetaObject::invokeMethod(obj, method, Qt::QueuedConnection);
}
Q_SLOT void test1() {
// Uses QSignalSpy
Foo foo;
SignalSpy state1(&foo.m_state1, SIGNAL(entered()));
SignalSpy state2(&foo.m_state2, SIGNAL(entered()));
call(&foo, "start");
state1.wait();
QCOMPARE(state1.count(), 1);
call(&foo, "sigGoToStateTwo");
state2.wait();
QCOMPARE(state2.count(), 1);
call(&foo, "sigGoToStateOne");
state1.wait();
QCOMPARE(state1.count(), 2);
}
Q_SLOT void test2() {
// Uses SignalWaiter
Foo foo;
SignalWaiter state1(&foo.m_state1, SIGNAL(entered()));
SignalWaiter state2(&foo.m_state2, SIGNAL(entered()));
foo.start();
state1.wait();
QCOMPARE(state1.count(), 1);
emit foo.sigGoToStateTwo();
state2.wait();
QCOMPARE(state2.count(), 1);
emit foo.sigGoToStateOne();
state1.wait();
QCOMPARE(state1.count(), 2);
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
FooTest test;
QTest::qExec(&test, a.arguments());
QMetaObject::invokeMethod(&a, "quit", Qt::QueuedConnection);
return a.exec();
}
#include "main.moc"
I am forcing all signal invocations to be done from the event loop, so that the event transitions will only happen while the event loop is running. This makes the test code uniformly wait after each transition. Otherwise, the second wait would time out:
Q_SLOT void test1() {
SignalSpy state1(&m_foo.m_state1, SIGNAL(entered()));
SignalSpy state2(&m_foo.m_state2, SIGNAL(entered()));
m_foo.start();
state1.wait();
QCOMPARE(state1.count(), 1);
emit m_foo.sigGoToStateTwo(); // The state2.entered() signal is emitted here.
state2.wait(); // But we wait for it here, and this wait will time out.
QCOMPARE(state2.count(), 1); // But of course the count will match.
emit m_foo.sigGoToStateOne();
state1.wait(); // This would timeout as well.
QCOMPARE(state1.count(), 2);
}
This can be worked around without the use of explicit queued calls by the use of a signal spy class that internally uses a queued connection.
Kuba Ober gives a very good analysis of how to use the test framework & SignalSpy to do in depth testing of your state machine.
If all you're trying to do is generate a sigGoToStateX() from a test file then don't forget that you can chain signals together.
So for example given a class "Tester":
class Tester : public QObject {
Q_OBJECT
public:
Tester(Foo *fooClass) {
//Connecting signals gives you the kind of behaviour you were asking about
connect(this, SIGNAL(testTransitionToState1()), fooClass, SIGNAL(sigGoToState1()));
connect(this, SIGNAL(testTransitionToState2()), fooClass, SIGNAL(sigGoToState2()));
connect(this, SIGNAL(testTransitionToState3()), fooClass, SIGNAL(sigGoToState3()));
}
void SwitchState(int newState) {
//Now any time we emit the test signals, the foo class's signals will be emitted too!
if (newState == 1) emit testTransitionToState1();
else if (newState == 2) emit testTransitionToState1();
else if (newState == 3) emit testTransitionToState1();
}
signals:
void testTransitionToState1();
void testTransitionToState2();
void testTransitionToState3();
}
So for example calling SwitchState(1) will invoke the correct signals for switching to state 1. If this simple case is all you need for testing then that's all you really need.
If you need something more complex, go with the full SignalSpy example.
I would like to program a Qt programe with libcurl.
Header like this:
class WorkThread : public QThread
{
Q_OBJECT
public:
//...
void work(QString url_);
static size_t callback_get_head(void *ptr, size_t size, size_t nmemb, void *userp);
protected:
void run();
private:
QString url;
};
Source code:
//....
void WorkThread::work(QString url_)
{
url=url_;
start();
}
void WorkThread::run()
{
CURL *curl;
CURLcode res;
char buffer[512];
curl = curl_easy_init();
if(curl) {
char *liburl=url.toLatin1().data();
curl_easy_setopt(curl, CURLOPT_URL, liburl);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WorkThread::callback_get_head);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
printf("curl_easy_perform() failed: %s\n",curl_easy_strerror(res));
curl_easy_cleanup(curl);
printf("%s \n",buffer);
}
}
size_t WorkThread::callback_get_head(void *ptr, size_t size, size_t nmemb, void *userp)
{
strcat( (char*)(userp), (char*)(ptr));
return size * nmemb;
}
In main :
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
WorkThread thread1;
WorkThread thread2;
WorkThread thread3;
thread1.work("http://hq.sinajs.cn/list=sh601006");
thread2.work("http://hq.sinajs.cn/list=sh601006");
thread3.work("http://hq.sinajs.cn/list=sh601006");
return a.exec();
}
When I compile and run , I find it that the results is different each time. What is wrong?It said "name resolve failed".But it seems that name resolve successed in thread1 and thread2.
The problem is that you're not using QThread properly. Unless you're going to change how Qt handles threads, you shouldn't be inheriting from it; You're doing it Wrong!
Your main object has the thread affinity of the main thread, though your Curl object's thread affinity is the new thread.
Separate the Curl code into a separate class, inherited from QObject and then move that to the new thread. This should solve the problems you're seeing.
This article explains how to use QThread properly.
I've "Core" object that handles QMainWindow.
Core.h code
class Core : public QObject
{
Q_OBJECT
public:
explicit Core(QObject *parent = 0);
~Core();
void appInit();
int getAuth();
public slots:
void appExit();
private slots:
void appMenuTriggered(QAction *action);
private:
void preInit();
MainWindow *mwnd;
};
Core.cpp code
Core::Core(QObject *parent) : QObject(parent)
{
qDebug() << "Core::Constructor called";
preInit();
}
Core::~Core()
{
delete mwnd;
qDebug() << "Core::Destructor called";
}
int Core::getAuth()
{
LoginDialog *login = new LoginDialog();
int r = login->exec();
delete login;
return r;
}
void Core::appExit() // connected to qapplication aboutToQuit
{
qDebug() << "Core::appExit called";
}
void Core::preInit() // called after getAuth im main.cpp
{
qDebug() << "Core::preInit called";
}
void Core::appMenuTriggered( QAction *action )
{
qDebug() << "action triggered";
}
void Core::appInit()
{
mwnd = new MainWindow();
mwnd->show();
qDebug() << "Core::appInit called";
}
I'm trying to connect mainwindow menubar signal to core slot like this:
connect(mwnd->menuBar(), SIGNAL(triggered()), this, SLOT(appMenuTriggered()));
But it doesn't work. Im new to c++ and Qt. How to connect this?
Or maybe there is better way to handle mainwindow actions to other programm parts.
UPD
Problem solved. Forget to include QMenuBar
You have to give the full function spec in the SIGNAL and SLOT parameters (but without the argument names). Like this:
connect(mwnd->menuBar(),
SIGNAL(triggered(QAction*)),
this,
SLOT(appMenuTriggered(QAction*)));
If you debug such code in Qt Creator, the connect function will write diagnostic error messages to the Application Output pane when it doesn't find a signal or a slot. I suggest that you find these error messages before you fix your problem, so that you know where to look in future. It's very easy to get signals and slots wrong!