2014年2月3日 星期一

Java System Tray

不論Sun Solaris、Microsoft Windows、Linux、Gnome、KDE等作業系統,在支援圖形化使用者界面上,均提供類似的功能,例如工作列 (Task Bar)、桌面 (Desktop) 等,其中較特別的功能則是工作列之系統紙匣 (System Tray)。

系統紙匣預設位於工作列的右方、螢幕的右下角。一般的程式在按下視窗縮小鍵之後,會縮小並以圖像形式出現於工作列上。但有些程式卻將圖像縮放於系統紙匣內,有如常駐程式般,方便使用者點選使用。

系統紙匣可由以下類別組成,其中SystemTrayTrayIcon類別為Java SE 6.0新增之類別:
  • 系統紙匣 (System Tray):java.awt.SystemTray類別。
  • 紙匣圖像 (Tray Icon):java.awt.TrayIcon類別。
  • 突顯式選單 (Popup Menu):java.awt.PopupMenu類別。
  • 選單 (Menu):java.awt.Menu類別。
  • 選單項目 (Menu Item):java.awt.MenuItem類別。
  • 核取選單項目 (Checkbox Menu Item):java.awt.CheckboxMenuItem類別。
如下圖所示:
欲建立系統紙匣,首先以SystemTray類別的getSystemTray()方法取得作業系統之系統紙匣區域,並回傳SystemTray物件,此一物件代表系統紙匣區域,但由於並非所有的作業系統均支援系統紙匣,因此在執行此方法時,可能產生以下之例外錯誤:
  • UnsupportedOperationException:作業系統不支援此功能。
  • SecurityException:無存取系統紙匣之權限。
為避免作業系統不支援所產生之例外錯誤,可使用SystemTray類別的isSupported()方法判斷作業系統是否支援系統紙匣功能。取得作業系統之系統紙匣區域的程式架構如下:


// 若作業系統支援系統紙匣功能
if (SystemTray.isSupported()) {
  // 取得系統紙匣區域
  SystemTray tray = SystemTray.getSystemTray();
  ...
}


SystemTray物件建立之後,接著以TrayIcon類別建立紙匣圖像,其建構函式為:

  public TrayIcon(Image image)
  public TrayIcon(Image image, String tooltip)
  public TrayIcon(Image image, String tooltip, PopupMenu popup)

其中參數:

  • image:以java.awt.Image類別建立之圖像,以作為紙匣圖像之用。
  • tooltip:紙匣圖像之使用提示說明。當滑鼠移至紙匣圖像上方時,所顯示之使用提示說明(如下圖所示)。
  • popup:以java.awt.PopupMenu類別建立之突顯式選單。當於紙匣圖像上方按下滑鼠右鍵時,所顯示之突顯式選單。

由上述之建構函式可以發現,以TrayIcon類別建立紙匣圖像,預設僅支援Java AWT的PopupMenu類別,並不支援Java Swing的JPopupMenu類別。
待紙匣圖像建立之後,則以SystemTray類別的add()方法將TrayIcon物件加入系統紙匣區域之中,其程式架構如下:


// 若作業系統支援系統紙匣功能
if (SystemTray.isSupported()) {
  // 取得系統紙匣區域
  SystemTray tray = SystemTray.getSystemTray();
  ...
  try {
    // 將TrayIcon加入SystemTray之中
    tray.add(trayIcon);
  }
  catch (Exception e) {...}
}


TrayIcon類別提供displayMessage()方法,以顯示紙匣圖像訊息框,訊息類型包括錯誤、一般、純文字與警告訊息,需注意的是,執行displayMessage()方法必須在執行SystemTray類別的add()方法之後,若在add()方法之前,則displayMessage()方法將執行無效。其正確的執行方式如下所示:


try {
  // 將TrayIcon加入SystemTray之中
  tray.add(trayIcon);
}
catch (Exception e) {...}

// 顯示紙匣圖像訊息框
trayIcon.displayMessage("Caption", "TrayIcon - Text", 
  TrayIcon.MessageType.INFO);


請參考以下範例。


// 若作業系統支援系統紙匣功能
if (SystemTray.isSupported()) {
  //  取得系統紙匣區域
  java.awt.SystemTray tray = SystemTray.getSystemTray();

  // 建立突顯式選單
  PopupMenu pop = new PopupMenu();

  MenuItem mnuCut = new MenuItem("Cut");
  mnuCut.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      menu_actionPerformed(e);
    }
  });

  MenuItem mnuCopy = new MenuItem("Copy");
  mnuCopy.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      menu_actionPerformed(e);
    }
  });

  MenuItem mnuPaste = new MenuItem("Paste");
  mnuPaste.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      menu_actionPerformed(e);
    }
  });

  // About
  MenuItem mnuAbout = new MenuItem("About");
  mnuAbout.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      menu_actionPerformed(e);
    }
  });

  // Exit
  MenuItem mnuExit = new MenuItem("Exit");
  mnuExit.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      //dispose();
      System.exit(0);
    }
  });

  // 建立子選單
  Menu submenu = new Menu("Level");
  
  // 建立核取選單項目
  cbItem = new CheckboxMenuItem[3];

  // 定義核取選單項目已被選取
  cbItem[0] = new CheckboxMenuItem("Basic", true);
  cbItem[0].addItemListener(this);
  cbItem[1] = new CheckboxMenuItem("Intermediate", false);
  cbItem[1].addItemListener(this);
  cbItem[2] = new CheckboxMenuItem("Advance", false);
  cbItem[2].addItemListener(this);

  submenu.add(cbItem[0]);
  submenu.add(cbItem[1]);
  submenu.add(cbItem[2]);
  
  // 建立突顯式選單
  pop.add(mnuCut);
  pop.add(mnuCopy);
  pop.add(mnuPaste);
  pop.add("-");
  // 新增子選單至選單中
  pop.add(submenu);
  pop.add("-");
  pop.add(mnuAbout);
  pop.add("-");
  pop.add(mnuExit);

  Image image = 
    Toolkit.getDefaultToolkit().getImage("images/dukeswing.gif");
  
  // 建立紙匣圖示
  trayIcon = new TrayIcon(image, "Tray Demo", pop);
  // 設定圖像是否為自動調整大小
  trayIcon.setImageAutoSize(true);
  
  // 建立紙匣圖示的動作Listener
  trayIcon.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      menu_actionPerformed(e);
    }
  });

  // 建立紙匣圖示的滑鼠Listener
  trayIcon.addMouseListener(new MouseListener() {
    public void mouseClicked(MouseEvent e) {
      System.out.println("按下並釋放滑鼠按鍵");                 
    }
    public void mouseEntered(MouseEvent e) {
      System.out.println("滑鼠移至紙匣圖示上方");                 
    }
    public void mouseExited(MouseEvent e) {
      System.out.println("滑鼠離開紙匣圖示");                 
    }
    public void mousePressed(MouseEvent e) {
      System.out.println("按下滑鼠按鍵");                 
    }
    public void mouseReleased(MouseEvent e) {
      System.out.println("釋放滑鼠按鍵");                 
    }
  });
  
  try {
    // 將TrayIcon物件加入SystemTray物件之中
    tray.add(trayIcon);
  } 
  catch (AWTException ex) {
    ex.printStackTrace();
  }

  // 顯示紙匣圖示訊息框      
  trayIcon.displayMessage("TrayIcon - Caption", "TrayIcon - Text",
    TrayIcon.MessageType.INFO);

else {
  System.out.println("作業系統不支援系統紙匣功能");
}


【執行結果】


【參考資料】

[1] Java Platform, Standard Edition 7 API Specification.
[2] 黃嘉輝,深入研究Java Swing (第二版),上奇資訊。

© Chia-Hui Huang

沒有留言:

張貼留言