Qt Jambi

I've been looking at excuses to learn Qt for some time now, but could not really justify to myself going back to C++, but now with jambi, you can write Qt programs in java. More importantly, with the Qt Jambi to Awt bridge, you can melt swing components in Qt windows and Qt widgets in swing components. Here is a picture of some swing components in a QWidget


and another one with some Qt components in a swing frame

qtinawt.png See this code snippet for how it is easy to do:
12         QGridLayout layout = new QGridLayout(this);
14         // A few Qt widgets
15         layout.addWidget(new QLabel("First name:"), 0, 0);
16         layout.addWidget(new QLineEdit(), 0, 1);
17         layout.addWidget(new QLabel("Last name:"), 1, 0);
18         layout.addWidget(new QLineEdit(), 1, 1);
20         // The AWT part of the GUI
21         {
22             JPanel panel = new JPanel();
24             panel.setLayout(new GridLayout(1, 2));
26             panel.add(new JLabel("Social security number:"));
27             panel.add(new JTextField());
29             // Add the AWT panel to Qt's layout
30             layout.addWidget(new QComponentHost(panel), 2, 0, 1, 2);
31         }

beyond hello world

So I wanted to go beyond the hello world level, and try to integrate jedit in a Qt window. If it works, this could lead to interesting things such as distributing jedit dockable windows through Qt system QtDockWidget which should be easy based on the new abstract docking window manager service in jedit, or using Qt widgets to extend jedit, ...

I managed to embed jedit in a Qt window, although I had to trick jedit to not build a JFrame when a view is created, I've used the same trick as in biocep workbench, which is writing a small patch to the jEdit class so that the view (which is a JFrame) is never set to visible, and its content pane borrowed by some other component, in that case, a Qt component. Here is how everything looks like:

$ tree
|-- build.properties
|-- build.xml
|-- jambidocking
|   |-- data
|   |   |-- JambiDockingPlugin.props
|   |   |-- actions.xml
|   |   `-- services.xml
|   `-- src
|       `-- JambiDocking
|           |-- JambiDockingDockingLayout.java
|           |-- JambiDockingWindowManager.java
|           |-- Plugin.java
|           `-- Provider.java
|-- src
|   |-- com
|   |   `-- addictedtor
|   |       `-- jambijedit
|   |           `-- JambiJedit.java
|   `-- org
|       `-- gjt
|           `-- sp
|               `-- jedit
|                   `-- jEdit.java
`-- src_qtjambiawtbridge
    `-- com
        `-- trolltech
            `-- research
                `-- qtjambiawtbridge
                    |-- QComponentHost.java
                    |-- QWidgetHost.java
                    |-- QWidgetWrapper.java
                    |-- QtJambiAwtBridge.java
                    |-- RedirectContainer.java
                    |-- examples
                    |   |-- AwtInQt.java
                    |   `-- QtInAwt.java
                    `-- generated
                        |-- QComponentHostNative.java
                        |-- QWidgetHostNative.java
                        `-- QtJambi_LibraryInitializer.java

19 directories, 21 files

Apart from the code of the Qt Jambi to Awt bridge, there is the patched jEdit.java, the JambiJedit.java file which basically creates a Qt main window and sets jedit as its central widget, and the jambidocking directory which contains the start of an implementation of jedit's shiny new DockableWindowManager system (more on that later)


The good news is that it works, the bad news is that it sort of works

Bad things start to happen when I tried to implement the DockableWindowManager system, here is the kind of messages I get, I suppose the issue is that jedit uses threading quite a lot and Qt is not happy about it

     [java] Exception in thread "main" 7:25:23 PM [main] [error] main: QObject used from outside its own thread, object=com::trolltech::research::qtjambiawtbridge::QComponentHost(0xa305370) , objectThread=Thread[AWT-EventQueue-0,6,main], currentThread=Thread[main,5,main]
     [java] 7:25:23 PM [main] [error] main:  at com.trolltech.qt.GeneratorUtilities.threadCheck(GeneratorUtilities.java:56)
     [java] 7:25:23 PM [main] [error] main:  at com.trolltech.research.qtjambiawtbridge.generated.QComponentHostNative.event(QComponentHostNative.java:37)
     [java] 7:25:23 PM [main] [error] main:  at com.trolltech.research.qtjambiawtbridge.QComponentHost.event(QComponentHost.java:35)
     [java] 7:25:23 PM [main] [error] main:  at com.trolltech.qt.gui.QApplication.exec(Native Method)
     [java] 7:25:23 PM [main] [error] main:  at com.addictedtor.jambijedit.JambiJedit.main(Unknown Source)
     [java] QPixmap: It is not safe to use pixmaps outside the GUI thread
     [java] QPixmap: It is not safe to use pixmaps outside the GUI thread
     [java] QPixmap: It is not safe to use pixmaps outside the GUI thread
     [java] QPixmap: It is not safe to use pixmaps outside the GUI thread
     [java] QPixmap: It is not safe to use pixmaps outside the GUI thread
     [java] QPixmap: It is not safe to use pixmaps outside the GUI thread

Anyway, I zipped it up here in case someone else wants to have a go. It is not quite there yet but at least now I have my excuse to learn Qt, which was the original point ...