Trolltech Home | Qt-jambi-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 1

Qt-jambi-interest Archive, August 2006
A couple of more feedbacks


Message 1 in thread

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


Message 2 in thread

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


Message 3 in thread

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


Message 4 in thread

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



Message 5 in thread

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.


Message 6 in thread

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


Message 7 in thread

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.


Message 8 in thread

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>


Message 9 in thread

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


Message 10 in thread

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();
   }
}