Domanda

Ho un'app Java che mette un'icona nel Systray con un menu di clic destro. Quando lo eseguo dall'IDE (netbeans) funziona correttamente. Ma quando lo costruisco ed eseguo il file jar mette l'icona nel systray ma quando faccio clic con il pulsante destro del mouse su di esso, non ha un menu contestuale.

Ecco un po 'di codice. Qualsiasi aiuto apprezzato. Ho controllato la versione della piattaforma e la versione console di Java ed entrambi sembrano essere uguali.

package abaxis;

import java.awt.AWTException;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;

public class Systray
{
    private TrayIcon trayIcon = null;
private Image databaseimage;
private Image databaseDisconnectedImage;
public PopupMenu popup;
private ActionListener exitListener;
private ActionListener settingsListener;
private ActionListener connectListener;
private ActionListener disconnectListener;
private static Systray instance;
private static Abaxis abaxis = null;

private SystemTray tray;

private MenuItem connectItem;
private MenuItem settingsItem; 
private MenuItem exitItem;
private MenuItem disconnectItem;

public Systray() 
{
    // create a action listener to listen for default action executed on the tray icon
    exitListener = new ActionListener() {
        public void actionPerformed(ActionEvent e) 
        {
            System.exit(0);
        }
    };
    settingsListener = new ActionListener() {
        public void actionPerformed(ActionEvent e) 
        {
            //New Jframe.
            JFrame settingsJFrame = new AbaxisSettingsForm();
            settingsJFrame.setVisible(true);
        }
    };
    connectListener = new ActionListener() {
        public void actionPerformed(ActionEvent e) 
        {
            //Start the application.
            abaxis.connect();
            setConnectedItems();
        }
    };
    disconnectListener = new ActionListener() {
        public void actionPerformed(ActionEvent e) 
        {
            //Discconect the application.
            abaxis.disconnect();
            setDisconnectedItems();
        }
    };
}

public static Systray getSystray()
{
    if(instance == null)
    {
        instance = new Systray();
        instance.init();
    }
    return instance;
}

public void init()
{
    // get the SystemTray instance
    tray = SystemTray.getSystemTray();
    // load Images
        databaseimage = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/images/database.png"));
        databaseDisconnectedImage = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/images/database_delete.png"));
    // create a popup menu
    this.popup = new PopupMenu();

    // create menu item for the default action
    connectItem = new MenuItem("Connect");
    connectItem.addActionListener(connectListener);
    settingsItem = new MenuItem("Settings");
    settingsItem.addActionListener(settingsListener);
    exitItem = new MenuItem("Exit");
    exitItem.addActionListener(exitListener);
    disconnectItem = new MenuItem("Disconnect");
    disconnectItem.addActionListener(disconnectListener);       

    // set the TrayIcon properties
    //trayIcon.addActionListener(exitListener);
    // construct a TrayIcon
    trayIcon = new TrayIcon( databaseimage, "Abaxis", this.popup );
    // add the tray image
    try 
    {
        tray.add(trayIcon);
    } 
    catch (AWTException e) 
    {
        System.err.println(e);
    }

    try 
    {
        abaxis = Abaxis.start();
    } 
    catch (Exception e)
    {
        System.out.println(e.getMessage());
    }

    if(abaxis.isConnected())
    {
        //Set all the stuff if its connected.
        setConnectedItems();
    } 
    else
    {
        //Set all the stuff if its disconnected.
        setDisconnectedItems();
    }
}

private void setConnectedItems()
{
    this.popup.removeAll();
    this.popup.add(disconnectItem);
    this.popup.add(settingsItem);
    this.popup.add(exitItem);
    this.updateImage(databaseimage);

}

private void setDisconnectedItems()
{
    this.popup.removeAll();
    this.popup.add(connectItem);
    this.popup.add(settingsItem);
    this.popup.add(exitItem);
    this.updateImage(databaseDisconnectedImage);
}

public void updateImage(Image x)
{
    if (this.trayIcon != null) 
    {
         this.trayIcon.setImage(x);
    }
}

}

Grazie sono riuscito a scoprire che era un problema con un barattolo mancante. Ma il file jar sembra essere nella cartella lib. Quindi non so perché abbia un winge. Stacktrace:

java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path thrown while loading gnu.io.RXTXCommDriver
    Exception in thread "main" java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path
    at java.lang.ClassLoader.loadLibrary(Unknown Source)
    at java.lang.Runtime.loadLibrary0(Unknown Source)
    at java.lang.System.loadLibrary(Unknown Source)
    at gnu.io.CommPortIdentifier.<clinit>(CommPortIdentifier.java:123)
    at abaxis.Abaxis.connectToBloodMachine(Abaxis.java:114)
    at abaxis.Abaxis.connect(Abaxis.java:90)
    at abaxis.Abaxis.init(Abaxis.java:76)
    at abaxis.Abaxis.start(Abaxis.java:53)
    at abaxis.Systray.init(Systray.java:141)
    at abaxis.Systray.getSystray(Systray.java:88)
    at abaxis.Abaxis.main(Abaxis.java:279)
È stato utile?

Soluzione

RXTX funziona con i driver che dipendono dal sistema operativo che è in esecuzione. Questi driver sono dotati di libreria RXTX e sono:

  • librxtxSerial.so e librxtxParallel.so per Linux.
  • librxtxSerial.dll e librxtxParallel.dll per finestre.
  • librxtxSerial.jnilib per Mac

Questo link Ha le istruzioni per installare correttamente questi driver e questa domanda: java.lang.unsatintifidedlinkerror: nessun rxtxserial in java.library.path Ha diverse soluzioni alternative per risolvere questo tipo di eccezione.

Tuttavia tutti presumono che tu abbia accesso a % Java_home % percorso o sai dove si trovano i driver, il che va bene se stai lavorando sul tuo computer ma non va bene se è necessario distribuire la tua app. In questo caso, basta copiare i file del driver nella stessa cartella in cui il tuo jar è posto. Devi vedere qualcosa del genere per sapere che funziona correttamente:

Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7

Aggiornare

Di recente ho notato che Linux non include l'attuale directory di lavoro in java.library.path proprietà. Di conseguenza, se si aggiunge semplicemente librxtxSerial.so nella cartella app che ottieni ancora UnsatisfiedLinkError. Ancora una volta, è possibile impostare questa proprietà quando si esegue l'applicazione tramite la riga di comando in questo modo:

java -jar -Djava.library.path=/path/to/lib

Oppure puoi usare un approccio hacky spiegato qui: Impostazione "java.library.path" a livello di programmazione. Questo approccio non è sicuro e non lo consiglio se hai accesso per implementare un'altra soluzione alternativa, ma l'ho provato e funziona:

String javaLibraryPath = System.getProperty("java.library.path");

if(!javaLibraryPath.contains(File.pathSeparator + "." + File.pathSeparator)){

    StringBuilder sb = new StringBuilder(javaLibraryPath).append(File.pathSeparator).append(".");
    // The line above appends "." (current directory) to the library path
    // Of course 'rxtxSerial.so' must be placed in the current directory

    System.setProperty("java.library.path", sb.toString());

    try {
        Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
        sysPathsField.setAccessible(true);
        sysPathsField.set(null, null);// Setting this field to null will force a reevaluation of 
                                      // the library path as soon as loadLibrary() is called

    } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
        ex.printStackTrace();
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top