I try to send a message via dbus-send to this small example program.
But it is not received:
dbus-send --session --type=method_call / dbustester.test.slot_foo
The return code is 0 and not message is printed to the console.
Below is the source code.
main.cpp
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtDBus/QtDBus>
#include <Example.h>
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
Example *e = new Example();
e->setupDBus();
return app.exec();
}
Example.h
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtDBus/QtDBus>
class Example : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "dbustester.test")
public:
Example(QObject* parent = NULL) :
QObject(parent)
{
}
void setupDBus()
{
QDBusConnection session = QDBusConnection::sessionBus();
if (!session.isConnected())
{
qFatal("Cannot connect to the D-Bus session bus.");
return;
}
session.connect("", "/", "dbustester.test", "slot_foo", this, SLOT(slot_foo(void)));
if(!session.registerObject("/", this, QDBusConnection::ExportScriptableContents)) {
qFatal("Cannot registerObject.");
return;
}
if(!session.registerService("dbustester.test")) {
qFatal("Cannot registerObject.");
return;
}
}
public slots:
Q_SCRIPTABLE void slot_foo()
{
qDebug() << "request received";
}
};
Build:
qmake -project
echo "CONFIG += qdbus" >> *.pro
qmake
I've found the answer while writing the question, but I wrote the question anyway. Some people might find it useful.
dbus-send --session --dest=dbustester.test --type=method_call / dbustester.test.slot_foo
I forgot the --dest argument. :>
Related
This question already has answers here:
When should Q_OBJECT be used?
(4 answers)
QT "No such slot" Error [duplicate]
(1 answer)
Closed 6 years ago.
I have written an UDP programme with Qt, and when I connect this:
connect(socket,SIGNAL(readyRead()),this,SLOT(processPendingDatagrams()));
the complier tells me that
no such slot
the error click here
and I want to know how to fix it, thank you!
P.S.
Here are my files:
files
Here are my codes:
enter code here
udptest.cpp:
#include "udptest.h"
#include <QObject>
#include <QUdpSocket>
#include <QtNetwork>
UDPtest::UDPtest()
{
socket = new QUdpSocket();
port = 2016;
socket->bind(port,QUdpSocket::ShareAddress
| QUdpSocket::ReuseAddressHint);
connect(socket,SIGNAL(readyRead()),this,SLOT(processPendingDatagrams()));
}
QString UDPtest::getIP()
{
QList<QHostAddress> list = QNetworkInterface::allAddresses();
foreach (QHostAddress address, list)
{
if(address.protocol() == QAbstractSocket::IPv4Protocol)
return address.toString();
}
return 0;
}
void UDPtest::sendMessage(QString message)
{
QByteArray data;
QDataStream out(&data,QIODevice::WriteOnly);
QString localHostName = QHostInfo::localHostName();
QString address = getIP();
out <<"123"<< localHostName << address << message;
socket->writeDatagram(data,data.length(),QHostAddress::Broadcast, port);
}
void UDPtest::processPendingDatagrams()
{qDebug()<<"receive";
while(socket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(),datagram.size());
QDataStream in(&datagram,QIODevice::ReadOnly);
QString userName,localHostName,ipAddress,message;
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
in >>userName >>localHostName >>ipAddress >>message;
QString msg=time+userName+localHostName+ipAddress+message;
msger=msg;
qDebug()<<msg;
}
}
QString UDPtest:: messager()
{
return msger;
}
main.cpp:
#include"udptest.h"
#include<QDebug>
#include <QtCore/QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug()<<"123";
UDPtest test;
test.sendMessage("aha");
return a.exec();
}
udptest.h:
#ifndef UDPTEST_H
#define UDPTEST_H
#include <QObject>
#include <QUdpSocket>
#include <QtCore/QCoreApplication>
#include <QtNetwork>
class UDPtest:public QObject
{
public:
UDPtest();
QString messager();
void sendMessage(QString);
private slots:
void processPendingDatagrams();
private:
QString msger;
QUdpSocket *socket;
qint16 port;
QString getIP();
};
#endif // UDPTEST_H
QudptestConsole.pro:
QT += core
QT -= gui
QT += network
CONFIG += c++11
TARGET = QudptestConsole
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp \
udptest.cpp
HEADERS += \
udptest.h
You have forgotten Q_OBJECT macro in UDPtest class
class UDPtest: public QObject
{
Q_OBJECT
public:
UDPtest();
.....
}
I'm trying to do a simple GET request (with modified User-Agent), return response to QML and do a JSON parsing.
Actually it only returns page content when loading is complete but it doesn't return it to QML.
Sorry for the noob question. I'm new to this language and I'm trying to learn it :)
Here's my code:
Home.qml
function getRequest() {
[...]
console.log('Request...')
var jsonResult = JSON.parse(connectNet.connectUrl("http://myURL.com/index.php").toString())
lbOutput.text = jsonResult.predictions[0].description.toString()
}
}
connectnet.cpp
#include "connectnet.h"
#include "stdio.h"
#include <QDebug>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QUrl>
connectNet::connectNet(QObject *parent) : QObject(parent)
{
}
void connectNet::connectUrl(QString url)
{
QNetworkAccessManager *manager = new QNetworkAccessManager();
QNetworkRequest request;
QNetworkReply *reply = NULL;
request.setUrl(QUrl(url));
request.setRawHeader( "User-Agent" , "FAKE USER AGENT HERE" );
reply = manager->get(request);
connect(manager, SIGNAL(finished(QNetworkReply*)), this,
SLOT(replyFinished(QNetworkReply*)));
}
QString connectNet::replyFinished(QNetworkReply *reply)
{
return reply->readAll();
}
appname.cpp
#ifdef QT_QML_DEBUG
#include <QtQuick>
#endif
#include <sailfishapp.h>
#include "connectnet.h"
int main(int argc, char *argv[])
{
//INIT SETTINGS
QGuiApplication *app = SailfishApp::application(argc, argv);
QQuickView *view = SailfishApp::createView();
connectNet ConnectNet;
view->rootContext()->setContextProperty("connectNet", &ConnectNet);
view->setSource(SailfishApp::pathTo("qml/APPNAME.qml"));
view->showFullScreen();
app->exec();
}
Hope I've well explained what I'm looking for. Thanks for your help.
====================================================
EDIT 20/08/2015: added updated connectnet.h
#ifndef CONNECTNET_H
#define CONNECTNET_H
#include <QObject>
#include <QNetworkReply>
#include <QDebug>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QUrl>
class ConnectNet : public QObject
{
Q_OBJECT
QNetworkAccessManager m_manager;
public:
ConnectNet(QObject * parent = 0) : QObject(parent) {
connect(&m_manager, &QNetworkAccessManager::finished,
[this](QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError)
emit replyAvailable(QString::fromUtf8(reply->readAll()));
});
}
signals:
void replyAvailable(const QString & reply);
public slots:
void sendRequest(const QString url) {
QNetworkRequest request;
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", "MyLittleAgent");
m_manager.get(request);
}
};
#endif // CONNECTNET_H
this part of code gives a lot of errors :( (screenshot below)
connect(&m_manager, &QNetworkAccessManager::finished,
[this](QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError)
emit replyAvailable(QString::fromUtf8(reply->readAll()));
});
compiling erros: http://i.stack.imgur.com/30vWn.jpg
Your problem is that you think synchronously. The connectUrl cannot return a value (and it doesn't), since when it runs the result is not available. What you must do, instead, is for the ConnectNet class to emit a signal when the data is available.
It'd be a horrible idea if you tried to make a synchronous wrapper that did return the value: the QML engine would be stuck as long as it took for the result to be received. You could freeze your application by pulling the network cable at the right moment, or if the server was down. Users hate that, and it's a horrible antipattern that must be expediently eliminated and discouraged.
Here's how your ConnectNet (please, not connectNet, lowercase names are for members!) class could look. Note that the QNetworkAccessManager instance doesn't need to be a pointer.
class ConnectNet : public QObject {
Q_OBJECT
QNetworkAccessManager m_manager;
public:
ConnectNet(QObject * parent = 0) : QObject(parent) {
connect(&m_manager, &QNetworkAccessManager::finished,
[this](QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError)
emit replyAvailable(QString::fromUtf8(reply->readAll()));
});
}
Q_SLOT void sendRequest(const QString & url) {
auto request = QNetworkRequest(QUrl(url));
request.setRawHeader("User-Agent", "MyLittleAgent");
m_manager.get(request);
}
Q_SIGNAL void replyAvailable(const QString & reply);
};
Since connectNet instance instance is exposed as a property in the global QML context, you can connect to its signals as follows:
function getRequest() {
connectNet.sendRequest("http://myURL.com/index.php")
}
function resultHandler(result) {
var jsonResult = JSON.parse(result.toString())
lbOutput.text = jsonResult.predictions[0].description.toString()
}
Rectangle { // or any other item
Component.onCompleted: {
connectNet.replyAvailable.connect(resultHandler)
}
...
}
I want to start a process from a QT app and catch its termination event. Its done with the method QProcess::start(). But unlike in startDetached(), the standard output of the process is redirected to a buffer. I don't want that.
I can't find how to disable it. An ugly workaround is to call setStandardOutputFile("/dev/stdout")
test.h
#ifndef MY_TEST_H
#define MY_TEST_H
#include <QCoreApplication>
class MyApp : public QCoreApplication {
Q_OBJECT
private Q_SLOTS:
void subprocessStarted();
void subprocessFinished(int);
public:
MyApp( int & argc, char ** argv );
};
#endif
test.cpp
#include "test.h"
#include <QProcess>
#include <QCoreApplication>
#include <stdio.h>
#define ENTRY printf("%s\n", __PRETTY_FUNCTION__)
MyApp::MyApp( int & argc, char ** argv ) : QCoreApplication(argc, argv) {
ENTRY;
QProcess *process = new QProcess();
//process->setStandardOutputFile("/dev/stdout");
process->start("/bin/echo aaa");
bool b;
b = connect(process, SIGNAL(started()), SLOT(subprocessStarted()));
printf("connect started %d\n", b);
b = connect(process, SIGNAL(finished(int)), SLOT(subprocessFinished(int)));
printf("connect finished %d\n", b);
}
void MyApp::subprocessStarted() {
ENTRY;
}
void MyApp::subprocessFinished(int ret) {
ENTRY;
printf("%d\n", ret);
}
int main(int argc, char *argv[]) {
ENTRY;
MyApp a(argc, argv);
return a.exec();
}
Does QProcess::closeReadChannel(ProcessChannel channel) work for you?
Closes the read channel channel. After calling this function, QProcess
will no longer receive data on the channel. Any data that has already
been received is still available for reading. Call this function to
save memory, if you are not interested in the output of the process.
Like this-
QProcess *process = new QProcess();
process->start("/bin/echo aaa");
process->closeReadChannel(QProcess::StandardOutput);
process->closeReadChannel(QProcess::StandardError);
I tried declaring a signal in a prototype and then connecting it is script funcition for some reason it does not work as I hoped. My code is as follows. Could some one help me in this.
What I expected was, once I called p.setText('New String') in the script code, since setText emits the textChanged signal it should invoke the slot which is catchSignal(text) already connected in the script code.
Prototype header
#ifndef SCRIPTACTION_H
#define SCRIPTACTION_H
#include <QObject>
#include <QtScript>
class ScriptAction : public QObject , public QScriptable
{
Q_OBJECT
public:
ScriptAction(QObject *parent = 0);
signals:
void textChanged(const QString changedString);
};
#endif // SCRIPTACTION_H
Class
#include "scriptaction.h"
#include <QAction>
Q_DECLARE_METATYPE(QAction*)
ScriptAction::ScriptAction(QObject *parent) : QObject(parent)
{
}
Main Class
#include <QApplication>
#include <QDebug>
#include <QAction>
#include "scriptaction.h"
#include <QPushButton>
Q_DECLARE_METATYPE(QAction*)
QScriptValue qAction_Constructor(QScriptContext *ctx, QScriptEngine *eng)
{
qDebug() << "QAction is called";
if(ctx->isCalledAsConstructor())
{
QObject *parent = ctx->argument(0).toQObject();
QAction *action = new QAction("Test",parent);
return eng->newQObject(action, QScriptEngine::ScriptOwnership);
} else {
return QString("invalid call. Use new Constructor");
}
}
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
QScriptEngine engine;
//Evaluating a simaple expresssion
qDebug() << engine.evaluate("1+2").toNumber();
QPushButton button;
QScriptValue buttonScript= engine.newQObject(&button);
engine.globalObject().setProperty("button", buttonScript);
engine.evaluate("button.text ='Hello Text'; button.show()");
//QAction Prototype
ScriptAction qsAction ;
QScriptValue script_proto = engine.newQObject(&qsAction);
engine.setDefaultPrototype(qMetaTypeId<QAction*>(), script_proto);
QScriptValue ctor = engine.newFunction(qAction_Constructor , script_proto);
QScriptValue metaObject = engine.newQMetaObject(&QObject::staticMetaObject, ctor);
engine.globalObject().setProperty("QSAction" , metaObject);
engine.evaluate("var p = new QSAction(button);p.textChanged.connect(catchSignal);");
engine.evaluate("function catchSignal(text) { print ('PROTOTYPE SIGNAL IS CALLED ',text); } p.setText('New String'); " );
return app.exec();
}
I got rid of the issue, and now I see the signal is being triggered and slot is called properly.
All I did was moving the code to a separate script file and start using the QScriptDebugger to see its output. Then I figured there was an error and the code is edited to work.
Anyone who wants an example prototype class, this will hopefully be a good guideline.
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.