Tips/LookAndFeelDebugAgent のバックアップの現在との差分(No.4)
- title: SwingアプリケーションのLookAndFeelを外部から切り替える author: aterai pubdate: 2008-11-28 description: SwingアプリケーションのLookAndFeelをagentを使って外部から切り替えてデバッグします。
概要
Summary
Swing
アプリケーションのLookAndFeel
をagent
を使って外部から切り替えてデバッグします。
ソースコード
ソースコード
package swinghelper;
#spanadd
#spanend
import java.awt.*;
#spandel
import java.awt.event.*;
#spanend
#spandel
import java.lang.instrument.*;
#spanend
#spanadd
import java.awt.event.ActionEvent;
#spanend
#spanadd
import java.lang.reflect.Constructor;
#spanend
#spanadd
import java.lang.reflect.InvocationTargetException;
#spanend
#spanadd
import java.util.Arrays;
#spanend
#spanadd
import java.util.Optional;
#spanend
#spanadd
import java.util.logging.Logger;
#spanend
import javax.swing.*;
#spanadd
import com.formdev.flatlaf.*;
#spanend
public class LookAndFeelDebugAgent {
public static void premain(String args) throws Exception {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
public static Component makeUI() {
Box box = LookAndFeelUtils.createLookAndFeelBox();
box.add(Box.createVerticalGlue());
box.setBorder(BorderFactory.createEmptyBorder(5, 25, 5, 25));
return box;
}
#spanadd
#spanend
public static void premain(String args) {
EventQueue.invokeLater(() -> {
JFrame frame = new JFrame("LookAndFeelDebugAgent");
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.getContentPane().add(makeUI());
frame.pack();
frame.setVisible(true);
});
}
public static void createAndShowGUI() {
ButtonGroup group = new ButtonGroup();
Box box = Box.createVerticalBox();
for(LookAndFeelEnum lnf : LookAndFeelEnum.values()) {
JRadioButton rb = new JRadioButton(new ChangeLookAndFeelAction(lnf));
group.add(rb); box.add(rb);
}
box.add(Box.createVerticalGlue());
box.setBorder(BorderFactory.createEmptyBorder(5,25,5,25));
#spanadd
}
#spanend
JFrame frame = new JFrame("LnF");
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.getContentPane().add(box);
frame.pack();
frame.setVisible(true);
#spanadd
final class LookAndFeelUtils {
#spanend
private static String lookAndFeel = UIManager.getLookAndFeel().getClass().getName();
#spanadd
#spanend
private LookAndFeelUtils() {
/* Singleton */
}
private static enum LookAndFeelEnum {
Metal ("javax.swing.plaf.metal.MetalLookAndFeel"),
Mac ("com.sun.java.swing.plaf.mac.MacLookAndFeel"),
Motif ("com.sun.java.swing.plaf.motif.MotifLookAndFeel"),
Windows("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"),
GTK ("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"),
Nimbus ("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
private final String clazz;
private LookAndFeelEnum(String clazz) {
this.clazz = clazz;
#spanadd
#spanend
public static Box createLookAndFeelBox() {
Box box = Box.createVerticalBox();
ButtonGroup buttonGroup = new ButtonGroup();
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
AbstractButton b = makeButton(info);
initLookAndFeelAction(info, b);
box.add(b);
buttonGroup.add(b);
}
public String getClassName() {
return clazz;
for (Class<?> clz : Arrays.asList(FlatLightLaf.class, FlatDarkLaf.class)) {
String full = clz.getName();
String name = full.substring(full.lastIndexOf('.') + 1);
UIManager.LookAndFeelInfo info = new UIManager.LookAndFeelInfo(name, full);
AbstractButton b = makeButton(info);
initLookAndFeelAction(info, b);
box.add(b);
buttonGroup.add(b);
}
return box;
}
private static class ChangeLookAndFeelAction extends AbstractAction{
private final String lnf;
protected ChangeLookAndFeelAction(LookAndFeelEnum lnfe) {
super(lnfe.toString());
this.lnf = lnfe.getClassName();
this.setEnabled(isAvailableLookAndFeel(lnf));
}
private static boolean isAvailableLookAndFeel(String lnf) {
try{
Class lnfClass = Class.forName(lnf);
LookAndFeel newLnF = (LookAndFeel)(lnfClass.newInstance());
return newLnF.isSupportedLookAndFeel();
}catch(Exception e) {
return false;
#spanadd
#spanend
private static AbstractButton makeButton(UIManager.LookAndFeelInfo info) {
boolean selected = info.getClassName().equals(lookAndFeel);
return new JRadioButton(info.getName(), selected);
}
#spanadd
#spanend
public static void initLookAndFeelAction(UIManager.LookAndFeelInfo info, AbstractButton b) {
String cmd = info.getClassName();
b.setText(info.getName());
b.setActionCommand(cmd);
b.setHideActionText(true);
b.addActionListener(e -> setLookAndFeel(cmd));
}
#spanadd
#spanend
private static void setLookAndFeel(String newLookAndFeel) {
String oldLookAndFeel = lookAndFeel;
if (!oldLookAndFeel.equals(newLookAndFeel)) {
try {
UIManager.setLookAndFeel(newLookAndFeel);
lookAndFeel = newLookAndFeel;
} catch (UnsupportedLookAndFeelException ignored) {
Toolkit.getDefaultToolkit().beep();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
Logger.getGlobal().severe(ex::getMessage);
return;
}
updateLookAndFeel();
}
@Override public void actionPerformed(ActionEvent e) {
try{
UIManager.setLookAndFeel(lnf);
}catch(Exception ex) {
ex.printStackTrace();
System.out.println("Failed loading L&F: " + lnf);
}
for(Frame f:Frame.getFrames()) {
if(f instanceof JFrame) {
SwingUtilities.updateComponentTreeUI(f);
f.pack();
}
}
}
#spanadd
#spanend
private static void updateLookAndFeel() {
for (Window window : Window.getWindows()) {
SwingUtilities.updateComponentTreeUI(window);
}
}
}
解説
Look And Feel
を切り替えるためのパネルが一緒に起動し、対象アプリケーションのソースコードを変更することなく、LookAndFeel
の変更をテストすることが出来ます。
Description
- アプリケーションと同時に
Look And Feel
を切り替えるための別パネルを起動して、対象アプリケーションのソースコードを変更することなくLookAndFeel
の変更がテスト可能
javaagent
を使うので、JDK 1.6
以上で以下のように起動します。
- このサンプルではデフォルト以外の
Look And Feel
としてFlatLightLaf
とFlatDarkLaf
を追加して以下のようにBoot-Class-Path
を指定してコンパイルしている#spanend #spanadd <target name="package" depends="compile"> #spanend <jar jarfile="${build.dir}/${name}-${version}.jar" basedir="${build.dest}"> <manifest> <!--attribute name="Main-Class" value="${main.class}" /--> <!--attribute name="Agent-Class" value="${main.class}" /--> <attribute name="Premain-Class" value="${main.class}" /> <attribute name="Class-Path" value="${runtime.classpath}" /> <attribute name="Can-Retransform-Classes" value="true"/> <attribute name="Boot-Class-Path" value="flatlaf-3.5.jar" /> </manifest> </jar> #spanadd </target> #spanend #spanadd
-
javaagent
を使用するため、JDK 1.6
以上で以下のように起動する#spandel java -javaagent:lnfagent.jar -jar example.jar #spanend #spanadd java -javaagent:lnfagent1.0.1.jar -jar example.jar #spanend