PDA

View Full Version : Qt4 'breaks' command line program



kachofool
11th November 2009, 16:12
Hey all,

I'm having problems trying to integrate an existing program with a Qt front end. The front end is pretty simple and built in Qt Creator. When I try to set up components of my existing program (by creating objects and initializing them -- the program is just a collection of classes), the GUI never launches and the program doesn't initialize all of its components correctly. It stops and 'blocks' somewhere in the code, seemingly for no reason. I should note that the code works fine without any Qt stuff in it. Conversely the GUI works fine if I don't try to initialize my program.

I'm initializing my program through member functions of the main class of my Qt Project (I've called it FrontEnd):



#include <QtGui/QApplication>
#include "frontend.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

FrontEnd rcnsWindow;
rcnsWindow.SysInitialize(); // hangs

rcnsWindow.show();

return a.exec();
}



Why could adding the Qt libraries and code stop my original program from working? I've made sure to copy over any compiler flags I needed and everything seems to compile fine.

I realize this is a general question, but was hoping that there is something blatant I'm missing. The program is fairly straightforward and basically does some I/O with serial ports.

Regards,

-KF

franz
11th November 2009, 21:27
It kind of depends on what FrontEnd::SysInitialize() does. The code you supplied doesn't do anything shocking.

kachofool
11th November 2009, 22:13
After messing with this for most of today, I'm realizing I don't really understand how Qt applications work at all.

FrontEnd::SysInitialize() inits some I/O devices that are connected to serial ports. There should be a finite delay of four seconds for the whole thing to run. Here's the contents of the function.



coupleAxial = new Axis("Translation");
coupleAxial->StartSensor();
coupleAxial->StartMover();


The problem is the GUI seems to block for a random amount of time. It'll recover, but takes a very long time. So I call processEvents() after each line of code, and it works. But I'm pretty sure this is the wrong way of going about it?

I have some generic questions

* What does the final app.exec(); call do in main.cpp? Main.cpp sets up the window, shows it, and then calls exec on the application. I'm guessing this throws it in some infinite loop that waits for events?

* What's the correct way to use processEvents()? Why should I have to use it at all? In the example with the three above function calls in the SysInitialize() function, I know that it takes a finite amount of time to execute, based on the command line version of my program. I don't care if my GUI blocks for roughly this amount of time, but this isn't what happens--the three lines aren't executed one after another

* What's the correct way to program new commands and functions? I'm assuming based on tutorials on the Qt site that main.cpp stays pretty much the same as when Qt Creator generates it. Then you populate your main class with member functions, slots, etc (in my case, FrontEnd). You call these member functions based on events (timers, button presses)...is that right?

wysota
12th November 2009, 01:16
Those three lines don't do anything shocking as well :) Please provide their contents. And if they are composed from calls to another three methods, provide those as well.


* What does the final app.exec(); call do in main.cpp?
It starts the application's main event loop. Before that no events are processed (unless you do that manually using processEvents).


* What's the correct way to use processEvents()?
The correct way is not to use it at all.


* What's the correct way to program new commands and functions?
There is no simple answer to that question. In general you should instantiate objects, initialize them and let them process events or signals (or both).

In your case it might help if you ran your initialization code after the event loop is already running. You can do that by using QTimer::singleShot() with a timeout of 0.


QTimer::singleShot(0, someObj, SLOT(initializeMe()));
return app.exec();

kachofool
12th November 2009, 17:57
Hi wysota,

Thanks for the reply. Your method worked, but introduced the problem of delaying the GUI from showing up until the initialization was done.

I've decided to instead use threads to implement some of the GUI's functionality. The GUI is basically a control panel for a motor and sensor that are 'coupled' together (so that the motor tries to follow the sensor position).

In any case, I've more or less got desired functionality with the initialization using QThreads. Now I have a more generic question...

Since the GUI is just a control panel, it's set up so that most button presses will act like a macro to do something with the motor/sensor behaviour. Say I have 10 of these buttons tied to 10 functions (like start, stop, reset, etc).

To keep the GUI responsive I was hoping to tie these 10 functions to threads. My questions revolve around the 'correct' way to go about implementing this.

* Is what I'm trying to do overkill? Most of these threads won't even loop, so they aren't doing some huge job, except for in some cases where the work (even though its still sequential) will cause delays on the order of seconds.

* Is using threads to handle user commands the norm in keeping a GUI responsive? Or am I looking at this problem wrong?

* Do I create a new thread class for each function I want to run? Or would it be better to subclass once? I don't know how I would run a 'different' function with only one thread type unless I pass some sort of instruction to the thread, and having a giant case/switch to decide what to do or something along those lines.

Tyvm for the help so far!

KF

wysota
13th November 2009, 00:44
Thanks for the reply. Your method worked, but introduced the problem of delaying the GUI from showing up until the initialization was done.
You can increase the timeout of the timer to delay initialization. But it will then freeze your UI.


I've decided to instead use threads to implement some of the GUI's functionality. The GUI is basically a control panel for a motor and sensor that are 'coupled' together (so that the motor tries to follow the sensor position).
Bad idea, you can't use threads to operate on GUI.


* Is what I'm trying to do overkill?
Yes. You can happily do everything in one thread. Including the initialization. You just need to do it the smart way.


* Is using threads to handle user commands the norm in keeping a GUI responsive? Or am I looking at this problem wrong?
Read my article on Qt Quarterly about responsive GUIs.

squidge
13th November 2009, 01:54
If your buttons just send command to a device down a communications port such as serial or usb then wait for a reply and you don't want that wait to block your ui then I'd say the best way is to have one thread for the comms and the default one for the ui. The ui will just queue up the requests and the thread processes them as it can.

kachofool
13th November 2009, 20:56
fatjuicymole, this is exactly what I ended up doing and all seems to be working fairly well so far.

wysota, I realize I can't update the GUI directly with threads. I've used signals and slots instead in cases where I need to alter the GUI from the main thread.

Thanks to all for the input :)