2015-09-05 33 views
6

Sto usando la versione corrente di SWT per creare le mie applicazioni e voglio eseguirle con Mac OS X (Yosemite).
Il mio problema ora è che non sono in grado di acquisire i clic sugli elementi "Informazioni", "Preferenze" e "Esci" che sono stati aggiunti automaticamente alla mia applicazione.
Ho già cercato molto e ho trovato la seguente classe che mi sembra molto utile per me http://www.transparentech.com/files/CocoaUIEnhancer.java.Cattura about, preferences ed esci dal menu

E questo è il mio codice per inizializzarlo:

import org.eclipse.swt.*; 
import org.eclipse.swt.widgets.*; 

public class Test { 
    private Display display; 
    private Shell shell; 

    public Test(Display display) { 
    this.display = display; 
    initUI(); 
    } 

    public void open() { 
    shell.open(); 
    while (!shell.isDisposed()) { 
     if (!display.readAndDispatch()) { 
     display.sleep(); 
     } 
    } 
    } 

    private void initUI() { 
    shell = new Shell(display); 
    shell.setSize(808, 599); 
    shell.setText("Test"); 

    AboutHandler aboutHandler = new AboutHandler(); 
    PreferencesHandler preferencesHandler = new PreferencesHandler(); 
    QuitHandler quitHandler = new QuitHandler(); 

    CocoaUIEnhancer uienhancer = new CocoaUIEnhancer("Test"); 
    uienhancer.hookApplicationMenu(display, quitHandler, aboutHandler, preferencesHandler); 
    } 

    private class AboutHandler implements Listener { 
    public void handleEvent(Event e) { 
    } 
    } 

    private class PreferencesHandler implements Listener { 
    public void handleEvent(Event e) { 
    } 
    } 

    private class QuitHandler implements Listener { 
    public void handleEvent(Event e) { 
    } 
    } 
} 

posso compilarlo senza errori, ma se comincio il programma, allora mi metterò la seguente eccezione:

Exception in thread "main" java.lang.NoSuchMethodError: actionProc 
    at org.eclipse.swt.internal.Callback.bind(Native Method) 
    at org.eclipse.swt.internal.Callback.<init>(Unknown Source) 
    at org.eclipse.swt.internal.Callback.<init>(Unknown Source) 
    at org.eclipse.swt.internal.Callback.<init>(Unknown Source) 
    at CocoaUIEnhancer.initialize(CocoaUIEnhancer.java:124) 
    at CocoaUIEnhancer.hookApplicationMenu(CocoaUIEnhancer.java:92) 
    at Test.initUI(Test.java:50) 
    at Test.<init>(Test.java:18) 

E 'probabilmente un errore nelle librerie native ma non riesco a capirlo!

risposta

8

Non ho utilizzato lo CocoaUIEnhancer, poiché causava anche problemi.

Così qui è quello che ho finito per fare le mie applicazioni:

/** 
* Convenience method that takes care of special menu items (About, Preferences, Quit) 
* 
* @param name  The name of the menu item 
* @param parent The parent {@link Menu} 
* @param listener The {@link Listener} to add to the item 
* @param id  The <code>SWT.ID_*</code> id 
*/ 
private void addMenuItem(String name, Menu parent, Listener listener, int id) 
{ 
    if (OSUtils.isMac()) 
    { 
     Menu systemMenu = Display.getDefault().getSystemMenu(); 

     for (MenuItem systemItem : systemMenu.getItems()) 
     { 
      if (systemItem.getID() == id) 
      { 
       systemItem.addListener(SWT.Selection, listener); 
       return; 
      } 
     } 
    } 

    /* We get here if we're not running on a Mac, or if we're running on a Mac, but the menu item with the given id hasn't been found */ 
    MenuItem item = new MenuItem(parent, SWT.NONE); 
    item.setText(name); 
    item.addListener(SWT.Selection, listener); 
} 

Basta chiamare con SWT.ID_PREFERENCES, SWT.ID_ABOUT e SWT.ID_QUIT rispettivamente. Fornire il nome di una voce di menu di fallback, un fallback Menu e l'attuale Listener che si desidera aggiungere alla voce di menu.

Così, per esempio:

addMenuItem("Quit", myMenu, new Listener() 
{ 
    @Override 
    public void handleEvent(Event event) 
    { 
     // Close database connection for example 
    } 
}, SWT.ID_QUIT); 
+0

Una soluzione perfetta: semplice e immediata! Anche le voci del menu possono essere rinominate. Ma per quanto riguarda l'elemento "SWT"? Come cambiare il suo testo? Display.setAppName non funziona per me a causa di un motivo sconosciuto. Ci sono altri modi per farlo? –

+0

Il mio errore. Display.setAppName() funziona correttamente. Non avrei dovuto fare nulla con il display prima di chiamare setAppName(). Doveva essere la prima riga del mio codice. –

+0

@ m.vokhm Sì, stavo per pubblicarlo. Sono contento che stia lavorando per te ora. – Baz

2

sembra che questo l'actionProc

int actionProc(int id, int sel, int arg0) 

in CocoaUIEnhancer probabilmente ha bisogno di usare long piuttosto che int per gli argomenti di lavorare con 64 bit SWT.

+0

E 'stata una buona idea, ma purtroppo non aiuta. Ho cambiato i parametri id, sel, arg0 da int a long ma l'eccezione è sempre la stessa e lo stacktrace è lo stesso. – altralaser

2

è necessario modificare CocoaUIEnhancer.java, per farlo funzionare con l'applicazione SWT pura come descritto in this tutorial:

  • modificare il metodo getProductName() per restituire una stringa quando nessun prodotto viene trovato (invece di null)
  • Avvolgere il codice a hookWorkbenchListener() in un try-catch (IllegalStateException e) bloccare
  • Avvolgere il codice a modifyShells() in un try-catch (IllegalStateException e) bloccare
  • aggiungere del codice al metodo actionProc (...), per far apparire una finestra di dialogo About-e-Dialog Preferenze (dal momento che non stiamo usando i comandi):
static long actionProc(long id, long sel, long arg0) throws Exception { 
     // ... 
     else if (sel == sel_preferencesMenuItemSelected_) { 
      showPreferences(); 
     } else if (sel == sel_aboutMenuItemSelected_) { 
      showAbout(); 
     } 
     return 0; 
    } 

    private static void showAbout() { 
     MessageDialog.openInformation(null, "About...", 
       "Replace with a proper about text/dialog"); 
    } 

    private static void showPreferences() { 
     System.out.println("Preferences..."); 
     PreferenceManager manager = new PreferenceManager(); 
     PreferenceDialog dialog = new PreferenceDialog(null, manager); 
     dialog.open(); 
    } 


    // ... 

Infine, aggiungiamo le seguenti righe al nostro metodo main():

public static final String APP_NAME = "MyApp"; 

public static void main(String[] args) { 
    //in your case change the Test constructor 
    Display.setAppName(APP_NAME); 
    Display display = Display.getDefault(); 

    //insert in initUI method call the earlysetup 
    if (SWT.getPlatform().equals("cocoa")) { 
     new CocoaUIEnhancer().earlyStartup(); 
    } 

    Shell shell = new Shell(display); 
    shell.setText(APP_NAME); 
    ... 
} 

codice Citato.