I have written a console application for my server. It works very well, I can start it over the terminal and all is okay.
For desktop environments it would be very nice, to set a flag in the settings.ini file of the program to open a MainWindow to show some information of the running console application. The console in the background can be left open. All I need is a window and some SINGAL/SLOTS between the main application running in console and the MainWindow.
How to realize this? I figured out, I have to handle with QApplication and QCoreApplication right?
Simply put this line to your pro file:
CONFIG += console
In Qt5.x from Win7 to Win10 you could do something like this:
//includes
#include <QApplication>
#include <QMainWindow>
#include <QString>
#include <QObject>
#include <QDir>
#include <QSettings>
#include <windows.h>
#include <stdio.h>
#include <iostream>
//
// Add to project file:
// CONFIG += console
//
The server:
//Here we have the Server class able to send signals
//Server will be used in main.cpp for console
//and/or in MainWindow to handle the signals
class Server : public QObject
{
Q_OBJECT
public:
Server( QObject *parent = 0 ) : QObject( parent )
{
//do server stuff
//this->setName( "Test" );
//std::cout << this->getName( ) << std::endl;
//std::cout << "Enter URL: << std::endl;
//std::string url;
//std::cin >> url;
//_url = QString::fromStdString( url );
//emit finished();
}
signals:
void finished( );
private:
QString _url;
};
The MainWindow:
//Here is the MainWindow using Server
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow( QWidget *parent = 0 ) : QMainWindow()
{
server = new Server( this ); //use server in hybrid mode (console and gui)
connect( server, SIGNAL(finished()), this, SLOT(close()) ); //establish connection
}
private:
Server *server;
};
The main:
int main( int argc, char *argv[] )
{
QString iniPath = QFileInfo( QDir::fromNativeSeparators(argv[0]) ).absolutePath(); //get the current dir
QSettings settings( iniPath+"/settings.ini", QSettings::IniFormat ); //open ini
bool gui = settings.value( "gui", false ).toBool(); //read ini
if( gui ) //decide
{
#if defined( Q_OS_WIN )
// hide console window, but not in your case
// ::ShowWindow( ::GetConsoleWindow(), SW_HIDE );
#endif
//std::cout will print to the console in the bg like you wished
QApplication a( argc, argv );
MainWindow *w = new MainWindow;
w->show();
int e = a.exec();
delete w; //needed to execute deconstructor
exit( e ); //needed to exit the hidden console
return e;
}
else
{
QCoreApplication a( argc, argv );
Server *instance = new Server; //use server in console only
exit( 0 );
return a.exec();
}
}
I tried it also without the "CONFIG += console", but then you need to redirect the streams and create the console on your own:
#ifdef _WIN32
if (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()){
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
freopen("CONIN$", "r", stdin);
}
#endif
BUT this only works if you start it through a debugger, otherwise all inputs are directed towards the system too. Means, if you type a name via std::cin the system tries to execute the name as a command. (very strange)
Two other warnings to this attempt would be, that you can't use ::FreeConsole() it won't close it and if you start it through a console the app won't close.
Last there is a Qt help section in QApplication to this topic. I tried the example there with an application and it doesn't work for the GUI, it stucked somewhere in an endless loop and the GUI won't be rendered or it simply crashes:
QCoreApplication* createApplication(int &argc, char *argv[])
{
for (int i = 1; i < argc; ++i)
if (!qstrcmp(argv[i], "-no-gui"))
return new QCoreApplication(argc, argv);
return new QApplication(argc, argv);
}
int main(int argc, char* argv[])
{
QScopedPointer<QCoreApplication> app(createApplication(argc, argv));
if (qobject_cast<QApplication *>(app.data())) {
// start GUI version...
} else {
// start non-GUI version...
}
return app->exec();
}
So if you are using Windows and Qt simply use the console option, hide the console if you need the GUI and close it via exit.
Related
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. :>
I want to use the camera in a headless (console) qt application (at least for unit testing).
But I facing a problem with Qt. As soon I use my code in a console application, the camera won't work - the readyForCaptureChanged event of QCameraImageCapture will not be called.
If I use exactly the same code in a gui application, the event gets triggered and I can capture images.
The common code I use is that:
camera = new QCamera(cameras.at(config->cameraNumber()));
imageCapture = new QCameraImageCapture(camera);
connect(imageCapture, SIGNAL(readyForCaptureChanged(bool)), this, SLOT(readyForCapture(bool)));
camera->start(); // to start the viewfinder
// ——
void ImageCapture::readyForCapture(bool b) {
qDebug() << "ready for capture "<<b;
}
when I call this code in the gui application directly in the constructor of my MainWindow, it works (event will be triggered).
When I call this code in my qt console application, it does not work (event will not be triggered).
Can anybody help me? Thanks
** UPDATE 29. August - full code **
Console Application:
main.cpp
#include <QCoreApplication>
#include <QTest>
#include <QTimer>
#include <QDebug>
#include <runoneventloop.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
RunOnEventLoop * run = new RunOnEventLoop(&a);
QTimer::singleShot(0, run, SLOT(run()));
return a.exec();
}
RunOnEventLoop.cpp
#include "runoneventloop.h"
RunOnEventLoop::RunOnEventLoop(QObject *parent) :
QObject(parent)
{
}
void RunOnEventLoop::run() {
qDebug() << "hier run";
camera = new QCamera(0);
imageCapture = new QCameraImageCapture(camera);
connect(imageCapture, SIGNAL(readyForCaptureChanged(bool)), this, SLOT(readyForCapture(bool)));
camera->start(); // to start the viewfinder
}
void RunOnEventLoop::readyForCapture(bool b) {
qDebug() << "ready of capture "<<b;
}
RunOnEventLoop.h
#ifndef RUNONEVENTLOOP_H
#define RUNONEVENTLOOP_H
#include <QObject>
#include <QDebug>
#include <QCamera>
#include <QCameraImageCapture>
class RunOnEventLoop : public QObject
{
Q_OBJECT
public:
explicit RunOnEventLoop(QObject *parent = 0);
private:
QCamera* camera;
QCameraImageCapture* imageCapture;
signals:
public slots:
void run();
void readyForCapture(bool);
};
#endif // RUNONEVENTLOOP_H
GUI Application
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug() << "hier";
camera = new QCamera(0);
imageCapture = new QCameraImageCapture(camera);
connect(imageCapture, SIGNAL(readyForCaptureChanged(bool)), this, SLOT(readyForCapture(bool)));
camera->start(); // to start the viewfinder
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::readyForCapture(bool b) {
qDebug() << "ready of capture "<<b;
}
again, it's the same code. Console App does not call the readyForCapture method, while the gui application calls it.
you can download the archive here: DOWNLOAD
If would be nice if you could provide something more of your console-based Qt application... the code you presented, how is it called by your main code?
Anyway, just guessing, if no events are raised at all maybe it is because you are not running any event loop... are you sure that your code at some point call exec() on your QCoreApplication object? Are you sure that the owner of the object from which you call connect() is the thread of QCoreApplication?
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 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
I am trying to display and get the result a message box from outside of a QObject class. I seem to be able to generate the dialog like this:
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QMessageBox>
class DialogHandler : public QObject
{
Q_OBJECT
signals:
void MySignal();
public:
DialogHandler()
{
connect( this, SIGNAL( MySignal() ), this, SLOT(MySlot()) );
}
void EmitSignal()
{
emit MySignal();
}
public slots:
void MySlot()
{
QMessageBox* dialog = new QMessageBox;
dialog->setText("Test Text");
dialog->exec();
int result = dialog->result();
if(result)
{
std::cout << "ok" << std::endl;
}
else
{
std::cout << "invalid" << std::endl;
}
}
};
#include "main.moc" // For CMake's automoc
void MyFunction(DialogHandler* dialogHandler)
{
dialogHandler->EmitSignal();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
DialogHandler* dialogHandler = new DialogHandler;
MyFunction(dialogHandler);
return app.exec();
}
To get the result back in MyFunction, it seems to work to do simply pass an object to fill with the result like this:
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QMessageBox>
class DialogHandler : public QObject
{
Q_OBJECT
signals:
void MySignal(int* returnValue);
public:
DialogHandler()
{
connect( this, SIGNAL( MySignal(int*) ), this, SLOT(MySlot(int*)), Qt::BlockingQueuedConnection );
}
void EmitSignal(int* returnValue)
{
emit MySignal(returnValue);
}
public slots:
void MySlot(int* returnValue)
{
std::cout << "input: " << *returnValue << std::endl;
QMessageBox* dialog = new QMessageBox;
dialog->addButton(QMessageBox::Yes);
dialog->addButton(QMessageBox::No);
dialog->setText("Test Text");
dialog->exec();
int result = dialog->result();
if(result == QMessageBox::Yes)
{
*returnValue = 1;
}
else
{
*returnValue = 0;
}
}
};
#include "main.moc" // For CMake's automoc
void MyFunction(DialogHandler* dialogHandler)
{
int returnValue = -1;
dialogHandler->EmitSignal(&returnValue);
std::cout << "returnValue: " << returnValue << std::endl;
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
DialogHandler* dialogHandler = new DialogHandler;
QtConcurrent::run(MyFunction, dialogHandler);
std::cout << "End" << std::endl;
return app.exec();
}
Does that seem reasonable? Is there a better way to do it?
This isn't possible quite like you have it, but with a bit of work it could be done. One option, of course, would be to convert your class to a QObject, at which point you could send signals. It doesn't help for the delay during exec, however. If that is necessary, you could have a messaging class that lives in the main UI thread, but can be called from other threads. The function called from other threads would need to lock, make a semaphore, and send an event to itself with the semaphore and message to be displayed. Then, in customEvent (which would be in the UI thread), you would create the message box, exec it, and trigger the semaphore after the message box is cleared.
Of course, things get a bit more complicated if you need to send information back the other way as well. Then you'll need a complete subsystem for your program, instead of just one basic class like I describe here.