AWT AWT TrayIcon in Ubuntu

Status
Nicht offen für weitere Antworten.

Topfen

Mitglied
Hy Leute,

ich versuche eine Java-Anwendung mit einem TrayIcon auszustatten, dabei wird mir jedoch jedes mal gesagt das mein OS (Ubuntu 8.10 mit JDK6) keine TrayIcons unterstützt.

Hier mein Code:
Java:
public static void trayIcon(){
        ImageIcon icon = new ImageIcon("icon.gif");
        PopupMenu menu = new PopupMenu();

        MenuItem exit = new MenuItem("Server beenden");
        exit.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        menu.add(exit);

        try {
            SystemTray systemTray = SystemTray.getSystemTray();
            TrayIcon trayIcon = new TrayIcon(icon.getImage(), "TrayIcon", menu);
            systemTray.add(trayIcon);
        } catch (UnsupportedOperationException ex) {
            System.err.println("Not supported");
        } catch(AWTException ex){}
        
    }

Soweit ich gelesen habe müsste der Code stimmen und Ubuntu mit der Notification Area das Icon auch anzeigen, aber dem ist leider nicht so.
Ich höffe jemand hat eine Idee was nicht stimmen könnte.

topfen
 
Wie lautet denn die genaue Fehlermeldung? Warum ignorierst du AWTException komplett?

Ich hab sowohl mit jdic als auch Java6 das TrayIcon ohne Probleme unter Ubuntu 8.10 und 9.04 laufen ...
 
Es wird die UnsupportedOperationException in dem Aufruf von SystemTray.getSystemTray() geworfen.

Das mit der AWTException ist nur vorübergehend, da mein Programm noch nicht ganz fertig ist. Und soweit ich weiß nichts mit dem Problem zu tun hat.

topfen
 
Sun-JDK auf dem Ubuntu installieren. Da ist sicher ein OpenJDK oder IBM-JRE oder sowas drauf welches die TrayIcons nicht unterstützt.

Ebenius
 
Laut APT ist das neueste JDK von Sun installiert

Code:
topfen@topfen-desktop:~$ sudo apt-get install sun-java6-jdk
[sudo] password for topfen: 
Paketlisten werden gelesen... Fertig
Abhängigkeitsbaum wird aufgebaut       
Lese Status-Informationen ein... Fertig
sun-java6-jdk ist schon die neueste Version.
Die folgenden Pakete wurden automatisch installiert und werden nicht länger benötigt:
  automake1.4 gstreamer0.10-plugins-ugly glade-common gstreamer0.10-ffmpeg
  libsidplay1
Verwenden Sie »apt-get autoremove«, um sie zu entfernen.
0 aktualisiert, 0 neu installiert, 0 zu entfernen und 11 nicht aktualisiert.
topfen@topfen-desktop:~$
 
Bist Du sicher, dass Du nur das Sun-JRE drauf hast? Was sagt denn
Code:
java -version
... ?

Ebenius
 
Code:
topfen@topfen-desktop:~$ java -version
java version "1.6.0_13"
Java(TM) SE Runtime Environment (build 1.6.0_13-b03)
Java HotSpot(TM) Client VM (build 11.3-b02, mixed mode, sharing)
topfen@topfen-desktop:~$
 
Also ich programmiere auch unter Ubuntu und musste für meine Diplomarbeit ein TrayIcon verwenden was sich der Gegebenheit (Größe des Icons passt sich automatisch an die Größe der Menüleiste an) dynamisch anpasst und unter Linux und Windows läuft.

Ich hatte mir das damals aus einem Tutorial zusammengebastelt. Stelle Dir mal die drei Klassen zur Verfügung die u.a. auch ein komfortables Popup-Menü enthält. Du kannst Dir ja die wichtigsten Teile daraus kopieren.

Klasse: JTrayIcon.java
Java:
package quark.ui.tray;

import quark.listener.UIListener;

import java.awt.AWTEvent;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.AWTException;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JDialog;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.PopupMenuEvent;

/**
 * Ein Swing TrayIcon welches die regulären AWT-Komponenten überschreibt und
 * durch neue Swing-Komponenten ersetzt.
 */
public class JTrayIcon
{
    private JPopupMenu popupMenu;
    private JDialog trayParent;
    private TrayIcon trayIcon;   
    private ActionListener leftClickListener, leftDoubleClickListener, rightClickListener;
    
    /**
     * Konstruktor
     * Erzeugt eine Dialogbox für das PopupMenu, einPopupMenu, das TrayIcon
     * und erstellt das finale SystemTray.
     * 
     * @see quark.ui.tray.JTrayMenu
     * @see quark.ui.tray.JTrayImage
     */
    public JTrayIcon(UIListener uiListener) 
    {     
        try
        {
            trayIcon = new JTrayImage().setIcon();
        } 
        catch (IOException ex)
        {
            Logger.getLogger(JTrayIcon.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        trayParent = new JDialog();
        trayParent.setSize(0, 0);
        trayParent.setUndecorated(true);
        trayParent.setAlwaysOnTop(true);
        trayParent.setVisible(false);
        
        //PopupMenu erstellen
        popupMenu = new JTrayMenu().getPopupMenu(uiListener);        
        setTrayPopUp(popupMenu);
        
        //ClassCastException fix
        Toolkit.getDefaultToolkit().getSystemEventQueue().push( new PopupFixQueue(popupMenu) );
        
        SystemTray systemTray = SystemTray.getSystemTray();
        try 
        {
            systemTray.add(trayIcon);
        } 
        catch (AWTException e) 
        {
            e.printStackTrace();
        }
    }
    
    /**
     * Setzt ein PopupMenu in die Dialogbox und überschreibt die aktuellen
     * Listenerklassen.
     * 
     * @param trayMenu JPopupMenu
     */
    public void setTrayPopUp(JPopupMenu trayMenu) 
    {
        this.popupMenu = trayMenu;
        
        popupMenu.addPopupMenuListener(new PopupMenuListener() 
        {
            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) 
            {
            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) 
            {
                trayParent.setVisible(false);
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) 
            {
                trayParent.setVisible(false);
            }
        });
//        popupMenu.setVisible(true);
//        popupMenu.setVisible(false);
        
        //Listener registrieren
        trayIcon.addMouseListener(new MouseAdapter() 
        {
            @Override
            public void mouseClicked(MouseEvent e) 
            {
                if (SwingUtilities.isLeftMouseButton(e)) 
                {
                    if (e.getClickCount() == 1 && leftClickListener != null)
                        leftClickListener.actionPerformed(null);
                    else if (e.getClickCount() == 2 && leftDoubleClickListener != null)
                        leftDoubleClickListener.actionPerformed(null);
                }
                
                else if (SwingUtilities.isRightMouseButton(e)) 
                {
                    if (e.getClickCount() == 1 && rightClickListener != null)
                        rightClickListener.actionPerformed(null);
                    showPopup(e.getPoint());
                }
            }

            @Override
            public void mousePressed(MouseEvent e) 
            {
                if (e.isPopupTrigger()) 
                {
                    if (SwingUtilities.isRightMouseButton(e) && rightClickListener != null)
                        rightClickListener.actionPerformed(null);
                    showPopup(e.getPoint());
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) 
            {
                if (e.isPopupTrigger()) 
                {
                    if (SwingUtilities.isRightMouseButton(e) && rightClickListener != null)
                        rightClickListener.actionPerformed(null);
                    showPopup(e.getPoint());
                }
            }
        });
    }
    
    /**
     * Methode zum zeigen des PopupMenus.
     * 
     * @param p Position des Listeners
     */
    private void showPopup(final Point p) 
    {
        trayParent.setVisible(true);
        trayParent.toFront();

        SwingUtilities.invokeLater(new Runnable() 
        {
            @Override
            public void run() 
            {
                Point p2 = computeDisplayPoint(p.x, p.y, popupMenu.getPreferredSize());
                popupMenu.show(trayParent, p2.x - trayParent.getLocation().x, p2.y - trayParent.getLocation().y);
            };
        });
    }

    /**
     * Berechnet die optimale Position für die Anzeige des PopupMenus.
     */
    private Point computeDisplayPoint(int x, int y, Dimension dim)
    {
        if (x - dim.width > 0)
            x -= dim.width;
        if (y - dim.height > 0)
            y -= dim.height;
        return new Point(x, y);
    }
    
    
    //BaloonTips
    //==========================================================================
    
    public void showDisplayMessage(String header, String message)
    {
        trayIcon.displayMessage( header,
                                 message,
                                 TrayIcon.MessageType.NONE );
    }
    
    public void showDisplayErrorMessage(String header, String message)
    {
        trayIcon.displayMessage( header,
                                 message,
                                 TrayIcon.MessageType.ERROR );
    }
    
    public void showDisplayInfoMessage(String header, String message)
    {
        trayIcon.displayMessage( header,
                                 message,
                                 TrayIcon.MessageType.INFO );
    }
    
    public void showDisplayWarningMessage(String header, String message)
    {
        trayIcon.displayMessage( header,
                                 message,
                                 TrayIcon.MessageType.WARNING );
    }
    
    //Sonstiges
    //==========================================================================
    
    /**
     * ClassCastException FIX
     */
    public class PopupFixQueue extends EventQueue 
    {
        private JPopupMenu popup;

        public PopupFixQueue(JPopupMenu popup)
        {
            this.popup = popup;
        }

        protected void dispatchEvent(AWTEvent event) 
        {
            try 
            {
                super.dispatchEvent(event);
            } 
            catch (Exception ex) 
            {
                if (event.getSource() instanceof TrayIcon) 
                {
                    popup.setVisible(false);
                }
            }
        }
    }
}

Klasse: JTrayImage.java
Java:
package quark.ui.tray;

import quark.dh.Constants;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.TrayIcon;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;

/**
 * Ermittel anhand der zur Verfügung stehenden Größe in der Statusleiste des 
 * Betriebssystems die optimale Größe und erstellt ein TrayIcon.
 */
public class JTrayImage 
{
    private TrayIcon trayIcon;
    
    /**
     * Erstellt ein TrayIcon.
     * 
     * @return TrayIcon
     * @throws java.io.IOException
     */
    public TrayIcon setIcon() throws IOException
    {
        try 
        {       
            Dimension trayIconSize = getTrayIconSize();
            BufferedImage trayIconImage = null;
            
            String tooltip = Constants.NAME + " " + Constants.VERSION;

            //Sonderregel für Linux mit Gnome (braucht nicht konvertiert werden)
            if(trayIconSize.width == 24 & trayIconSize.height <= 24)
            {
                trayIconImage = ImageIO.read(getClass().getResource("/quark/img/trayicon/trayicon24.png"));
            }
            else if(trayIconSize.height > 16 && trayIconSize.height <= 22)
            {
                trayIconImage = scaleIconToBufferedImage(ImageIO.read(getClass().getResource("/quark/img/trayicon/trayicon22.png")),
                    trayIconSize.width-1, trayIconSize.height-1, BufferedImage.TYPE_INT_ARGB);
            }
            else if(trayIconSize.height > 22 && trayIconSize.height <= 32)
            {
                trayIconImage = scaleIconToBufferedImage(ImageIO.read(getClass().getResource("/quark/img/trayicon/trayicon32.png")),
                    trayIconSize.width-1, trayIconSize.height-1, BufferedImage.TYPE_INT_ARGB);
            }
            else 
            {
                trayIconImage = ImageIO.read(getClass().getResource("/quark/img/trayicon/trayicon16.png"));
            }

            trayIcon = new TrayIcon(trayIconImage, tooltip);
        }
        
        catch(Exception exp) 
        {
            System.out.println("Fehlerhaftes TrayIcon");
            trayIcon = new TrayIcon(ImageIO.read(getClass().getResource("/quark/img/trayicon/trayicon16.png")));
        }
        
        return trayIcon;
    }
    
    /**
     * Holt sich über die SystemTray Klasse die aktuell zur Verfügung stehende
     * Größe für das TrayIcon.
     * 
     * @return Dimension Die zur verfügung stehende Größe
     */
    public Dimension getTrayIconSize() 
    {
        try 
        {
            Class<?> clazz = Class.forName("java.awt.SystemTray");

            if(clazz != null) 
            {
                Object o = clazz.getMethod("getSystemTray",new Class[] {}).invoke(clazz,new Object[] {});
                return (Dimension)clazz.getMethod("getTrayIconSize", new Class[] {}).invoke(o, new Object[] {});
            }
        }
        catch(Exception e) 
        {
            e.printStackTrace();
        }

        return null;
    }
    
    /**
     * Skalliert ein Image auf eine fest definierte Größe.
     * Scales an image to a specific size and returns an BufferedImage
     * 
     * @param img Ursprungsbild
     * @param x maximale Breite
     * @param y maximale Höhe
     * 
     * @return skalliertes BufferedImage
     */
    public static BufferedImage scaleIconToBufferedImage(BufferedImage img, int x, int y) 
    {
        return scaleIconToBufferedImage(img, x, y, img.getType());
    }
  
    /**
   * Scales an image to a specific size and returns an BufferedImage
   * 
   * @param img
   *          Scale this IMage
   * @param x
   *          new X-Value
   * @param y
   *          new Y-Value
   * @param type The type of the image.
   * @return Scaled BufferedImage
   * 
   * @since 2.7
   */
    public static BufferedImage scaleIconToBufferedImage(BufferedImage img, int x, int y, int type) 
    {
        Image image = img.getScaledInstance(x, y, Image.SCALE_SMOOTH);

        BufferedImage im = new BufferedImage(x, y, type);

        Graphics2D g2 = im.createGraphics();
        g2.drawImage(image, null, null);
        g2.dispose();

        im.flush();
        return im;
    }
}

Klasse: JTrayMenu.java
Java:
package quark.ui.tray;

import quark.listener.UIListener;

import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;

/**
 * Ein PopupMenu auf Swingbasis für das JTrayIcon.
 */
public class JTrayMenu 
{  
    private JPopupMenu popupMenu;
    private JMenu menu;
    private JMenuItem menuItem;
    
    /**
     * Erstellt ein PopupMenu.
     * 
     * @param uiListener UIListener
     * 
     * @return popupMenu
     */
    public JPopupMenu getPopupMenu(UIListener uiListener)
    {
        popupMenu = new JPopupMenu();
        
        //Import
        menuItem = new JMenuItem("Messwerte importieren");
        menuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/quark/img/16/import16.png"))); // NOI18N
        menuItem.setActionCommand("import");
        menuItem.addActionListener(uiListener);
        popupMenu.add(menuItem);
        
        //Separator
        popupMenu.add(new JSeparator());
        
        //Regelkarten
        menu = new JMenu("Regelkarten");
        
            menuItem = new JMenuItem("Mittelwertkarte (xQuer)");
            menuItem.setActionCommand("xQuer");
            menuItem.addActionListener(uiListener);
            menu.add(menuItem);
            
            menuItem = new JMenuItem("Mediankarte (xTilde)");
            menuItem.setActionCommand("xTilde");
            menuItem.addActionListener(uiListener);
            menu.add(menuItem);
            
            menuItem = new JMenuItem("Standardabweichungskarte (s)");
            menuItem.setActionCommand("s");
            menuItem.addActionListener(uiListener);
            menu.add(menuItem);
            
            menuItem = new JMenuItem("Spannweitenkarte (R)");
            menuItem.setActionCommand("R");
            menuItem.addActionListener(uiListener);
            menu.add(menuItem);
            
            menuItem = new JMenuItem("Urwertekarte (x)");
            menuItem.setActionCommand("x");
            menuItem.addActionListener(uiListener);
            menu.add(menuItem);
            
            //Separator
            menu.add(new JSeparator());
            
            menuItem = new JMenuItem("xQuer/s-Regelkarte");
            menuItem.setActionCommand("xQuers");
            menuItem.addActionListener(uiListener);
            menu.add(menuItem);
            
            menuItem = new JMenuItem("xTilde/R-Regelkarte");
            menuItem.setActionCommand("xTildeR");
            menuItem.addActionListener(uiListener);
            menu.add(menuItem);

            //Separator
            menu.add(new JSeparator());

            menuItem = new JMenuItem("Individuelle Kombination");
            menuItem.setActionCommand("chartCombChoise");
            menuItem.addActionListener(uiListener);
            menu.add(menuItem);
            
        popupMenu.add(menu);
        
        //Eventliste
        menuItem = new JMenuItem("Eventliste");
        menuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/quark/img/16/eventlist16.png"))); // NOI18N
        menuItem.setActionCommand("eventList");
        menuItem.addActionListener(uiListener);
        popupMenu.add(menuItem);
        
        //Sichprobenauswertung
        menuItem = new JMenuItem("Sichprobenauswertung");
        menuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/quark/img/16/mathvalue16.png"))); // NOI18N
        menuItem.setActionCommand("mathList");
        menuItem.addActionListener(uiListener);
        popupMenu.add(menuItem);
        
        //Histogramm
        menuItem = new JMenuItem("Histogramm");
        menuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/quark/img/16/histogramm16.png"))); // NOI18N
        menuItem.setActionCommand("histogramm");
        menuItem.addActionListener(uiListener);
        popupMenu.add(menuItem);
        
        //Separator
        popupMenu.add(new JSeparator());
        
        //Sichprobenauswertung
        menuItem = new JMenuItem("Einstellungen");
        menuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/quark/img/16/config16.png"))); // NOI18N
        menuItem.setActionCommand("config");
        menuItem.addActionListener(uiListener);
        popupMenu.add(menuItem);
        
        //Separator
        popupMenu.add(new JSeparator());
        
        //Sichprobenauswertung
        menuItem = new JMenuItem("QuaRK beenden");
        menuItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/quark/img/16/exit16.png"))); // NOI18N
        menuItem.setActionCommand("exit");
        menuItem.addActionListener(uiListener);
        popupMenu.add(menuItem);
        
        return popupMenu;
    }
}

greetz

der Doc
 
Zuletzt bearbeitet:
Danke Dr. Gibble, aber dein Code wird mir auch nicht helfen...

In JTrayIcon.java Zeile 69 wird wieder die UnsupportedOperationException geworfen werden

-topfen
 
Kann es evtl. sein das Du das TrayIcon/SystemTray zu früh aufrufst vor allem anderen?

Zum Zeitpunkt des Autostarts existiert das SystemTray noch nicht und wirft daher wahrscheinlich die Exception. Schau mal mit
Java:
System.out.println(SystemTray.isSupported());
nach ob die Funktion schon bereitsteht.

Ich manage das so das die Main-Methode immer erst einen GUIManager startet der die einzelnen Oberflächen initialisiert. Dort wird zuerst die HauptGUI initialisiert und erst im Anschluss das SystemTray.

Sonst setzte die Initialisierung mal testweise in einer Schleife die (ca. 50x) das SystemTray initialisieren will bis keine Exception mehr geworfen wird. Wenn es nach dem 5-10 Versuch funktioniert lag es nur daran das Du das TrayIcon zu früh gestartet hast.
 
@Doc

Egal wann ich SystemTray aufrufe immer dasselbe Ergebnis, sogar eine Wartezeit hat nix gebracht

@Wildcard

Beides...immer das gleiche Ergebnis
 
Schalte testhalber mal die Desktopeffekte ab.
Mit welcher JRE startest du in der IDE?
Mach mal sudo update-alternatives --config java
Ist die Sun JRE als Default markiert?
 
Probleme mit Compiz hatte ich bei der google-Suche auch gefunden. Allerdings stand überall, dass das Problem in Java 6 Update 10 behoben sei. Offensichtlich wohl doch nicht...

Ebenius
 
Ich hab's jetzt extra nochmal versucht. Kein Problem mit dem TrayIcon mit Ubuntu 9.04, aktiviertem Compiz und Java 6u13
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Zurück
Oben