我正在为更大的GUI应用程序编写脚本。主应用程序窗口使用系统的LookAndFeel
,但我希望我的脚本的GUI使用Nimbus LookAndFeel
。创建GUI后,我想将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);
}
}
答案 0 :(得分: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来处理激活/停用的事件。
答案 1 :(得分: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);
}
}
答案 2 :(得分:2)
LAF不能在一般情况下混合使用,它们的设计使得在任何给定时间任何应用程序中的所有组件都只有一个。因此,混合的结果是未定义的 - 您可能会或可能不会在具体的上下文中使用它,但要为意外的视觉和感觉做法做好准备。
视觉文物的一个例子(它在SwingX测试基础设施中完成,简单到写出来 - 但我太懒了;-) - 打开optionPane,而不是移动它:你会看到Nimbus条纹颜色出现或多或少不可预测
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-delegates可以随时访问存储在UIManager中的属性:主要是,它们在实例化时从存储在UIManager中的属性配置组件的属性,然后从组件访问这些属性。但有时他们会直接访问UIManager ..从而导致无法预测的文物。
答案 3 :(得分:0)
此解决方案假定您要更改"此"的外观和感觉设置。特定的窗口(一个小的私人帮助方法)。我使用了一个对话窗口来获取用户的输入(您可以自己重新设计它以将其隐藏起来并在需要时进行更改)。当然,为了清晰起见,这有点长,可以很容易地缩短。
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...
}
}