2013-08-25 3 views
3

Я пишу сценарий для большего приложения с графическим интерфейсом. В главном окне приложения используется LookAndFeel системы, но я хочу, чтобы графический интерфейс моего скрипта использовал Nimbus LookAndFeel. После создания графического интерфейса я хочу вернуть LookAndFeel к оригиналу. Я чувствую, что ниже SSCCE должен работать, но я получаю NullPointerException при использовании объектов Component.Изменение внешнего вида и конкретного окна

import java.awt.Dimension; 
import java.awt.GridBagLayout; 
import javax.swing.*; 
import javax.swing.UIManager.LookAndFeelInfo; 

public class GUI extends JFrame { 
    private static LookAndFeel originalLookAndFeel = UIManager.getLookAndFeel(); 
    static { 
     System.out.println("At start, look and feel is " + UIManager.getLookAndFeel().getName()); 
     try { 
      setNimbusLookAndFeel(); 
     } catch (Exception e) { 
      System.out.println(e.getMessage()); 
     } 
     System.out.println("Look and feel changed to " + UIManager.getLookAndFeel().getName() 
       + " before component creation"); 
    } 
    private GridBagLayout gridBag = new GridBagLayout(); 
    private JTabbedPane tabs = new JTabbedPane(); 
    private JPanel selectionPanel = new JPanel(gridBag); 
    private JPanel infoPanel = new JPanel(gridBag); 
    private JPanel settingsPanel = new JPanel(gridBag); 

    public GUI() { 
     setWindowProperties(); 
     setUpComponents(); 
     addComponents(); 

     try { 
      System.out.println("Setting to original, which is " + originalLookAndFeel.getName()); 
      UIManager.setLookAndFeel(originalLookAndFeel); 
      System.out.println("Current look and feel is " + UIManager.getLookAndFeel().getName()); 
     } catch (UnsupportedLookAndFeelException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void setWindowProperties() { 
     setLayout(gridBag); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setSize(new Dimension(700, 600)); 
     setTitle("fAmos Quester"); 
     setResizable(false); 
     setLocationRelativeTo(null); 
    } 

    private static void setNimbusLookAndFeel() { 
     try { 
      for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { 
       if ("Nimbus".equals(info.getName())) { 
        UIManager.setLookAndFeel(info.getClassName()); 
       } 
      } 
     } catch (Exception e) { 
      try { 
       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
      } catch (Exception e2) { 
      } 
     } 
    } 

    public void setUpComponents() { 
     tabs.addTab("Quest selection", selectionPanel); 
     tabs.addTab("Quest info", infoPanel); 
     tabs.addTab("Settings", settingsPanel); 

     selectionPanel.setPreferredSize(new Dimension(650, 500)); 
     infoPanel.setPreferredSize(new Dimension(650, 500)); 
     settingsPanel.setPreferredSize(new Dimension(650, 500)); 
    } 

    private void addComponents() { 
     add(tabs); 
    } 

    public static void main(String[] args) { 
     new GUI().setVisible(true); 
    } 
} 

ответ

5

Как правило, смешивать LAF не рекомендуется. Эта проблема является примером того, почему.

В Nimbus LAF есть что-то, что может не позволить вам это сделать. Запустите код как есть. Он установит LAF на System LAF, а затем сбросит LAF. В моем случае система Windows, и она работает нормально. Затем измените код, чтобы использовать Nimbus LAF. Сначала он работает, но попробуйте изменить размер кадра, и вы получите ошибки. Таким образом, кажется, что рамка Nimbus не работает полностью независимо от текущего LAF.

import java.awt.*; 
import java.awt.event.*; 
import java.awt.GridBagLayout; 
import javax.swing.*; 
import javax.swing.UIManager.LookAndFeelInfo; 

public class GUI2 extends JFrame { 
    private static LookAndFeel originalLookAndFeel = UIManager.getLookAndFeel(); 
/* 
    private GridBagLayout gridBag = new GridBagLayout(); 
    private JTabbedPane tabs = new JTabbedPane(); 
    private JPanel selectionPanel = new JPanel(gridBag); 
    private JPanel infoPanel = new JPanel(gridBag); 
    private JPanel settingsPanel = new JPanel(gridBag); 
*/ 
    private GridBagLayout gridBag; 
    private JTabbedPane tabs; 
    private JPanel selectionPanel; 
    private JPanel infoPanel; 
    private JPanel settingsPanel; 

    public GUI2() { 
     System.out.println("At start, look and feel is " + UIManager.getLookAndFeel().getName()); 
     try { 
//   setNimbusLookAndFeel(); 
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     System.out.println("Look and feel changed to " + UIManager.getLookAndFeel().getName() 
       + " before component creation"); 

     gridBag = new GridBagLayout(); 
     setLayout(gridBag); 
     tabs = new JTabbedPane(); 
     selectionPanel = new JPanel(gridBag); 
     infoPanel = new JPanel(gridBag); 
     settingsPanel = new JPanel(gridBag); 

     setUpComponents(); 
     addComponents(); 
     setWindowProperties(); 

     Action reset = new AbstractAction() 
     { 
      public void actionPerformed(ActionEvent ae) 
      { 
       try { 
        System.out.println("Setting to original, which is " + originalLookAndFeel.getName()); 
        UIManager.setLookAndFeel(originalLookAndFeel); 
        System.out.println("Current look and feel is " + UIManager.getLookAndFeel().getName()); 
       } catch (UnsupportedLookAndFeelException e) { 
        //e.printStackTrace(); 
        System.out.println(e.getMessage()); 
       } 

      } 
     }; 

     Timer timer = new Timer(500, reset); 
     timer.setRepeats(false); 
     timer.start(); 
    } 

    private void setWindowProperties() { 
//  setLayout(gridBag); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setTitle("fAmos Quester"); 
//  setResizable(false); 
     pack(); 
     setLocationRelativeTo(null); 
    } 

    private void setNimbusLookAndFeel() { 
     try { 
      for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { 
       if ("Nimbus".equals(info.getName())) { 
        UIManager.setLookAndFeel(info.getClassName()); 
       } 
      } 
     } catch (Exception e) { 
      try { 
       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
      } catch (Exception e2) { 
      } 
     } 
    } 

    public void setUpComponents() { 
     tabs.addTab("Quest selection", selectionPanel); 
     tabs.addTab("Quest info", infoPanel); 
     tabs.addTab("Settings", settingsPanel); 

     selectionPanel.setPreferredSize(new Dimension(650, 500)); 
     infoPanel.setPreferredSize(new Dimension(650, 500)); 
     settingsPanel.setPreferredSize(new Dimension(650, 500)); 
    } 

    private void addComponents() { 
     add(tabs); 
    } 

    public static void main(String[] args) { 
     new GUI2().setVisible(true); 
    } 
} 

Возможно, решение было бы создать компонент с использованием Nimbus LAF, как это сделано выше. Однако не сбрасывайте LAF до тех пор, пока кадр не будет деактивирован. Затем вы можете попробовать сбросить LAF каждый раз, когда кадр активирован. Вы должны использовать WindowListener для обработки активированных/дезактивированных событий.

+0

Я подумываю переключиться на JDialog. Так я бы добавил слушателя окна и изменил LAF после закрытия? –

+0

Если вы используете модальный JDialog, что бы попробовать. Опять его просто догадка с моей стороны. – camickr

+0

Да, это похоже на шарм. Благодарю. –

3

Проблема возникает из-за попытки изменения PLAF в статическом блоке. Переместите его в конструктор, и он работает.

import java.awt.Dimension; 
import java.awt.GridBagLayout; 
import javax.swing.*; 
import javax.swing.UIManager.LookAndFeelInfo; 

public class GUI extends JFrame { 
    private static LookAndFeel originalLookAndFeel = UIManager.getLookAndFeel(); 
    private GridBagLayout gridBag = new GridBagLayout(); 
    private JTabbedPane tabs = new JTabbedPane(); 
    private JPanel selectionPanel = new JPanel(gridBag); 
    private JPanel infoPanel = new JPanel(gridBag); 
    private JPanel settingsPanel = new JPanel(gridBag); 

    public GUI() { 
     System.out.println("At start, look and feel is " + UIManager.getLookAndFeel().getName()); 
     try { 
      setNimbusLookAndFeel(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     System.out.println("Look and feel changed to " + UIManager.getLookAndFeel().getName() 
       + " before component creation"); 

     setWindowProperties(); 
     setUpComponents(); 
     addComponents(); 

     try { 
      System.out.println("Setting to original, which is " + originalLookAndFeel.getName()); 
      UIManager.setLookAndFeel(originalLookAndFeel); 
      System.out.println("Current look and feel is " + UIManager.getLookAndFeel().getName()); 
     } catch (UnsupportedLookAndFeelException e) { 
      //e.printStackTrace(); 
      System.out.println(e.getMessage()); 
     } 
    } 

    private void setWindowProperties() { 
     setLayout(gridBag); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setSize(new Dimension(700, 600)); 
     setTitle("fAmos Quester"); 
     setResizable(false); 
     setLocationRelativeTo(null); 
    } 

    private void setNimbusLookAndFeel() { 
     try { 
      for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { 
       if ("Nimbus".equals(info.getName())) { 
        UIManager.setLookAndFeel(info.getClassName()); 
       } 
      } 
     } catch (Exception e) { 
      try { 
       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
      } catch (Exception e2) { 
      } 
     } 
    } 

    public void setUpComponents() { 
     tabs.addTab("Quest selection", selectionPanel); 
     tabs.addTab("Quest info", infoPanel); 
     tabs.addTab("Settings", settingsPanel); 

     selectionPanel.setPreferredSize(new Dimension(650, 500)); 
     infoPanel.setPreferredSize(new Dimension(650, 500)); 
     settingsPanel.setPreferredSize(new Dimension(650, 500)); 
    } 

    private void addComponents() { 
     add(tabs); 
    } 

    public static void main(String[] args) { 
     new GUI().setVisible(true); 
    } 
} 
+0

Я больше не испытываю исключение во время выполнения, но LookAndFeel моего окна не является нимбом. Поскольку компоненты создаются, а LookAndFeel не является нимбом, они не отображаются как Nimbus. Первоначально я использовал статический блок, чтобы гарантировать, что Nimbus был установлен как LookAndFeel перед созданием Компонентов. –

+0

Можете ли вы показать SSCCE, который лучше отражает реальную проблему? В стороне, если уже есть фрейм, этот графический интерфейс должен быть диалогом. См. [Использование нескольких JFrames, Good/Bad Practice?] (Http://stackoverflow.com/a/9554657/418556) –

+0

Что вам непонятно? –

1

LAF не могут быть смешаны в общем случае, они спроектированы таким образом, что в любой момент времени для любого компонента в любом приложении имеется ровно одно. Таким образом, результат смешивания просто неопределен - вы можете или не можете уйти с ним в конкретном контексте, но будьте готовы к неожиданным визуальным и чувственным артефактам.

Пример для визуальных артефактов (это делается в тестовой инфраструктуре SwingX, достаточно просто, чтобы написать его, но я слишком ленив ;-) - откройте опциюПане, чем передвиньте ее: вы увидите цветные нимбы появляются более или менее непредсказуемо

setLAF("Metal"); 
final JTable table = new JTable(new AncientSwingTeam()); 
JXFrame frame = wrapWithScrollingInFrame(table, "Metal-base"); 
Action action = new AbstractAction("show dialog") { 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     setLAF("Nimbus"); 
     JOptionPane.showMessageDialog(table, "dummy - we are Nimbus!"); 
     setLAF("Metal"); 
    } 
}; 
addAction(frame, action); 
show(frame); 

техническая причина заключается в том, что UI-участники могут получить доступ к свойствам, хранящиеся в UIManager в любое время: в основном, они настроить свойства компонента из тех, которые хранятся в UIManager во время создания экземпляра и после которые получают доступ к этим свойствам из компонента. Иногда они получают доступ непосредственно к UIManager .. таким образом, приводя к непредсказуемым артефактам.

0

В этом решении предполагается, что вы измените настройку Look and Feel для «этого» конкретного окна (немного частного вспомогательного метода). Я использовал диалоговое окно для ввода ввода от пользователя (вы могли бы отредактировать это самостоятельно, чтобы скрыть его от пользователя и внести изменения, когда вам это нужно). Конечно, это немного длиннее для ясности и может быть легко сокращено.

private void changeLookAndFeel() { 
     final LookAndFeelInfo[] list = UIManager.getInstalledLookAndFeels(); 
     //Look And Feels available 


      final List<String> lookAndFeelsDisplay = new ArrayList<>(); 
      final List<String> lookAndFeelsRealNames = new ArrayList<>(); 

      for (LookAndFeelInfo each : list) { 
       lookAndFeelsDisplay.add(each.getName()); //simplified name of each available look and feel 
       lookAndFeelsRealNames.add(each.getClassName()); //class name 
      } 

      if (lookAndFeelsDisplay.size() != lookAndFeelsRealNames.size()) { 
       throw new InternalError(); //should never happen, redundant 
      } 

      String changeSpeed = (String) JOptionPane.showInputDialog(this, "Choose Look and Feel Here\n(these are all available on your system):", "Choose Look And Feel", JOptionPane.QUESTION_MESSAGE, null, lookAndFeelsDisplay.toArray(), null); 

      boolean update = false; 
      if (changeSpeed != null && changeSpeed.length() > 0) { 
       for (int a = 0; a < lookAndFeelsDisplay.size(); a++) { 
        if (changeSpeed.equals(lookAndFeelsDisplay.get(a))) { 
         try { 
          UIManager.setLookAndFeel(lookAndFeelsRealNames.get(a)); //reads the identical class name at the corresponding index position. 
          this.whichLookAndFeel = changeSpeed; 
          update = true; 
          break; 
         } 
         catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
          err.println(ex); 
          ex.printStackTrace(); 
          Logger.getLogger(MyClass.class.getName()).log(Level.SEVERE, null, ex); 
         } 
        } 
       } 
      } 

      if (update) { 
       // make updates here... 
      } 
    } 
Смежные вопросы