Qt SIGNAL-SIGNAL connection the new Way - qt

I use the old connection syntax until now. Today I want to change my project to new connection syntax like this:
#include <QDebug>
class Telefon : public QObject {
Q_OBJECT
public:
void letRing() {
qDebug() << "letRing";
emit ring();
}
signals:
void ring();
public slots:
void onRing() {
qDebug() << "onRing";
}
};
class Cable : public QObject {
Q_OBJECT
signals:
void ring();
};
int main(int argc, char *argv[])
{
Telefon *fon1 = new Telefon();
Telefon *fon2 = new Telefon();
Cable *cable = new Cable();
// old connection way
// connect(fon1, SIGNAL(ring()), cable, SIGNAL(ring()));
// connect(cable, SIGNAL(ring()), fon2, SLOT(onRing()));
// new connection way
QObject::connect(fon1, &Telefon::ring, cable, &Cable::ring); // <-- This is the problem
QObject::connect(cable, &Cable::ring, fon2, &Telefon::onRing);
fon1->letRing();
return 0;
}
The compiling went well with no errors. But the telefon never rings :(
Output should be:
letRing
onRing
But it is:
letRing
I Dig into the Qt code and found that SIGNAL-SLOT connections where valid but SIGNAL-SIGNAL connections don't work this way. Beside it generate no error while compiling. Is there a way to connect SIGNALs the new way/syntax?

Related

qt asynchron clients response gsoap

i am writing client server application using gsoap lib. the problem is that a have a heavy process function in my server.i want to when special client call this function, the server send message for this special client that "your answer is ready" when this client answer is ready. and its possible that multiple client call this function in same time.
is there any tool like asynchronAnswer in qt? and if not how can i handle it with qt or gsoap tools?
whats the true architect of handle this problems? using multi thread in client calling and wait for response in other thread or exactly call client by its ip in server or something better?
thanks,
You can try to use QWebSocket for this task. You have connected client list, if client send a request for "heavy process function", you are puting in thread pool, and sending replay to the specific client after calculations are done. In code it will be something like this:
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QObject>
#include <QtWebSockets>
class Server : public QObject
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
~Server();
signals:
void closed();
public slots:
private slots:
void onNewConnection();
void onMessage(QString message);
void onDisconnected();
private:
QWebSocketServer* m_pWebSocketServer;
QList<QWebSocket*> m_clients;
};
#endif // SERVER_H
server.cpp
#include <QThreadPool>
#include "server.h"
#include "heavytask.h"
Server::Server(QObject *parent) :
QObject(parent),
m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Server"), QWebSocketServer::NonSecureMode, this))
{
if (m_pWebSocketServer->listen(QHostAddress::Any, 4000)) {
connect(m_pWebSocketServer, &QWebSocketServer::newConnection, this, &Server::onNewConnection);
connect(m_pWebSocketServer, &QWebSocketServer::closed, this, &Server::closed);
}
}
void Server::onNewConnection()
{
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
connect(pSocket, &QWebSocket::textMessageReceived, this, &Server::onMessage);
connect(pSocket, &QWebSocket::disconnected, this, &Server::onDisconnected);
m_clients << pSocket;
}
void Server::onMessage(QString message)
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (message == "Start heavy process function in your server, please") {
HeavyTask* ht = new HeavyTask(pClient);
QThreadPool::globalInstance()->start(ht);
}
}
void Server::onDisconnected()
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (pClient) {
m_clients.removeAll(pClient);
pClient->deleteLater();
}
}
Server::~Server()
{
m_pWebSocketServer->close();
qDeleteAll(m_clients.begin(), m_clients.end());
}
heavytask.h
#ifndef HEAVYTASK_H
#define HEAVYTASK_H
#include <QThreadPool>
#include <QRunnable>
#include <QWebSocket>
class HeavyTask : public QRunnable
{
public:
explicit HeavyTask(QWebSocket* client);
void run();
private:
QWebSocket* m_client;
};
#endif // HEAVYTASK_H
heavytask.cpp
#include "heavytask.h"
HeavyTask::HeavyTask(QWebSocket* client) : m_client(client)
{
}
void HeavyTask::run()
{
/*
Do your havy task;
*/
if (m_client != nullptr) {
if (m_client->isValid()) {
m_client->sendTextMessage("Your answer is ready!");
}
}
}
and main.cpp
#include <QCoreApplication>
#include "server.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Server server(&a);
QObject::connect(&server, &Server::closed, &a, &QCoreApplication::quit);
return a.exec();
}
Hope it'll be useful. (Not tasted at all, but compiling)

Qt Mainwindow menu signals

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!

Asynchronously Run Console Output and GUI in Qt

I am working on building a GUI around a console application. I would like to be able to click a button to run the console app and show the console output inside of the GUI itself. How might I accomplish this? I am working in Linux.
You could also try QProcess. It provides a Qt interface to launching external processes, reading their I/O and waiting, or not, on their completion.
For your purpose, it sounds like you want the process to run asynchronously, so code might look like :
myprocessstarter.h :
#include <QObject>
#include <QProcess>
#include <QDebug>
class MyProcessStarter : public QObject
{
Q_OBJECT
public:
MyProcessStarter() : QObject() {};
void StartProcess();
private slots:
void readStandardOutput();
private:
QProcess *myProcess;
};
main.cpp:
#include "myprocessstarter.h"
void MyProcessStarter::StartProcess()
{
QString program = "dir";
QStringList arguments;
// Add any arguments you want to be passed
myProcess = new QProcess(this);
connect(myProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
myProcess->start(program, arguments);
}
void MyProcessStarter::readStandardOutput()
{
QByteArray processOutput;
processOutput = myProcess->readAllStandardOutput();
qDebug() << "Output was " << QString(processOutput);
}
void main(int argc, char** argv)
{
MyProcessStarter s;
s.StartProcess();
}
I wanted to do something similar in one of my applications. I redirected all output from the standard stream (cout) to my console window. To periodically read out the stream contents I use a timer loop. Works fine for me.
StdRedirector.cpp
#include "StdRedirector.h"
QMutex coutMutex;
void outcallback(const char* ptr, std::streamsize count, void* bufferString)
{
string *b = (string *) bufferString;
string t;
for (int i=0; i < count; i++)
{
if (ptr[i] == '\n')
{
t = t + "\n";
} else {
t = t + ptr[i];
}
}
coutMutex.lock();
*b = *b + t;
coutMutex.unlock();
}
void ConsoleWindow::updateTimer(void)
{
coutMutex.lock();
if (bufferString.size() > 0)
{
consoleBox->insertPlainText(QString(bufferString.c_str()));
bufferString.clear();
QScrollBar *sb = consoleBox->verticalScrollBar();
sb->setValue(sb->maximum());
}
coutMutex.unlock();
}
ConsoleWindow::ConsoleWindow(QWidget *parent) : QWidget(parent)
{
consoleBox = new QTextEdit(this);
consoleBox->setReadOnly(true);
stdRedirector = new StdRedirector<>(std::cout, outcallback, &bufferString);
QVBoxLayout *vb = new QVBoxLayout();
vb->addWidget(consoleBox);
vb->setMargin(0);
vb->setSpacing(0);
setLayout(vb);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(updateTimer()));
timer->start(100);
}
ConsoleWindow::~ConsoleWindow()
{
delete stdRedirector;
}
StdRedirector.h
#ifndef STD_REDIRECTOR
#define STD_REDIRECTOR
#include <QWidget>
#include <QTextEdit>
#include <QString>
#include <QVBoxLayout>
#include <QTimer.h>
#include <QMutex>
#include <QScrollBar>
#include <iostream>
#include <string>
using namespace std;
template<class Elem = char, class Tr = std::char_traits<Elem>>
class StdRedirector : public std::basic_streambuf<Elem, Tr>
{
typedef void (*pfncb) ( const Elem*, std::streamsize _Count, void* pUsrData );
public:
StdRedirector(std::ostream& a_Stream, pfncb a_Cb, void* a_pUsrData) :
m_Stream(a_Stream),
m_pCbFunc(a_Cb),
m_pUserData(a_pUsrData)
{
m_pBuf = m_Stream.rdbuf(this);
}
~StdRedirector()
{
m_Stream.rdbuf(m_pBuf);
}
std::streamsize xsputn(const Elem* _Ptr, std::streamsize _Count)
{
m_pCbFunc(_Ptr, _Count, m_pUserData);
return _Count;
}
typename Tr::int_type overflow(typename Tr::int_type v)
{
Elem ch = Tr::to_char_type(v);
m_pCbFunc(&ch, 1, m_pUserData);
return Tr::not_eof(v);
}
protected:
std::basic_ostream<Elem, Tr>& m_Stream;
std::streambuf* m_pBuf;
pfncb m_pCbFunc;
void* m_pUserData;
};
class ConsoleWindow : public QWidget
{
Q_OBJECT
public:
ConsoleWindow(QWidget *parent = 0);
~ConsoleWindow();
public slots:
void updateTimer(void);
public:
QTextEdit *consoleBox;
StdRedirector<> *stdRedirector;
string bufferString;
};
#endif
The StdRedirector class is based on code from this forum post: http://www.qtforum.org/article/24554/displaying-std-cout-in-a-text-box.html
Take a look at the popen() function, it might do what you need.
Then you could pass the FILE * to a QTextStream and work in Qt style with it.
I suggest, rather than showing stdout in GUI, having own console output, which essentially means all messages you want to show to users you are sending to your own output.
This way you can have debug messages and such still available from console, wtih potential errors with connections and whatever that can happen and have fully controlled console output in GUI application. Of course this output can also be outputted to stdout so it is visible in console, but it also allows you to append a prefixs like WARNING LOG NOTICE NO_THIS_WENT_WRONG or whatever you want to show to users as your console entry.

I just cannot get QTcpServer working (newConnection never called)

I know similar question to this have been asked, but I haven't found an answer that fixes my problem.
I'm adapting some existing Qt code to add server functionality to a program my company uses. To that end I added a QTcpServer object to the existing dialog, call listen() and connect a slot to the newConnection emitter, like:
.h
class QConsole : public QDialog
{
Q_OBJECT
public:
void init();
public slots:
void new_Connection();
private:
QTcpServer m_Server;
}
.cpp
void QConsole::init()
{
m_Server.listen(QHostAddress::Any, 12346);
QDialog::connect(&m_Server, SIGNAL(newConnection()), this, SLOT(new_Connection()));
}
Main is:
int main( int argc, char *argv[] )
{
QApplication app(argc, argv);
QConsole * _output_window = new QConsole(desktopRect);
_output_window->init();
_output_window->show();
return app.exec();
}
new_Connection() never gets called so I can't see the relevance, but here it is:
void QConsole::new_Connection()
{
}
This works fine in that my program starts listening on the port specified and if I telnet to it a connection of sorts it made, but new_Connection() is never ever ever called!
I've seen posts on this problem dating back to 2005 so it's obviously not a new thing, but what I haven't found is a satisfactory answer to the problem (or any answer actually). This has got everyone at work stumped, even the person that has written a Qt server program. I'm guessing that there is something fundamentally wrong with the existing framework, but I have no idea what it might be.
I have been tearing my hair out for a day and a half over this, and the closes I got to success was using waitForNewConnection() which would actually return me a socket, but when I connected to the readReady() emitter, that was never fired either. So what would prevent these signals never getting called?
Please spare my sanity and help me as much as you can.
Here is a complete working example, tested using MSVC++ 2010.
This listens for a connection on port 12346, replies with "HELLO WORLD" and logs the connection to a list on the dialog.
main.cpp
#include <QtGui>
#include "console.hpp"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
Console con;
con.show();
return app.exec();
}
console.hpp
#include <QtCore>
#include <QtGui>
#include <QtNetwork>
class Console : public QDialog
{
Q_OBJECT
public:
Console();
public slots:
void connection();
private:
QTcpServer mServer;
QListWidget* mConnList;
};
console.cpp
#include "console.hpp"
Console::Console() :
QDialog(),
mServer(),
mConnList(new QListWidget())
{
if (!mServer.listen(QHostAddress::Any, 12346))
qDebug() << "Error during 'listen'" << mServer.errorString();
connect(&mServer, SIGNAL(newConnection()), this, SLOT(connection()));
QVBoxLayout* mainLayout = new QVBoxLayout();
mainLayout->addWidget(mConnList);
setLayout(mainLayout);
}
void Console::connection()
{
qDebug() << "CONNECTION";
QTcpSocket* skt = mServer.nextPendingConnection();
if (!skt)
return;
mConnList->addItem(QString("%1:%2").arg(skt->peerAddress().toString()).arg(skt->peerPort()));
skt->write("HELLO WORLD!\r\n");
skt->close();
}
test.pro
TEMPLATE=app
CONFIG+=console debug
QT=core gui network
HEADERS=console.hpp
SOURCES=main.cpp console.cpp
Another working example, again on Linux, although I have coded a program using QTcpServer to run on both Linux and Windows before without a problem. If this doesn't work, surely it must be either a Qt installation or OS configuration problem. Either that or a bug in the Qt version.
~/tcp_test$ qmake --version
QMake version 2.01a
Using Qt version 4.8.6 in /usr/lib/x86_64-linux-gnu
~/tcp_test$ for file in qconsole.{h,cpp} main.cpp tcp_test.pro ; do echo -e "$file:\n"; cat $file; echo; echo; done
qconsole.h:
#include <QDialog>
#include <QTcpServer>
class QConsole : public QDialog
{
Q_OBJECT
public:
QConsole();
public slots:
void connection();
private:
QTcpServer server;
};
qconsole.cpp:
#include "qconsole.h"
QConsole::QConsole()
{
server.listen(QHostAddress::Any, 12346);
QDialog::connect(&server, SIGNAL(newConnection()), this, SLOT(connection()));
}
void QConsole::connection()
{
qDebug("got connection");
}
main.cpp:
#include <QApplication>
#include "qconsole.h"
int main( int argc, char *argv[] )
{
QApplication app(argc, argv);
QConsole * window = new QConsole();
window->show();
return app.exec();
}
tcp_test.pro:
QT = core gui network
CONFIG += debug
TARGET = tcp_test
SOURCES = main.cpp qconsole.cpp
HEADERS = qconsole.h
~/tcp_test$ ./tcp_test &
[3] 9784
~/tcp_test$ nc localhost 12346
got connection
^C

Qt QNetworkAccessManager does not emit signals

The function CheckSite() is called with an url like http://example.com, it initializes a QNetworkAccessManager object and connect() slots and signals.
The manger->get() call seems work (it generates http traffic) but does not call the slot replyFinished() at the request end.
What's wrong with this code?
#include <QtCore>
#include <QtNetwork>
class ClientHandler : public QObject
{
Q_OBJECT
QNetworkAccessManager *manager;
private slots:
void replyFinished(QNetworkReply *);
public:
void CheckSite(QString url);
};
void ClientHandler::replyFinished(QNetworkReply *reply) { qDebug() << "DONE"; }
void ClientHandler::CheckSite(QString url) {
QUrl qrl(url);
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(qrl));
}
Nothing. I wrapped it so it was fully functional and it works fine:
// placed in client.cpp
#include <QtDebug>
#include <QCoreApplication>
/* YOUR CODE */
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
ClientHandler handler;
handler.CheckSite("www.google.com");
return app.exec();
}
#include "client.moc"
It output "DONE" as expected. Maybe the site you're checking really isn't returning? Maybe it needs authentication or is producing ssl errors?
What code do you have around that? Do you spin an event loop somewhere? e.g. qapp.exec() ?

Resources