전체 글
- Java event 2008.12.15
- Java Swing Events 2008.12.14
- Substance look&feel 사용법 (서브스텐스 룩앤필) 2008.12.08
Java event
Java Swing Events
Java Swing Events
Events are an important part in any GUI program. All GUI applications are event-driven. An application reacts to different event types which are generated during it's life. Events are generated mainly by the user of an application. But they can be generated by other means as well. e.g. internet connection, window manager, timer. In the event model, there are three participants:
- event source
- event object
- event listener
The Event source is the object whose state changes. It generates Events. The Event object (Event) encapsulates the state changes in the event source. The Event listener is the object that wants to be notified. Event source object delegates the task of handling an event to the event listener.
Event handling in Java Swing toolkit is very powerful and flexible. Java uses Event Delegation Model. We specify the objects that are to be notified when a specific event occurs.
An event object
When something happens in the application, an event object is created. For example, when we click on the button or select an item from list. There are several types of events. An ActionEvent, TextEvent, FocusEvent, ComponentEvent etc. Each of them is created under specific conditions.
Event object has information about an event, that has happened. In the next example, we will analyze an ActionEvent in more detail.
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JPanel; public class EventObject extends JFrame { private JList list; private DefaultListModel model; public EventObject() { setTitle("Event Object"); JPanel panel = new JPanel(); panel.setLayout(null); model = new DefaultListModel(); list = new JList(model); list.setBounds(150, 30, 220, 150); JButton ok = new JButton("Ok"); ok.setBounds(30, 35, 80, 25); ok.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(event.getWhen()); Locale locale = Locale.getDefault(); Date date = new Date(); String s = DateFormat.getTimeInstance(DateFormat.SHORT, locale).format(date); if ( !model.isEmpty() ) model.clear(); if (event.getID() == ActionEvent.ACTION_PERFORMED) model.addElement(" Event Id: ACTION_PERFORMED"); model.addElement(" Time: " + s); String source = event.getSource().getClass().getName(); model.addElement(" Source: " + source); int mod = event.getModifiers(); StringBuffer buffer = new StringBuffer(" Modifiers: "); if ((mod & ActionEvent.ALT_MASK) > 0) buffer.append("Alt "); if ((mod & ActionEvent.SHIFT_MASK) > 0) buffer.append("Shift "); if ((mod & ActionEvent.META_MASK) > 0) buffer.append("Meta "); if ((mod & ActionEvent.CTRL_MASK) > 0) buffer.append("Ctrl "); model.addElement(buffer); } }); panel.add(ok); panel.add(list); add(panel); setSize(420, 250); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { new EventObject(); } }
The code example shows a button and a list. If we click on the button, information about the event is displayed in the list. In our case, we are talking about an ActionEvent class. The data will be the time, when the event occured, the id of the event, the event source and the modifier keys.
public void actionPerformed(ActionEvent event) {
Inside the action listener, we have an event parameter. It is the instance of the event, that has occured. In our case it is an ActionEvent.
cal.setTimeInMillis(event.getWhen());
Here we get the time, when the event occured. The method returns time value in milliseconds. So we must format it appropriately.
String source = event.getSource().getClass().getName(); model.addElement(" Source: " + source);
Here we add the name of the source of the event to the list. In our case the source is a JButton.
int mod = event.getModifiers();
We get the modifier keys. It is a bitwise-or of the modifier constants.
if ((mod & ActionEvent.SHIFT_MASK) > 0) buffer.append("Shift ");
Here we determine, whether we have pressed a Shift key.

Implementation
There are several ways, how we can implement event handling in Java Swing toolkit.
- Anonymous inner class
- Inner class
- Derived class
Anonymous inner class
We will illustrate these concepts on a simple event example.
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class SimpleEvent extends JFrame { public SimpleEvent() { setTitle("Simle Event"); JPanel panel = new JPanel(); panel.setLayout(null); JButton close = new JButton("Close"); close.setBounds(40, 50, 80, 25); close.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { System.exit(0); } }); panel.add(close); add(panel); setSize(300, 200); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { new SimpleEvent(); } }
In this example, we have a button that closes the window upon clicking.
JButton close = new JButton("Close");
The button is the event source. It will generate events.
close.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { System.exit(0); } });
Here we register an action listener with the button. This way, the events are sent to the event target. The event target in our case is ActionListener class. In this code, we use an anonymous inner class.
Inner class
Here we implement the example using an inner ActionListener class.
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class InnerClass extends JFrame { public InnerClass() { setTitle("Using inner class"); JPanel panel = new JPanel(); panel.setLayout(null); JButton close = new JButton("Close"); close.setBounds(40, 50, 80, 25); ButtonListener listener = new ButtonListener(); close.addActionListener(listener); panel.add(close); add(panel); setSize(300, 200); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { System.exit(0); } } public static void main(String[] args) { new InnerClass(); } }
ButtonListener listener = new ButtonListener(); close.addActionListener(listener);
Here we have a non anonymous inner class.
class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { System.exit(0); } }
The button listener is defined here.
A derived class implementing the listener
The following example will derive a class from a component and implement an action listener inside the class.
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class UsingInterface extends JFrame { public UsingInterface() { setTitle("Using inner class"); JPanel panel = new JPanel(); panel.setLayout(null); MyButton close = new MyButton("Close"); close.setBounds(40, 50, 80, 25); panel.add(close); add(panel); setSize(300, 200); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } class MyButton extends JButton implements ActionListener { public MyButton(String text) { super.setText(text); addActionListener(this); } public void actionPerformed(ActionEvent e) { System.exit(0); } } public static void main(String[] args) { new UsingInterface(); } }
In this example, we create a MyButton class, which will implement the action listener.
MyButton close = new MyButton("Close");
Here we create the MyButton custom class.
class MyButton extends JButton implements ActionListener {
The MyButton class is extended from the JButton class. It implements the ActionListener interface. This way, the event handling is managed within the MyButton class.
addActionListener(this);
Here we add the action listener to the MyButton class.
Multiple sources
A listener can be plugged into several sources. This will be explained in the next example.
import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.EtchedBorder; public class MultipleSources extends JFrame { JLabel statusbar; public MultipleSources() { setTitle("Multiple Sources"); JPanel panel = new JPanel(); statusbar = new JLabel(" ZetCode"); statusbar.setBorder(BorderFactory.createEtchedBorder( EtchedBorder.RAISED)); panel.setLayout(null); JButton close = new JButton("Close"); close.setBounds(40, 30, 80, 25); close.addActionListener(new ButtonListener()); JButton open = new JButton("Open"); open.setBounds(40, 80, 80, 25); open.addActionListener(new ButtonListener()); JButton find = new JButton("Find"); find.setBounds(40, 130, 80, 25); find.addActionListener(new ButtonListener()); JButton save = new JButton("Save"); save.setBounds(40, 180, 80, 25); save.addActionListener(new ButtonListener()); panel.add(close); panel.add(open); panel.add(find); panel.add(save); add(panel); add(statusbar, BorderLayout.SOUTH); setSize(400, 300); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { JButton o = (JButton) e.getSource(); String label = o.getText(); statusbar.setText(" " + label + " button clicked"); } } public static void main(String[] args) { new MultipleSources(); } }
We create four buttons and a statusbar. The statusbar will display an informative message upon clicking on the button.
close.addActionListener(new ButtonListener()); ... open.addActionListener(new ButtonListener()); ...
Each button will be registered against a ButtonListener class.
JButton o = (JButton) e.getSource(); String label = o.getText();
Here we determine, which button was pressed.
statusbar.setText(" " + label + " button clicked")
We update the statusbar.

Multiple listeners
We can register several listeners for one event.
import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Calendar; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.border.EtchedBorder; public class MultipleListeners extends JFrame { private JLabel statusbar; private JSpinner spinner; private static int count = 0; public MultipleListeners() { setTitle("Multiple Listeners"); JPanel panel = new JPanel(); statusbar = new JLabel("0"); statusbar.setBorder(BorderFactory.createEtchedBorder( EtchedBorder.RAISED)); panel.setLayout(null); JButton add = new JButton("+"); add.setBounds(40, 30, 80, 25); add.addActionListener(new ButtonListener1()); add.addActionListener(new ButtonListener2()); Calendar calendar = Calendar.getInstance(); int currentYear = calendar.get(Calendar.YEAR); SpinnerModel yearModel = new SpinnerNumberModel(currentYear, currentYear - 100, currentYear + 100, 1); spinner = new JSpinner(yearModel); spinner.setEditor(new JSpinner.NumberEditor(spinner, "#")); spinner.setBounds(190, 30, 80, 25); panel.add(add); panel.add(spinner); add(panel); add(statusbar, BorderLayout.SOUTH); setSize(300, 200); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } class ButtonListener1 implements ActionListener { public void actionPerformed(ActionEvent e) { Integer val = (Integer) spinner.getValue(); spinner.setValue(++val); } } class ButtonListener2 implements ActionListener { public void actionPerformed(ActionEvent e) { statusbar.setText(Integer.toString(++count)); } } public static void main(String[] args) { new MultipleListeners(); } }
In this example, we have a button, spinner and a statusbar. We use two button listeners for one event. One click of a button will add one year to the spinner component and update the statusbar. The statusbar will show, how many times we have clicked on the button.
add.addActionListener(new ButtonListener1()); add.addActionListener(new ButtonListener2());
We register two button listeners.
SpinnerModel yearModel = new SpinnerNumberModel(currentYear, currentYear - 100, currentYear + 100, 1); spinner = new JSpinner(yearModel);
Here we create the spinner component. We use a year model for the spinner. The SpinnerNumberModel arguments are initial value, min, max values and the step.
spinner.setEditor(new JSpinner.NumberEditor(spinner, "#"));
We remove the thousands separator.
Integer val = (Integer) spinner.getValue(); spinner.setValue(++val);
Here we increase the year number.

Removing listeners
The Java Swing toolkit enables us to remove the registered listeners.
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class RemoveListener extends JFrame { private JLabel text; private JButton add; private JCheckBox active; private ButtonListener buttonlistener; private static int count = 0; public RemoveListener() { setTitle("Remove listener"); JPanel panel = new JPanel(); panel.setLayout(null); add = new JButton("+"); add.setBounds(40, 30, 80, 25); buttonlistener = new ButtonListener(); active = new JCheckBox("Active listener"); active.setBounds(160, 30, 140, 25); active.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent event) { if (active.isSelected()) { add.addActionListener(buttonlistener);} else { add.removeActionListener(buttonlistener); } } }); text = new JLabel("0"); text.setBounds(40, 80, 80, 25); panel.add(add); panel.add(active); panel.add(text); add(panel); setSize(310, 200); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { text.setText(Integer.toString(++count)); } } public static void main(String[] args) { new RemoveListener(); } }
We have three components on the panel. A button, check box and a label. By toggling the check box, we add or remove the listener for a button.
buttonlistener = new ButtonListener();
We have to create a non anonymous listener, if we want to later remove it. We need a reference to it.
if (active.isSelected()) { add.addActionListener(buttonlistener);} else { add.removeActionListener(buttonlistener); }
We determine, whether the check box is selected. Then we add or remove the listener.

Moving a window
The following example will look for a position of a window on the screen.
import java.awt.Font; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class MovingWindow extends JFrame implements ComponentListener { private JLabel labelx; private JLabel labely; public MovingWindow() { setTitle("Moving window"); JPanel panel = new JPanel(); panel.setLayout(null); labelx = new JLabel("x: "); labelx.setFont(new Font("Serif", Font.BOLD, 14)); labelx.setBounds(20, 20, 60, 25); labely = new JLabel("y: "); labely.setFont(new Font("Serif", Font.BOLD, 14)); labely.setBounds(20, 45, 60, 25); panel.add(labelx); panel.add(labely); add(panel); addComponentListener(this); setSize(310, 200); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } public void componentResized(ComponentEvent e) { } public void componentMoved(ComponentEvent e) { int x = e.getComponent().getX(); int y = e.getComponent().getY(); labelx.setText("x: " + x); labely.setText("y: " + y); } public void componentShown(ComponentEvent e) { } public void componentHidden(ComponentEvent e) { } public static void main(String[] args) { new MovingWindow(); } }
The example shows the current window coordinates on the panel. To get the window position, we use the ComponentListener
labelx.setFont(new Font("Serif", Font.BOLD, 14));
We make the font bigger, the default one is a bit small.
int x = e.getComponent().getX(); int y = e.getComponent().getY();
Here we get the x and the y positions.
Notice, that we have to implement all four methods, that are available in the ComponentListener. Even, if we do not use them.

Adapters
Adapters are convenient classes. In the previous code example, we had to implement all four methods of a ComponentListener class. Even if we did not use them. To avoid unnecessary coding, we can use adapters. Adapter is a class that implements all necessary methods. They are empty. We then use only those methods, that we actually need. There is no adapter for a button click event. Because there we have only one method to implement. The actionPerformed() method. We can use adapters in situations, where we have more than one method to implement.
The following example is a rewrite of the previous one, using a ComponentAdapter.
import java.awt.Font; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class Adapter extends JFrame { private JLabel labelx; private JLabel labely; public Adapter() { setTitle("Adapter"); JPanel panel = new JPanel(); panel.setLayout(null); labelx = new JLabel("x: "); labelx.setFont(new Font("Serif", Font.BOLD, 14)); labelx.setBounds(20, 20, 60, 25); labely = new JLabel("y: "); labely.setFont(new Font("Serif", Font.BOLD, 14)); labely.setBounds(20, 45, 60, 25); panel.add(labelx); panel.add(labely); add(panel); addComponentListener(new MoveAdapter()); setSize(310, 200); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } class MoveAdapter extends ComponentAdapter { public void componentMoved(ComponentEvent e) { int x = e.getComponent().getX(); int y = e.getComponent().getY(); labelx.setText("x: " + x); labely.setText("y: " + y); } } public static void main(String[] args) { new Adapter(); } }
This example is a rewrite of the previous one. Here we use the ComponentAdapter.
addComponentListener(new MoveAdapter());
Here we register the component listener.
class MoveAdapter extends ComponentAdapter { public void componentMoved(ComponentEvent e) { int x = e.getComponent().getX(); int y = e.getComponent().getY(); labelx.setText("x: " + x); labely.setText("y: " + y); } }
Inside the MoveAdapter inner class, we define the componentMoved() method. All the other methods are left empty.
Substance look&feel 사용법 (서브스텐스 룩앤필)
Substance look and feel - getting started
This document describes the steps to create a sample Swing application and run it under Substance look and feel.
Since Substance requires JDK 6.0 or higher, if you don't have such an installation on your machine, you need to download it from this site and install it. The command-prompt examples below assume that java executable is in the path. This executable is part of JRE (under bin folder) as well as part of JDK (under bin folder). Consult your OS manual on how to add the relevant folder to the path. Alternatively, you can put the entire path to the java executable in the scripts below.
After you have JDK 6.0+ installed on your machine, create the following Walkthrough.java
class:
public class Walkthrough extends JFrame {
public Walkthrough() {
super("Sample app");
this.setLayout(new FlowLayout());
this.add(new JButton("button"));
this.add(new JCheckBox("check"));
this.add(new JLabel("label"));
this.setSize(new Dimension(250, 80));
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Walkthrough w = new Walkthrough();
w.setVisible(true);
}
});
}
}
This is a simple frame (that does nothing) with a button, a checkbox and a label. You can create this class in your favourite IDE or in any text editor. Once this class is created, compile it. If you're using an IDE, consult the IDE help on the compilation process. If you're using a simple text editor, you can compile this class by using:
javac Walktrough.java
If you have problems, consult the online help for javac compiler. The compiled Walkthrough.class
will be created in the same folder as your Walkthrough.java
. In order to run it, use:
java -cp . Walkthrough
You will see the following frame under the default Ocean look and feel:

In order to run the same frame under Substance look and feel, you first need to choose the Substance skin that you would like to use (see the links at the end of this document). Suppose that you choose the Business
skin. Now you have the following options:
- Start your VM with
-Dswing.defaultlaf=org.jvnet.substance.skin.SubstanceBusinessLookAndFeel
UIManager.setLookAndFeel(new SubstanceBusinessLookAndFeel())
UIManager.setLookAndFeel("org.jvnet.substance.skin.SubstanceBusinessLookAndFeel");
The first option doesn't require any code changes in the application above. Run the following script:
java -Dswing.defaultlaf=org.jvnet.substance.skin.SubstanceBusinessLookAndFeel -cp . Walkthrough
You will see the following exception:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot load org.jvnet.substance.skin.SubstanceBusinessLookAndFeel
at javax.swing.UIManager.initializeDefaultLAF(UIManager.java:1345)
at javax.swing.UIManager.initialize(UIManager.java:1432)
at javax.swing.UIManager.maybeInitialize(UIManager.java:1420)
at javax.swing.UIManager.getUI(UIManager.java:1007)
at javax.swing.JPanel.updateUI(JPanel.java:109)
at javax.swing.JPanel.(JPanel.java:69)
at javax.swing.JPanel.(JPanel.java:92)
at javax.swing.JPanel.(JPanel.java:100)
at javax.swing.JRootPane.createGlassPane(JRootPane.java:527)
at javax.swing.JRootPane.(JRootPane.java:347)
at javax.swing.JFrame.createRootPane(JFrame.java:260)
at javax.swing.JFrame.frameInit(JFrame.java:241)
at javax.swing.JFrame.(JFrame.java:208)
at Walkthrough.(Walkthrough.java:10)
at Walkthrough$1.run(Walkthrough.java:25)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:284)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
This means that the org.jvnet.substance.skin.SubstanceBusinessLookAndFeel class in not found in the classpath. This class is located in the substance.jar that you need to download from the Documents & Files section of the Substance project page. For this example, we assume that the substance.jar is located under C:/temp folder. In order to run the frame under Substance, use the following script:
java -Dswing.defaultlaf=org.jvnet.substance.skin.SubstanceBusinessLookAndFeel -cp .;C:/temp/substance.jar Walkthrough
The result is the same frame under Substance look and feel:

The other two options for setting Substance require changing the code. Go back to your Java editor and replace the main()
method by:
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
try {
UIManager.setLookAndFeel(new SubstanceRavenGraphiteLookAndFeel());
} catch (Exception e) {
System.out.println("Substance Raven Graphite failed to initialize");
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Walkthrough w = new Walkthrough();
w.setVisible(true);
}
});
}
Note that here we are using another Substance skin, Raven Graphite
. In order to compile the new Walkthrough.java
, you need to add the substance.jar to the build path. Consult your IDE help if you're using IDE. For command-prompt compilation, use the additional -cp flag:
javac -cp c:/temp/substance.jar Walktrough.java
Now you can run your application without the -Dswing.defaultlaf JVM flag, but you still need to specify the location of the substance.jar as before:
java -cp .;C:/temp/substance.jar Walkthrough
If you don't want to create an explicit dependency on the Substance classes in your code, change your main()
method to:
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
try {
UIManager.setLookAndFeel("org.jvnet.substance.skin.SubstanceRavenGraphiteLookAndFeel");
} catch (Exception e) {
System.out.println("Substance Raven Graphite failed to initialize");
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Walkthrough w = new Walkthrough();
w.setVisible(true);
}
});
}
You can run the application the same way as before. Here is how it looks like:

Where to go from here?
- Read the FAQ
- Read about the VM flags
- Read about the client properties
- Read about the API
- Read about using skins
- Download the sources and study the test application in
test/Check.java
- Read the Javadocs of SubstanceLookAndFeel class.
<출처 : https://substance.dev.java.net/docs/getting-started.html >