Bonjour,

Ayant moi-même bien souffert pour intégrer un composant SWING dans l'environnement SWT, sous Eclipse 3.8.2, pour qu'il fonctionne en Java 1.7 sous Macintosh, je me propose de vous indiquer comment procéder à cette intégration. Il me reste un problème à régler, concernant le Drag and Drop, que j'exposerai dans une autre discussion. La solution est applicable pour SWT hors d'Eclipse bien sûr.

Au préalable, je ne saurais que trop vous conseiller de procéder à l'intégration telle qu'indiquée sur ce lien, y compris si vous avez utilisé le plugin Albireo, qui n'est plus maintenu depuis Ganymède, en plus.

L'intégration que j'ai faite est inspirée d'un patch trouvé sur le bug tracker d'Eclipse. Pour ceux qui utilisent Eclipse 4, et qui peuvent attendre la release de Milestone 6 de la 4.3.3, ou qui utilisent directement SWT, il n'est peut-être pas nécessaire de faire l'intégration que j'ai faite. Toutefois, comme l'intégration que j'ai faite du patch n'a pas été suffisante pour régler tous les problèmes (en particulier de gestion de focus), cette discussion pourrait leur servir également.

J'ai, tout d'abord, créé une constante de type boolean qui j'ai appelée MAC_PATCH, que j'initialise à true, si le système d'exploitation est MacOSX et la version de java est 1.7.

Ensuite, j'ai ajouté le bloc static suivant à la classe d'intégration (EmbeddedSwingComposite) :

Code java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
static {    if ( MAC_PATCH ) {
        LOG.info("SWT_AWT Bridge: patching for Apple/Oracle MacOsX/JAVA7 bugs workaround" );
    SWT_AWT.embeddedFrameClass="sun.lwawt.macosx.CViewEmbeddedFrame";        
    }
}

Ceci est nécessaire pour que le bridge utilise la classe de Embedded Frame du JDK (ou OpenJDK), au lieu de celle du Java d'Apple.

Ensuite, ajouter le code suivante, dans la méthode createFrame() de la classe EmbeddedSwingComposite, entre la création de la frame, et l'initialisation du handler de contexte AWT :

Code java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
 
 
...
 
final Frame frame = SWT_AWT.new_Frame(this); // j'ai juste ajouté final à la ligne d'origine de createFrame
 
if (MAC_PATCH) {
 
 
    // patch du bug tracker Eclipse 4.3.2 (<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=374199" target="_blank">https://bugs.eclipse.org/bugs/show_bug.cgi?id=374199</a>)
 
    final Composite parent = AbstractSWTSwingNGComposite.this;
 
    // When display is disposed the frame is disposed in AWT EventQueue.
    // Force main event loop to run to let the frame finish dispose.
    final Display display = parent.getDisplay();
    display.addListener(SWT.Dispose, new Listener() {
        public void handleEvent(Event event) {
            while (frame.isDisplayable() && !display.isDisposed()) {
                if (!display.readAndDispatch()) {
                    display.sleep();
                }
            }
            //Frame finished dispose, the listener can be removed
            if (!display.isDisposed()) {
              display.removeListener(SWT.Dispose, this);
            }
        }
    });
 
    Listener listener = new Listener () {
        public void handleEvent (Event e) {
            switch (e.type) {
                      case SWT.Dispose:
                         getShell().removeListener (SWT.Activate, this);
                         getShell().removeListener (SWT.FocusOut, this);
                           break;
              case SWT.Activate:
                  if (!parent.isFocusControl()) return;
              // case géré par l'implémentation de la classe parente : case SWT.FocusIn:
                  EventQueue.invokeLater(new Runnable () {
                      public void run () {
                        if (frame.isActive()) return;
                        try {
                            Class clazz = frame.getClass();
                            Method method = clazz.getMethod("synthesizeWindowActivation", new Class[]{boolean.class});
                            if (method != null) method.invoke(frame, new Object[]{new Boolean(true)});
                            } catch (Throwable e) {
                                LOG.error("SWT_AWT ERROR",e);}
                            }
                      }
                  );
                  break;
              // case gérée par l'implémentation de la classe parente : case SWT.Deactivate:
              case SWT.FocusOut:
                  EventQueue.invokeLater(new Runnable () {
                      public void run () {
                          if (!frame.isActive()) return;
                          try {
                              Class clazz = frame.getClass();
                              Method method = clazz.getMethod("synthesizeWindowActivation", new Class[]{boolean.class});
                              if (method != null) method.invoke(frame, new Object[]{new Boolean(false)});
                          } catch (Throwable e) {
                              LOG.error("SWT_AWT ERROR",e);
                          }
                      }
                  });
                  break;
            }
        }
    };
 
 
    parent.addListener (SWT.Dispose, listener);
    parent.addListener (SWT.Activate, listener);
    parent.addListener (SWT.FocusOut, listener);
 
 
    // fin du patch du bug tracker Eclipse 4.3.2
 
 
    // les lignes suivantes sont nécessaire pour que la gestion du focus fonctionne correctement !!!
    frame.setVisible(false);
    frame.setVisible(true);    
 
 
    // autre partie reprise en partie du patch
    display.asyncExec(new Runnable() {
 
 
        @Override
        public void run() {
 
 
            if (parent.isDisposed()) return;
 
 
            final Rectangle clientArea = parent.getClientArea(); 
 
 
            try {
                Method method = frame.getClass().getMethod("validateWithBounds", new Class[] {int.class, int.class, int.class, int.class});
                if (method != null) method.invoke(frame, new Object[]{new Integer(clientArea.x), new Integer(clientArea.y), new Integer(clientArea.width), new Integer(clientArea.height)});
                parent.setFocus();
                if ( parent.isFocusControl() ) {
                    // le validateWithBounds fait perdre le focus au composant SWT, ce qui fait perdre le focus au composant AWT
                    // le fait de redonner le focus au compsant SWT ne redonne pas bizarrement le focus au composant AWT
                    EventQueue.invokeLater(new Runnable () {
                        public void run () {
                            if (!frame.isActive()) return;
                            // ce code redonne le focus à la frame AWT (un requestFocusInWindows est insuffisant, bizarrement    
                            try {
                                Class clazz = frame.getClass();
                                Method method = clazz.getMethod("synthesizeWindowActivation", new Class[]{boolean.class});
                                if (method != null) method.invoke(frame, new Object[]{new Boolean(true)});
                            } catch (Throwable e) {LOG.error("SWT_AWT ERROR",e);}
 
 
                            if ( awtContext.getSwingComponent()!=null ) {
                                awtContext.getSwingComponent().requestFocusInWindow();
                            }
                        }
                    });
                }
 
 
            } catch (Throwable e) {
                LOG.error("SWT_AWT ERROR",e);
            }
 
 
        }
    });
 
 
}
 
awtContext = new AwtContext(frame); // ligne dans le code d'origine de createFrame 
 
...

Voilà. Bien sûr, si vous voyez une manière de faire plus simple, n'hésitez pas à m'en faire part.