| Trolltech Home | Qt-jambi-interest Home | Recent Threads | All Threads | Author | Date | |
| All threads index page 1 | |
1) I see that the QApplication has to run in the main thread of my app. Why?
Doing this:
new Thread() {
public void run() {
QApplication.exec();
}
}.start();
seem to give me a not responding GUI.
2) If update my GUI in another thread than the AWT thread, I'm used to
in Swing to say something like this:
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
// Do your UI update stuff
}
});
to ensure correct handeling. What is the corresponding calls in Jambi if
I have a model update stemming from an RMI thread for example?
3) I'm fiddeling a bit with implementing QAbstractItemModel for a
QTreeView, similar to MVC programming in Swing for JTree. However, I was
expected to find this class to be an interface or at least have abstract
methods for the things that I was ment to implement. Why do every of
these methods have default implementations?
Best regards,
Helge Fredriksen
Helge Fredriksen wrote:
> 1) I see that the QApplication has to run in the main thread of my app.
> Why?
> Doing this:
>
> new Thread() {
> public void run() {
> QApplication.exec();
> }
> }.start();
>
> seem to give me a not responding GUI.
Hi Helge,
Qt was designed this way. GUI processing can only happen in the process
main thread. You can read more about how Qt works with threads here:
http://doc.trolltech.com/4.1/threads.html
> 2) If update my GUI in another thread than the AWT thread, I'm used to
> in Swing to say something like this:
> SwingUtilities.invokeAndWait(new Runnable() {
> public void run() {
> // Do your UI update stuff
> }
> });
> to ensure correct handeling. What is the corresponding calls in Jambi if
> I have a model update stemming from an RMI thread for example?
The proper way to do this in Qt is to use a queued signal/slot connection.
http://doc.trolltech.com/4.2/threads.html#signals-and-slots-across-threads
Say your rmi thread needs to change the label of a text:
Somewhere in the class where you set up your code you would do:
stateChanged.connect(label, "setText(String)");
And when the event occurs that triggers the change, you call:
stateChanged.emit(newStringValue);
Since the emitter thread and the receiver thread are different threads
this will automatically be interpreted as a queued connection.
-
Alternativly you can post an event to an object that lives in the gui
thread.
QApplication::postEvent(new QObject() {
public void event(QEvent e) {
// Do gui stuff...
}
}, new QEvent(QEvent.User+1));
-
> 3) I'm fiddeling a bit with implementing QAbstractItemModel for a
> QTreeView, similar to MVC programming in Swing for JTree. However, I was
> expected to find this class to be an interface or at least have abstract
> methods for the things that I was ment to implement. Why do every of
> these methods have default implementations?
This is a limitation in the generator that we're using. We are working
on fixing this.
-
Gunnar
On Tuesday 8 August 2006 09:59, Gunnar Sletta wrote:
> Alternativly you can post an event to an object that lives in the gui
> thread.
>
> QApplication::postEvent(new QObject() {
> public void event(QEvent e) {
> // Do gui stuff...
> }
> }, new QEvent(QEvent.User+1));
Would it be possible to merge this with the Runnable interface?
--
[ signature omitted ]
Attachment:
pgpNuOFifwIb5.pgp
Description: PGP signature
Thomas Zander wrote:
> On Tuesday 8 August 2006 09:59, Gunnar Sletta wrote:
>
>>Alternativly you can post an event to an object that lives in the gui
>>thread.
>>
>>QApplication::postEvent(new QObject() {
>> public void event(QEvent e) {
>> // Do gui stuff...
>> }
>>}, new QEvent(QEvent.User+1));
>
>
> Would it be possible to merge this with the Runnable interface?
It could certainly make sense to have some sort of invokeLater event
that would simplify this kind of programming. I'll make a task an put it
out for voting.
-
Gunnar
Gunnar Sletta wrote:
> Helge Fredriksen wrote:
>> 1) I see that the QApplication has to run in the main thread of my
>> app. Why?
>> Doing this:
>>
>> new Thread() {
>> public void run() {
>> QApplication.exec();
>> }
>> }.start();
>>
>> seem to give me a not responding GUI.
>
> Hi Helge,
>
> Qt was designed this way. GUI processing can only happen in the
> process main thread. You can read more about how Qt works with threads
> here:
>
> http://doc.trolltech.com/4.1/threads.html
>
>> 2) If update my GUI in another thread than the AWT thread, I'm used
>> to in Swing to say something like this:
>> SwingUtilities.invokeAndWait(new Runnable() {
>> public void run() {
>> // Do your UI update stuff
>> }
>> });
>> to ensure correct handeling. What is the corresponding calls in Jambi
>> if I have a model update stemming from an RMI thread for example?
>
> The proper way to do this in Qt is to use a queued signal/slot
> connection.
>
> http://doc.trolltech.com/4.2/threads.html#signals-and-slots-across-threads
>
>
> Say your rmi thread needs to change the label of a text:
> Somewhere in the class where you set up your code you would do:
> stateChanged.connect(label, "setText(String)");
> And when the event occurs that triggers the change, you call:
> stateChanged.emit(newStringValue);
>
> Since the emitter thread and the receiver thread are different threads
> this will automatically be interpreted as a queued connection.
>
> -
>
> Alternativly you can post an event to an object that lives in the gui
> thread.
>
> QApplication::postEvent(new QObject() {
> public void event(QEvent e) {
> // Do gui stuff...
> }
> }, new QEvent(QEvent.User+1));
Where do I execute the code which I ship off in the QEvent? For
instance, I might like to launch some new dialog in the event code. Can
I register as event listener for the type of event QEvent.User+1? I know
these are probably basic questions, but for a guy used to Swing, this is
a new ballgame all together.
Regards,
Helge F.
Helge Fredriksen wrote:
>> QApplication::postEvent(new QObject() {
>> public void event(QEvent e) {
>> // Do gui stuff...
>> }
>> }, new QEvent(QEvent.User+1));
>
>
> Where do I execute the code which I ship off in the QEvent? For
> instance, I might like to launch some new dialog in the event code. Can
> I register as event listener for the type of event QEvent.User+1? I know
> these are probably basic questions, but for a guy used to Swing, this is
> a new ballgame all together.
I'm not sure I understand. This will post an event to the eventloop and
when its time for the event to be processed the virtual function event
will be called. If you needed to open a dialog you would do something
like this:
QApplication::postEvent(new QObject() {
public void event(QEvent e) {
String name = QFileDialog.getSaveFileName();
setFileName(name);
}
}, new QEvent(QEvent.User + 1));
If the event receiver was a more generic object you would check the
QEvent.type() and verify that its actually User+1, but since this is a
special instance that won't receive any other events you don't need such
a check.
On a side note, I created the public task 125118 in our task tracker to
introduce a simplified version of this feature, e.g. something like
QApplication::invokeLater(Runnable r);
http://www.trolltech.com/developer/task-tracker/index_html?method=entry&id=125118
-
Gunnar
Gunnar Sletta wrote:
> Helge Fredriksen wrote:
>
>>> QApplication::postEvent(new QObject() {
>>> public void event(QEvent e) {
>>> // Do gui stuff...
>>> }
>>> }, new QEvent(QEvent.User+1));
>>
>>
>> Where do I execute the code which I ship off in the QEvent? For
>> instance, I might like to launch some new dialog in the event code.
>> Can I register as event listener for the type of event QEvent.User+1?
>> I know these are probably basic questions, but for a guy used to
>> Swing, this is a new ballgame all together.
>
> I'm not sure I understand. This will post an event to the eventloop
> and when its time for the event to be processed the virtual function
> event will be called. If you needed to open a dialog you would do
> something like this:
>
> QApplication::postEvent(new QObject() {
> public void event(QEvent e) {
> String name = QFileDialog.getSaveFileName();
> setFileName(name);
> }
> }, new QEvent(QEvent.User + 1));
>
Hmmm, I thought so too first. However, the statements inside
event(QEvent e) {} never get called in my
code... I see the code breaks in the posting, but not inside the event()
method.
Helge F.
Helge Fredriksen wrote:
>> QApplication::postEvent(new QObject() {
>> public void event(QEvent e) {
>> String name = QFileDialog.getSaveFileName();
>> setFileName(name);
>> }
>> }, new QEvent(QEvent.User + 1));
>>
> Hmmm, I thought so too first. However, the statements inside
> event(QEvent e) {} never get called in my
> code... I see the code breaks in the posting, but not inside the event()
> method.
>
> Helge F.
Hi Helge,
That shows me to not test code I post ;-)
QObject.event() returns a boolean. Strange that this didn't produce a
compile error for you. The example below works as expected though.
best regards,
Gunnar
<snip>
import com.trolltech.qt.core.*;
public class InvokeLater
{
public static void main(String args[]) {
// Set up
QCoreApplication.initialize(args);
// Post the event...
QCoreApplication.postEvent(new QObject() {
public boolean event(QEvent e) {
// Print out a message
System.out.println("Quit event triggered...");
// Exit the event loop
QCoreApplication.quit();
return true;
}
}, new QEvent(QEvent.User + 1));
// Spin the event loop.
QCoreApplication.exec();
}
}
</snip>
Gunnar Sletta wrote:
> Helge Fredriksen wrote:
>
>>> QApplication::postEvent(new QObject() {
>>> public void event(QEvent e) {
>>> String name = QFileDialog.getSaveFileName();
>>> setFileName(name);
>>> }
>>> }, new QEvent(QEvent.User + 1));
>>>
>> Hmmm, I thought so too first. However, the statements inside
>> event(QEvent e) {} never get called in my
>> code... I see the code breaks in the posting, but not inside the
>> event() method.
>>
>> Helge F.
>
> Hi Helge,
>
> That shows me to not test code I post ;-)
>
> QObject.event() returns a boolean. Strange that this didn't produce a
> compile error for you. The example below works as expected though.
>
> best regards,
> Gunnar
>
> <snip>
> import com.trolltech.qt.core.*;
>
> public class InvokeLater
> {
> public static void main(String args[]) {
> // Set up
> QCoreApplication.initialize(args);
>
> // Post the event...
> QCoreApplication.postEvent(new QObject() {
> public boolean event(QEvent e) {
> // Print out a message
> System.out.println("Quit event triggered...");
>
> // Exit the event loop
> QCoreApplication.quit();
> return true;
> }
> }, new QEvent(QEvent.User + 1));
>
> // Spin the event loop.
> QCoreApplication.exec();
> }
> }
> </snip>
>
>
>
I tried to modify your code to fit my scenario:
public class InvokeLater {
public static void main(String args[]) {
// Set up
QCoreApplication.initialize(args);
new Thread() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch
statement use File | Settings | File Templates.
}
QCoreApplication.postEvent(new QObject() {
public boolean event(QEvent e) {
// Print out a message
System.out.println("Quit event triggered...");
// Exit the event loop
QCoreApplication.quit();
return true;
}
}, new QEvent(QEvent.User + 1));
}
}.start();
// Post the event...
// Spin the event loop.
QCoreApplication.exec();
}
}
and no quit got triggered, the program hangs there nice and easy....
Helge
Helge Fredriksen wrote: > I tried to modify your code to fit my scenario: ... > and no quit got triggered, the program hangs there nice and easy.... Hi Helge, I've modified the example so that it works. Threading in Qt is a little bit different that threading in Java. QObjects have thread affinity, e.g. they belong to a certain thread. In addition to that you have one event loop pr thread. The event, posted in QCoreApplication.postEvent(), will be _posted_to_ the event loop of the QObjects thread and will be delivered _in_ the QObjects thread. By default the QObject belongs to the thread that created it. In your example the QObject is created in the secondary thread, thus belonging to it. The event is therefore posted to this threads event loop. Since the secondary thread doesn't spin an event loop the event never gets delivered. There are two solutions to this, depending on what you need. 1. You want the event delivered in the GUI event loop, because you want to open a dialog (I expect this is what you want, and what the example does). The way of doing this is to call QObject.moveToThread() on the qobject before posting the event to it. I solved this by introducing an Invokable class that I pass to QApplication.postEvent() instead of the plain QObject. In the constructor of Invokable I simply call moveToThread. 2. If you want the event delivered in the secondary thread, you need to manually spin the event loop in the Threads run() function. You can do this by a call to: QEventLoop loop = new QEventLoop(); loop.exec(); at the end of the run() function. You can read more about threading in Qt here: http://doc.trolltech.com/4.1/threads.html and event loops and threads: http://doc.trolltech.com/4.1/threads.html#per-thread-event-loop - Then again, all this would happen automatically if you used a queued connection (or an autoconnection) between your RMI thread and the gui objects that you need to update. Say that you had an RMI response handler that was constructed as part of your GUI thread and signals to this one. Then when RMI calls take place you emit signals that trigger slots in the RMI response handler. - Gunnar
import com.trolltech.qt.core.*;
import com.trolltech.qt.core.*;
public class InvokeLater {
public static class Invokable extends QObject {
public Invokable() {
moveToThread(QCoreApplication.instance().thread());
}
}
public static void main(String args[]) {
// Set up
QCoreApplication.initialize(args);
new Thread() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
QCoreApplication.postEvent(new Invokable() {
public boolean event(QEvent e) {
// Print out a message
System.out.println("Quit event triggered...");
// Exit the event loop
QCoreApplication.quit();
return true;
}
}, new QEvent(QEvent.User + 1));
}
}.start();
// Post the event...
// Spin the event loop.
QCoreApplication.exec();
}
}