2016-07-14 42 views
2

以下代碼創建一個簡單的GUI,其中央有一個按鈕,單擊該按鈕時應更新JMenuBar組件的字體。要做到這一點,方法setMyFontJButtonActionListener火。然而,經過多次列出的嘗試,我沒有做到這一點,但我不知道爲什麼。在setMyFont使用的代碼如下在JMenuBar可見後更新JMenu和JMenu字體

public void setMyFont(Font f, Font f2) { 
    //Attempt 1 in the hope it would autodetect that font 
    //had changed and just update 
    menuFont = f; 
    menuItemFont = f2; 

    //Attempt 2 in the hope on the repaint it would update 
    //the font with the new UIManager properties 
    UIManager.put("Menu.font", menuFont); 
    UIManager.put("MenuItem.font", menuItemFont); 

    //Attempt 3 in the hope that going over each component 
    //individually would update the font 
    for(Component comp: getComponents()) { 
     if(comp instanceof JMenu) { 
      comp.setFont(menuFont); 
     } else { 
      comp.setFont(menuItemFont); 
     } 
    } 

    validate(); 
    repaint(); 
} 

是否有一個原因,字體不與當前的代碼組件更新?另外,如何更改我的代碼以允許在組件上更新字體,即使它們已經創建了?


完整代碼SSCCE

import java.awt.Component; 
import java.awt.Font; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JMenu; 
import javax.swing.JMenuBar; 
import javax.swing.JMenuItem; 
import javax.swing.UIManager; 

public class Main extends JFrame { 
    private static final long serialVersionUID = 3206847208968227199L; 
    JButton but; 
    MenuBar mB; 

    private Main() { 
     setSize(600, 600); 

     mB = new MenuBar(); 
     setJMenuBar(new MenuBar()); 

     but = new JButton("Change Font"); 
     but.addActionListener(new CustomActionListener()); 
     add(but); 

     setVisible(true); 
     setLocationRelativeTo(null); 
    } 

    public static void main(String[] args) { 
     new Main(); 
    } 

    private class MenuBar extends JMenuBar { 
     private static final long serialVersionUID = -2055260049565317972L; 
     Font menuFont = new Font("Courier", Font.ITALIC + Font.BOLD, 12); 
     Font menuItemFont = new Font("sans-serif", 0, 12); 
     JMenu menu, subMenu; 

     MenuBar() { 
      UIManager.put("Menu.font", menuFont); 
      UIManager.put("MenuItem.font", menuItemFont); 

      menu = new JMenu("Menu"); 

      subMenu = new JMenu("Sub Menu"); 
      subMenu.add(new JMenuItem("Sub Item")); 
      subMenu.add(new JMenu("Sub Menu")); 
      menu.add(subMenu); 

      menu.add(new JMenuItem("Sub Item")); 
      menu.add(new JMenu("Sub Menu")); 

      add(menu); 

      menu = new JMenu("Another Menu"); 
      menu.add(new JMenu("Sub Menu")); 
      menu.add(new JMenuItem("Sub Item")); 
      menu.add(new JMenu("Sub Menu")); 
      add(menu); 
     } 

     public void setMyFont(Font f, Font f2) { 
      //Attempt 1 in the hope it would autodetect that font 
      //had changed and just update 
      menuFont = f; 
      menuItemFont = f2; 

      //Attempt 2 in the hope on the repaint it would update 
      //the font with the new UIManager properties 
      UIManager.put("Menu.font", menuFont); 
      UIManager.put("MenuItem.font", menuItemFont); 

      //Attempt 3 in the hope that going over each component 
      //individually would update the font 
      for(Component comp: getComponents()) { 
       if(comp instanceof JMenu) { 
        comp.setFont(menuFont); 
       } else { 
        comp.setFont(menuItemFont); 
       } 
      } 

      validate(); 
      repaint(); 
     } 
    } 

    private class CustomActionListener implements ActionListener { 
     public void actionPerformed(ActionEvent e) { 
      mB.setMyFont(new Font("sans-serif", 0, 12), new Font("Courier", Font.ITALIC + Font.BOLD, 12)); 
     } 
    } 
} 

回答

4
  1. 設置字體後,你需要有層次結構中的調用更新它的UI每個組件 - SwingUtilities有這個

    一個簡便方法
    UIManager.put("Menu.font", menuFont); 
    SwingUtilities.updateComponentTreeUI(Main.this); 
    
  2. 使用FontUIResource類如

    FontUIResource menuFont = new FontUIResource("Courier", Font.ITALIC + Font.BOLD, 12); 
    

改編自發布SSCCE下面的代碼對我的作品:

import java.awt.Font; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JMenu; 
import javax.swing.JMenuBar; 
import javax.swing.JMenuItem; 
import javax.swing.SwingUtilities; 
import javax.swing.UIManager; 
import javax.swing.plaf.FontUIResource; 

public class Main extends JFrame { 
    private static final long serialVersionUID = 3206847208968227199L; 
    JButton but; 
    MenuBar mB; 

    private Main() { 
     setSize(600, 600); 

     mB = new MenuBar(); 
     setJMenuBar(mB); 

     but = new JButton("Change Font"); 
     but.addActionListener(new CustomActionListener()); 
     add(but); 

     setVisible(true); 
     setLocationRelativeTo(null); 
    } 

    public static void main(String[] args) { 
     new Main(); 
    } 

    private class MenuBar extends JMenuBar { 
     private static final long serialVersionUID = -2055260049565317972L; 
     Font menuFont = new FontUIResource("Courier", Font.ITALIC + Font.BOLD, 12); 
     Font menuItemFont = new FontUIResource("sans-serif", 0, 12); 
     JMenu menu, subMenu; 

     MenuBar() { 
      UIManager.put("Menu.font", menuFont); 
      UIManager.put("MenuItem.font", menuItemFont); 

      menu = new JMenu("Menu"); 

      subMenu = new JMenu("Sub Menu"); 
      subMenu.add(new JMenuItem("Sub Item")); 
      subMenu.add(new JMenu("Sub Menu")); 
      menu.add(subMenu); 

      menu.add(new JMenuItem("Sub Item")); 
      menu.add(new JMenu("Sub Menu")); 

      add(menu); 

      menu = new JMenu("Another Menu"); 
      menu.add(new JMenu("Sub Menu")); 
      menu.add(new JMenuItem("Sub Item")); 
      menu.add(new JMenu("Sub Menu")); 
      add(menu); 
     } 

     public void setMyFont(Font f, Font f2) { 

      menuFont = f; 
      menuItemFont = f2; 
      UIManager.put("Menu.font", menuFont); 
      UIManager.put("MenuItem.font", menuItemFont); 
      SwingUtilities.updateComponentTreeUI(Main.this); 
     } 
    } 

    private class CustomActionListener implements ActionListener { 
     public void actionPerformed(ActionEvent e) { 
      mB.setMyFont(new FontUIResource("sans-serif", 0, 12), new FontUIResource("Courier", Font.ITALIC + Font.BOLD, 12)); 
     } 
    } 
} 
+1

(1+)使用updateComponentTree(...)比寫自己的遞歸方法來獲取添加到菜單欄的所有組件更容易。儘管您只需要調用菜單欄上的方法,而不是框架。 – camickr

+0

@camickr RE根據[docs](https://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html#programmatic)調用菜單欄,每調用一次SwingUtilities updateComponentTreeUI方法'[頂級容器](https://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html) – copeg

+0

@copeg謝謝你的回答。不幸的是,我可能做錯了,調用'SwingUtilities.updateComponentTreeUI(Main.this);'設置字體後什麼也沒做。我應該在'setMyFont'函數之外還是應該工作。*我也實現了'FontUIResource',它沒有區別* – Dan

3
mB = new MenuBar(); 
    setJMenuBar(new MenuBar()); 

你的ActionListener不工作在您添加到窗體的菜單欄。

的代碼應該是:

mB = new MenuBar(); 
    //setJMenuBar(new MenuBar()); 
    setJMenuBar(mB); 

的getComponents()方法不是遞歸。所以你的循環只會將JMenu組件添加到JMenuBar中,而不是JMenuItems。

此外,當創建您的字體爲什麼不使用更大的字體大小,所以你實際上可以看到是否有變化。

此外,在您的發佈代碼中,在創建組件之前設置UIManager字體屬性會影響獲取按鈕的目的。你的菜單已經是所需的字體。

1

也許你可以試試這個:

public class MenuFontChange { 

    public static void changeMenuFont(JMenuBar jBar, Font font) { 
     Component[] components = jBar.getComponents(); 
     for (Component component : components) { 
      component.setFont(font); 
      changeMenuItemFont((JMenu) component, font); 
     } 
    } 

    public static void changeMenuItemFont(JMenu jMenu, Font font) { 
     int n = jMenu.getItemCount(); 
     for (int i = 0; i < n; i++) { 
      JMenuItem item = jMenu.getItem(i); 
      item.setFont(font); 
     } 
    }