[java] Window Programming
java로 윈도우 프로그램을 만들 수 있는 기술
AWT (윈도우 3.1 쯤 나온 기술) -> Swing (최근 나온 기술) -> JavaFX (가장 최신 기술)
AWT, Swing : 둘 다 사용 방법이 비슷하다.
JavaFX : AWT, Swing와 연관성은 있지만 사용방법이 꽤 다르다. 안드로이드 환경과 비슷하다.
<윈도우 프로그래밍의 3요소>
1. 재료 (Component)
- 윈도우 프로그래밍을 만들기 위한 재료
2. 디자인 (Layout)
3. 동작 (Event)
4. Component (재료) 더 알아보기
1) AWT(Abstract Window Toolkit)
Abstract : 추상
버튼을 눌렀을 때 실제 기능은 코딩을 해야한다.
처음 버튼 자체는 껍데기일 뿐이다.
그렇기 때문에 Abstract 라고 말한다.
java.desktop
java.awt.Component
클래스를 살펴보자.
Component의 자식 클래스들을 만나보자
Button : 버튼
Canvas : 그림판 같이 그릴 수 있음
Checkbox : 체크박스
Choice : 항목이 숨겨져 있다가 버튼 누르면 리스트가 툭 튀어나옴
Container : 다른 컨포넌트를 담기위한 그릇이다. 모든재료는 Container에 담아야 사용가능하다.
Container의 중요한 자식 클래스
└ panel
└ applet : 가장 대표적인 Container. 전체 프로그램의 뼈대 담당.
└ window
└ dialog
└ frame : 가장 대표적인 Container. 전체 프로그램의 뼈대 담당.
Label : 글자만 출력 할 수 있는 재료
List : 처음부터 리스트가 있음
Scrollbar : 밑에나 아래 스크롤바를 달 수 있도록 함
TextComponent : 글자를 입력 할 수 있는 도구
TextComponent 의 중요한 자식 클래스
└ TextField : 딱 한줄 입력할 수 있는 텍스트 박스
└ TextArea : 여러 줄 입력할 수 있는 텍스트 박스
AWT는 간단하지만, 스윙으로 가면 재료가 많아진다.
<Container 의 핵심 클래스 2가지>
applet
- 가장 대표적인 Container. 전체 프로그램의 뼈대 담당.
- 웹브라우저에서 사용 가능한 프로그램을 만든다.
- 이제는 보안과 웹기술의 발전으로 거의 쓰지 않는다.
frame
- 일반데스크 탑에서 실행되는 응요 프로그램
- 가장 대표적인 Container. 전체 프로그램의 뼈대 담당.
package component;
import java.awt.Frame;
import java.awt.Label;
public class LabelTest {
public static void main(String[] args) {
//Label클래스의 인스턴스를 생성한다.
Label lab1 = new Label("첫번째 라벨"); //레이블 클래스는 바로 초기화가 가능하다.
Label lab2 = new Label("두번째 라벨");
Label lab3 = new Label("세번째 라벨");
//Label을 그릇에 담아야 사용이 가능하다.
//Frame클래스의 인스턴스를 생성한다.
Frame f = new Frame();
//재료들을 컨테이너에 담아준다.
f.add(lab1);
f.add(lab2);
f.add(lab3);
//화면 사이즈를 픽셀단위로 설정해준다.
f.setSize(300, 400);
//화면에 보여지게끔 설정을 해준다.
f.setVisible(true);
//프래임에 특성상 같은 위치에 겹쳐서 세번째만 보인다.
//종료는 콘솔의 빨간 버튼을 눌러 종료한다.
}
}
※ 결과값
프래임에 특성상 같은 위치에 겹쳐서 세번째만 보인다.
종료는 콘솔의 빨간 버튼을 눌러 종료한다.
프로그램에서 말하는 디자인은 공간 배치이다.
같은 코드를 Frame클래스를 상속받아 메인을 단순하게 만들어보자.
package component;
import java.awt.Frame;
import java.awt.Label;
public class LabelTest_1 extends Frame{
//인스턴스 변수를 미리 만들어준다.
private Label lab1, lab2, lab3;
LabelTest_1(){
//Label클래스의 인스턴스를 생성한다.
lab1 = new Label("첫번째 라벨"); //레이블 클래스는 클래스 특성상 바로 초기화가 가능하다.
lab2 = new Label("두번째 라벨");
lab3 = new Label("세번째 라벨");
//Label을 그릇에 담아야 사용이 가능하다.
//재료들을 컨테이너에 담아준다.
add(lab1);
add(lab2);
add(lab3);
//화면 사이즈를 픽셀단위로 설정해준다.
setSize(300, 400);
//화면에 보여지게끔 설정을 해준다.
setVisible(true);
}
public static void main(String[] args) {
//Frame클래스를 상속받아 LabelTest의 인스턴스를 생성한다. (?)
LabelTest_1 f = new LabelTest_1();
}
}
※ 결과값
<코드리펙토링>
- 코드리뷰
- 코드 전반적인 부분을 살펴보고 합리적이고 깔끔하게 고쳐나가는 작업
아래 예제를 실행해보자.
package component;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Label;
public class LabelTest_1 extends Frame{
//인스턴스 변수를 미리 만들어준다.
private Label lab1, lab2, lab3;
LabelTest_1(){
setLayout(new FlowLayout());
//Label클래스의 인스턴스를 생성한다.
lab1 = new Label("첫번째 라벨"); //레이블 클래스는 클래스 특성상 바로 초기화가 가능하다.
lab2 = new Label("두번째 라벨");
lab3 = new Label("세번째 라벨");
//Label을 그릇에 담아야 사용이 가능하다.
//재료들을 컨테이너에 담아준다.
add(lab1);
add(lab2);
add(lab3);
//각각의 라벨의 배경색깔을 바꾼다.
lab1.setBackground(Color.BLUE);
lab2.setBackground(Color.RED);
lab3.setBackground(Color.YELLOW);
//setSize(300, 400); //화면 사이즈를 픽셀단위로 설정해준다.
//300, 400은 가로세로 모니터에서 위치, 800, 600은 가로 세로 픽셀 크기
//화면크기와 실행 위치까지 정할 수 있다.
setBounds(300,400,800, 600);
//화면에 보여지게끔 설정을 해준다.(출력)
setVisible(true);
}
public static void main(String[] args) {
//Frame클래스를 상속받아 LabelTest의 인스턴스를 생성한다.
LabelTest_1 f = new LabelTest_1();
}
}
※ 결과값
package component;
import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Label;
public class ButtonTest extends Frame{
//인스턴스 변수를 미리 만들어준다.
private Button b1, b2, b3;
ButtonTest(){
setLayout(new FlowLayout());
//Label클래스의 인스턴스를 생성한다.
b1 = new Button("첫번째 라벨"); //레이블 클래스는 클래스 특성상 바로 초기화가 가능하다.
b2 = new Button("두번째 라벨");
b3 = new Button("세번째 라벨");
//Label을 그릇에 담아야 사용이 가능하다.
//재료들을 컨테이너에 담아준다.
add(b1);
add(b2);
add(b3);
//각각의 라벨의 배경색깔을 바꾼다.
b1.setBackground(Color.BLUE);
b2.setBackground(Color.RED);
b3.setBackground(Color.YELLOW);
//setSize(300, 400); //화면 사이즈를 픽셀단위로 설정해준다.
//300, 400은 가로세로 모니터에서 위치, 800, 600은 가로 세로 픽셀 크기
//화면크기와 실행 위치까지 정할 수 있다.
setBounds(300,400,800, 600);
//화면에 보여지게끔 설정을 해준다.(출력)
setVisible(true);
}
public static void main(String[] args) {
//Frame클래스를 상속받아 LabelTest의 인스턴스를 생성한다.
ButtonTest f = new ButtonTest();
}
}
※ 결과값
체크박스 : 다중선택
라디오 버튼 : 단일선택
체크박스를 라디오 버튼으로 만드는 방법은 그룹으로 묶는 것이다.
package component;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.FlowLayout;
import java.awt.Frame;
public class CheckboxTest extends Frame{
Checkbox c1, c2, c3;
Checkbox r1, r2;
CheckboxGroup g1;
CheckboxTest(){
setLayout(new FlowLayout()); // 위치를 잡는 레이아웃으로 추측
//체크박스를 만든다. 체크박스는 다중선택이 가능하다.
c1 = new Checkbox("첫번째 체크박스", true); // 체크박스에 미리 체크가 되도록 true값을 줌
c2 = new Checkbox("두번째 체크박스");
c3 = new Checkbox("세번째 체크박스");
g1 = new CheckboxGroup(); // 라디오 버튼을 만들기 위해 체크박스 그룹을 만든다.
// 라디오 버튼을 만든다. 라디오 버튼은 하나만 선택해야한다.
r1 = new Checkbox("첫번째 라디오", true, g1); //라디오 이름, 체크박스 선택유무, 그룹이름을 써준다.
r2 = new Checkbox("두번째 라디오", false, g1);
add(c1);
add(c2);
add(c3);
add(r1);
add(r2);
setSize(300, 400);
setVisible(true);
}
public static void main(String[] args) {
new CheckboxTest();//클래스를 호출하는 인스턴스 생성, 자기 자신이기 때문에 클래스 이름 생략
}
}
Choice 메서드를 써보자.
package component;
import java.awt.Choice;
import java.awt.Frame;
public class ChoiceTest extends Frame{
private Choice c;
ChoiceTest(){
c = new Choice();
c.add("홍길동");
c.add("임꺽정");
c.add("김유신");
c.add("강감찬");
add(c);
setSize(300, 400);
setVisible(true);
}
public static void main(String[] args) {
new ChoiceTest();
}
}
Choice
- 하나를 선택한다.
- 단일 선택만 가능
list
- 펼쳐서 보여준다. 기본적으로 1개만 선택
- 다중성택도 가능
package component;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.List;
public class ListTest extends Frame{
private List list1, list2;
ListTest(){
setLayout(new FlowLayout());
list1 = new List(5, true); //()인자는 출력될 아이템을 지정한다. 기본리스트는 4개이다.
list2 = new List(3);
list1.add("사과");
list1.add("배");
list1.add("포도");
list1.add("귤");
list1.add("레몬");
list2.add("짜장면");
list2.add("울면");
list2.add("라면");
list2.add("볶음면");
list2.add("짬짜면");
add(list1);
add(list2);
setSize(300, 400);
setVisible(true);
}
public static void main(String[] args) {
new ListTest();
}
}
//윈도우를 이용해서 야구게임을 만들어보자.
TextField, TextArea 를 사용해보자.
package component;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
public class TextTest extends Frame{
private TextField tf;
private TextArea ta;
TextTest(){
setLayout(new FlowLayout());
tf = new TextField(30); //한 줄입력, 크기를 늘리고 싶다면 인자의 값을 쓴다.
ta = new TextArea(5, 30); //여러 줄 입력, 행과 열의 크기를 입력할 수 있다.
add(tf);
add(ta);
setSize(600, 400);
setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new TextTest();
}
}
package component;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
public class TextTest extends Frame{
private TextField tf;
private TextArea ta;
TextTest(){
setLayout(new FlowLayout());
tf = new TextField("여기는 textfied",30); //한 줄입력, 크기를 늘리고 싶다면 인자의 값을 쓴다.
ta = new TextArea("여기는 TextArea", 5, 30); //여러 줄 입력, 행과 열의 크기를 입력할 수 있다.
add(tf);
add(ta);
setSize(600, 400);
setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new TextTest();
}
}
Container
panel
- 가장 대표적인 Container. 전체 프로그램의 뼈대 담당.
- 윈도우 안에서 부분적인 영역을 처리할 때 사용한다.
- 내가 필요한 부분 디자인을 따로 만들어 사용하고자 했을 때
접착제처럼 붙여 사용할 수 있도록 한다.
- 컨포넌트를 담을 수 있는 컨테이너가 패널이다.
package container;
import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Panel;
public class PanelTest extends Frame {
private Panel p1, p2;
private Button b1, b2, b3, b4;
PanelTest(){
setLayout(new FlowLayout());
p1 = new Panel();
p2 = new Panel();
b1 = new Button("패널 2 보이기");
b2 = new Button("패널 2 안보이기");
b3 = new Button("패널 1 보이기");
b4 = new Button("패널 1 안보이기");
p1.add(b1);
p1.add(b2);
p2.add(b3);
p2.add(b4);
add(p1);
add(p2);
setSize(300, 400);
setVisible(true);
}
public static void main(String[] args) {
new PanelTest();
}
}
package container;
import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Panel;
public class PanelTest extends Frame {
private Panel p1, p2;
private Button b1, b2, b3, b4;
PanelTest(){
setLayout(new FlowLayout());
//Label클래스의 인스턴스를 생성한다.
p1 = new Panel();
p2 = new Panel();
b1 = new Button("패널 2 보이기");
b2 = new Button("패널 2 안보이기");
b3 = new Button("패널 1 보이기");
b4 = new Button("패널 1 안보이기");
//재료들을 컨테이너에 담아준다.
p1.add(b1);
p1.add(b2);
p2.add(b3);
p2.add(b4);
add(p1);
add(p2);
//각각의 라벨의 배경색깔을 바꾼다.
p1.setBackground(Color.BLUE);
p2.setBackground(Color.MAGENTA);
//화면크기와 실행 위치까지 정할 수 있다.
setSize(300, 400);
//화면에 보여지게끔 설정을 해준다.(출력)
setVisible(true);
}
public static void main(String[] args) {
new PanelTest();//클래스를 호출하는 인스턴스 생성, 자기 자신이기 때문에 클래스 이름 생략
}
}
이벤트를 넣어보자.
이벤트는 마우스로 클릭하거나 하는 등의 컴퓨터 상에서 벌어지는 모든 사건을 말한다.
package container;
import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class PanelTest extends Frame implements ActionListener{
private Panel p1, p2;
private Button b1, b2, b3, b4;
PanelTest(){
setLayout(new FlowLayout());
//Label클래스의 인스턴스를 생성한다.
p1 = new Panel();
p2 = new Panel();
b1 = new Button("패널 2 보이기");
b2 = new Button("패널 2 안보이기");
b3 = new Button("패널 1 보이기");
b4 = new Button("패널 1 안보이기");
//재료들을 컨테이너에 담아준다.
p1.add(b1);
p1.add(b2);
p2.add(b3);
p2.add(b4);
add(p1);
add(p2);
//각각의 라벨의 배경색깔을 바꾼다.
p1.setBackground(Color.BLUE);
p2.setBackground(Color.MAGENTA);
//버튼이 눌리면 ActionListener 메서드가 호출되도록 한다.
b1.addActionListener(this);
//화면크기와 실행 위치까지 정할 수 있다.
setSize(300, 400);
//화면에 보여지게끔 설정을 해준다.(출력)
setVisible(true);
}
//ActionListener 상속받아 메서드를 오버라이드 한다. 버튼을 누르면 메서드가 호출돤다.
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("버튼이 눌렸어요~~~");
}
public static void main(String[] args) {
new PanelTest();//클래스를 호출하는 인스턴스 생성, 자기 자신이기 때문에 클래스 이름 생략
}
}
※ 결과값
이처럼 첫번째 버튼을 누르면 "버튼을 눌렀어요가 이클립스에 찍힌다.
package container;
import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class PanelTest extends Frame implements ActionListener{
private Panel p1, p2;
private Button b1, b2, b3, b4;
PanelTest(){
setLayout(new FlowLayout());
//Label클래스의 인스턴스를 생성한다.
p1 = new Panel();
p2 = new Panel();
b1 = new Button("패널 2 보이기");
b2 = new Button("패널 2 안보이기");
b3 = new Button("패널 1 보이기");
b4 = new Button("패널 1 안보이기");
//재료들을 컨테이너에 담아준다.
p1.add(b1);
p1.add(b2);
p2.add(b3);
p2.add(b4);
add(p1);
add(p2);
//각각의 라벨의 배경색깔을 바꾼다.
p1.setBackground(Color.BLUE);
p2.setBackground(Color.MAGENTA);
//버튼이 눌리면 ActionListener 메서드가 호출되도록 한다.
b1.addActionListener(this); // ActionEvent 메서드와 같은 클래스에 있기 때문에 this
b2.addActionListener(this);
b3.addActionListener(this);
b4.addActionListener(this);
//화면크기와 실행 위치까지 정할 수 있다.
setSize(300, 400);
//화면에 보여지게끔 설정을 해준다.(출력)
setVisible(true);
}
//ActionListener 상속받아 메서드를 오버라이드 한다. 버튼을 누르면 메서드가 호출돤다.
@Override
public void actionPerformed(ActionEvent arg0) {
/*
System.out.println(arg0);
System.out.println(arg0.getActionCommand()); //버튼이 가지고 있는 레이블 값만 뽑아온다.
System.out.println("버튼이 눌렸어요~~~");
*/
String cmd = arg0.getActionCommand(); //버튼이 가지고 있는 레이블 값만 뽑아온다.
if(cmd.equals("패널 2 보이기")) {
p2.setVisible(true);
}else if(cmd.equals("패널 2 안보이기")) {
p2.setVisible(false);
}else if(cmd.equals("패널 1 보이기")) {
p1.setVisible(true);
}else {
p1.setVisible(false);
}
}
public static void main(String[] args) {
new PanelTest();//클래스를 호출하는 인스턴스 생성, 자기 자신이기 때문에 클래스 이름 생략
}
}
※ 결과값
Frame
dispose()는 윈도우를 종료하는 윈도우 클래스의 메서드이다.
package container;
import java.awt.Button;
import java.awt.Frame;
public class FrameTest extends Frame{
private Button b;
FrameTest(){
b = new Button("버튼");
add(b);
setSize(300, 400);
setVisible(true);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
dispose(); // 윈도우를 종료시키는 메서드이다.
}
public static void main(String[] args) {
new FrameTest();
}
}
※ 결과값
버튼을 켜면 3초 후에 꺼진다.
package container;
import java.awt.Button;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.rmi.MarshalledObject;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.activation.ActivationDesc;
import java.rmi.activation.ActivationException;
import java.rmi.activation.ActivationID;
import java.rmi.activation.ActivationInstantiator;
public class FrameTest extends Frame implements ActionListener{
private Button b;
FrameTest(){
b = new Button("버튼");
add(b);
b.addActionListener(this);
setSize(300, 400);
setVisible(true);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
dispose(); // 윈도우를 종료시키는 메서드이다.
}
@Override
public void actionPerformed(ActionEvent e) {
dispose(); // 윈도우를 종료시키는 메서드이다.
}
public static void main(String[] args) {
new FrameTest();
}
}
※ 결과값
버튼의 x버튼을 누르면 없어진다.
2) Dialog
Window : 아무것도 없다.
- Dialog : 별도의 재료들로 만들어 줄 수 있다.
패널은 한번 붙이면 위치가 고정되지만,
Dialog는 창이 움직인다.
프로그램과 사용자 사이에서 소통창구가 되게 한다.
별도의 창이 사용되는 것은 Dialog가 대부분 이다.
서브윈도우로 사용된다.
자식클래스는 filrDialog가 있다.
(1) Custom(User Define) Dialog
다이얼로그는 서브 윈도우다.
다이얼로그를 내 마음대로 만들 수 있다.
다이얼로그를 그냥 상속받으면 커스텀 다이얼로그가 된다.
다이얼로그는 누가 나를 호출했는지가 가장 중요하다.
Dialog에서 가장 많이 사용하는 생성자
Dialog(Frame owner, String title, boolean modal)
생성자를 가장 많이 이용한다.
Frame owner
- 이 다이얼로그를 생성한 객체의 주소
String title
- 다이얼로그의 주소
- 새 창 다이얼로그의 타이틀
- 예) 메모장 - 다른이름으로 저장
boolean modal
- 다이얼로그의 실행방식이다.
- true false 중에 하나를 쓰면 된다.
- true 이면 madal방식이고 false는 modaless방식이다.
<modaless 과 modal>
modal
- 현재 윈도우를 종료하기 전 까지 다른 작업을 할 수 없게 하는 것이 modal방식이다. (modal 이 대부분이다.)
modaless
- modal의 반대. 현재 실행 중인 윈도우를 종료하지 않아도 다른 작업을 병행할 수 있는 상태.
훨씬 어렵고 신경써야 할 것이 많다.
(2) Common(System) Dialog
이미 만들어져있는 다이얼로그이다.
메모장의 파일열기 같이 운영체제가
미리 만들어 놓은 다이얼로그를 가져다가 쓰는 것이다.
FileDialog가 이에 해당한다.
package container;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dialog;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class MessageDialog extends Dialog implements ActionListener{
private String message;
//Dialog 자식클래스 생성자를 만들었다.
public MessageDialog(Frame arg0, String msg) { //생성자의 인자값을 넣어 준다.
super(arg0, "메시지 대화상자", true); // Dialog를 만들 때에는 반드시 부모 생성자를 호출해주어야 한다.
setLayout(new FlowLayout()); //자동정렬됨
message = msg; //생성자의 인자값을 불러온다.
Label lab = new Label(message);
add(lab);
Button b = new Button("종료");
add(b);
setBackground(Color.GRAY);
b.addActionListener(this);
setSize(200, 300);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
}
public class CustomDialogTest extends Frame implements ActionListener{
private Panel p;
private Button b1, b2;
public CustomDialogTest() {
p = new Panel();
b1 = new Button("다이얼로그 열기");
b2 = new Button("종료");
p.add(b1);
p.add(b2);
add(p);
b1.addActionListener(this);
setSize(300, 400);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
new MessageDialog(this, "이것은 메인에서 전달하는 메시지"); //현재 실행된 자기 자신의 주소를 넣어준다.
}
public static void main(String[] args) {
new CustomDialogTest();
}
}
본래 생성자의 목적에 맞게 디팩토링 하고 기능을 추가해보자.
package container;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dialog;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class MessageDialog extends Dialog implements ActionListener{
private String messge;//생성자의 인자값을 불러온다.
private Label lab;
private Button b;
//Dialog 자식클래스 생성자를 만들었다.
public MessageDialog(Frame arg0, String msg) { //생성자의 인자값을 넣어 준다.
super(arg0, "메시지 대화상자", true); // Dialog를 만들 때에는 반드시 부모 생성자를 호출해주어야 한다.
lab = new Label(msg);
b = new Button("종료");
}
void display() {
setLayout(new FlowLayout()); //자동정렬됨
add(lab);
add(b);
setBackground(Color.GRAY);
b.addActionListener(this);
setSize(200, 300);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
}
public class CustomDialogTest extends Frame implements ActionListener{
private Panel p;
private Button b1, b2;
public CustomDialogTest() {
p = new Panel();
b1 = new Button("다이얼로그 열기");
b2 = new Button("종료");
p.add(b1); //패널에 버튼 추가
p.add(b2);
add(p); //패널호출
b1.addActionListener(this);
setSize(300, 400);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
MessageDialog md = new MessageDialog(this, "이것은 메인에서 전달하는 메시지"); //현재 실행된 자기 자신의 주소를 넣어준다.
md.display();
}
public static void main(String[] args) {
new CustomDialogTest();
}
}
package container;
import java.awt.Button;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class CommonDialogTest extends Frame implements ActionListener{
FileDialog fopen, fsave;
Panel p;
Button btnOpen, btnSave;
public CommonDialogTest() {
p = new Panel(); //패널의 인스턴스 생성
btnOpen = new Button("파일 열기");
btnSave = new Button("파일 저장");
//첫번째는 주소값, 두번째는 title, 세번째는 파일열기 or 저장하기로 할건지 지정 옵션
fopen = new FileDialog(this, "파일 열기", FileDialog.LOAD);
//첫번째는 주소값, 두번째는 title, 세번째는 파일열기 or 저장하기로 할건지 지정 옵션
fsave = new FileDialog(this, "파일 저장", FileDialog.SAVE);
p.add(btnOpen);
p.add(btnSave);
add(p);
btnOpen.addActionListener(this);
btnSave.addActionListener(this);
}
@Override //버튼을 눌렀을 때 행동하도록 상속받아 연결
public void actionPerformed(ActionEvent arg0) {
if(arg0.getActionCommand().equals("파일 열기")) {
fopen.setVisible(true); //fopen을 불러와 보여준다.
System.out.println(fopen.getDirectory()); //현재 선택한 파일의 경로를 보여준다.
System.out.println(fopen.getFile()); //현재 선택한 파일의 주소를 보여준다.
}else {
fsave.setVisible(true); //fsave을 불러와 보여준다.
}
}
public static void main(String[] args) {
CommonDialogTest test = new CommonDialogTest();
test.setSize(300, 400);
test.setVisible(true);
}
}
5. Layout
1) Layout 매니저
메인윈도우가 커지든 안커지든 상관없이 중간에 매니저가 레이아웃 배치를 대신해준다.
이렇세 배치를 처리해주는 클래스를 layout 매니저라고 한다.
- FlowLayout : 기본매니저
- BorerLayout : 기본매니저
- GridLayout
- GridBagLayout
- CardLayout
<FlowLayout>
크기가 크거나 작아져도 변화된다. (기본매니저)
package layout;
import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.Frame;
public class FlowLayoutTest extends Frame{
Button b1, b2, b3, b4, b5; //버튼을 인스턴스 변수를 선언한다.
public FlowLayoutTest() { //생성자
setLayout(new FlowLayout()); //FlowLayout() 크기가 크거나 작아져도 변화된다.
//setLayout() 어떤식으로 배치할지 매니저를 선택해준다.
b1 = new Button("첫번째 버튼"); //버튼 인스턴스를 생성한다.
b2 = new Button("두번째 버튼");
b3 = new Button("세번째 버튼");
b4 = new Button("네번째 버튼");
b5 = new Button("다섯번째 버튼");
add(b1); //프레임에 b1버튼을 추가해서 화면에 보이게 한다.
add(b2);
add(b3);
add(b4);
add(b5);
}
public static void main(String[] args) {
FlowLayoutTest test = new FlowLayoutTest(); //클래스 인스턴스 생성
test.setSize(300, 400); //사이즈를 정함
test.setVisible(true); //창이 보여지게 함
}
}
※ 결과값
<BorerLayout>
왼쪽, 오른쪽, 위쪽, 아래쪽, 가운데 다섯 곳에 테두리를 기준으로 배치하는 방법 (기본매니저)
위치를 지정하지 않으면 계속 같은 곳에 나온다.
왼쪽일 때에는 west
오른쪽 일 때는 East
아래는 South
위에는 North
가운데는 center
인자값을 쓸 때 첫글자는 반드시 대문자여야한다.
package layout;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Frame;
public class BorderLayoutTest extends Frame{
Button b1, b2, b3, b4, b5; //버튼을 인스턴스 변수를 선언한다.
public BorderLayoutTest() { //생성자
setLayout(new BorderLayout()); //BorerLayout () 테두리를 기준으로 배치
//setLayout() 어떤식으로 배치할지 매니저를 선택해준다.
b1 = new Button("첫번째 버튼"); //버튼 인스턴스를 생성한다.
b2 = new Button("두번째 버튼");
b3 = new Button("세번째 버튼");
b4 = new Button("네번째 버튼");
b5 = new Button("다섯번째 버튼");
add("North",b1); //프레임에 b1버튼을 추가해서 화면에 보이게 한다.
add("South",b2); //인자에 어디에 배치할지 값을 넣어준다.
add("East",b3);
add("West",b4);
add("Center",b5);
}
public static void main(String[] args) {
BorderLayoutTest test = new BorderLayoutTest(); //클래스 인스턴스 생성
test.setSize(300, 400); //사이즈를 정함
test.setVisible(true); //창이 보여지게 함
}
}
※ 결과값
<Container의 기본 매니저>
Container 는 기본으로 매니저를 가지고 있다.
Panel의 경우는 기본레이아웃이 FlowLayout이며,
Applet과 같은자식클래스도 마찬가지 이다.
Window의 경우 기본 레이아웃이 BorerLayout 이며,
Dialog FileDialog, Frame 과 같은 자식 클래스도 마찬가지 이다.
<GridLayout>
규격이 있는 테이블(표)을 만들어준다.
행과열을 지정하여 격자를 지정할 수 있는 레이아웃
Flowlayout과는 달리 정해진 행과 열의 갯수가 바뀌지 않는다.
package layout;
import java.awt.Button;
import java.awt.Frame;
import java.awt.GridLayout;
public class GridLayoutTest extends Frame{
Button b1, b2, b3, b4, b5; //버튼을 인스턴스 변수를 선언한다.
public GridLayoutTest() { //생성자
setLayout(new GridLayout(2,3)); //GridLayout() 행과열을 지정하여 격자를 지정할 수 있는 레이아웃
//2행 3열 짜리 칸을 만들고 배치하겠다.
//setLayout() 어떤식으로 배치할지 매니저를 선택해준다.
b1 = new Button("첫번째 버튼"); //버튼 인스턴스를 생성한다.
b2 = new Button("두번째 버튼");
b3 = new Button("세번째 버튼");
b4 = new Button("네번째 버튼");
b5 = new Button("다섯번째 버튼");
add(b1); //프레임에 b1버튼을 추가해서 화면에 보이게 한다.
add(b2);
add(b3);
add(b4);
add(b5);
}
public static void main(String[] args) {
GridLayoutTest test = new GridLayoutTest(); //클래스 인스턴스 생성
test.setSize(300, 400); //사이즈를 정함
test.setVisible(true); //창이 보여지게 함
}
}
※ 결과값
<GridBagLayout>
불규칙한 테이블(표)을 만들 수 있다.
자세한 사용법은 API의
java.desktop > java.awt > GridLayout 클래스 항목을 참고하면 된다.
https://docs.oracle.com/javase/9/docs/api/index.html?overview-summary.html
<CardLayout>
같은 화면으로 여러개의 페이지를 보여주고자 했을 때
각각 버튼 누를 때마다 몇 깨의 화면을 따로따로 보여줬을 때
이벤트가 같이 나와야 한다.
package layout;
import java.awt.Button;
import java.awt.CardLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
//이벤트를 처리하기 위해서는 반드시 ActionListener 상속이 필요하다.
public class CardLayoutTest extends Frame implements ActionListener{
Button b1, b2, b3, b4, b5; //버튼을 인스턴스 변수를 선언한다.
CardLayout card; //인스턴스 변수를 생성한다.
public CardLayoutTest() { //생성자
card = new CardLayout(); //CardLayout()인스턴스 변수를 생성한다.
setLayout(card); //CardLayout() 같은 화면으로 여러개의 페이지를 보여주고자 했을 때
// CardLayout()은 반드시 이벤트가 필요하다.
//setLayout() 어떤식으로 배치할지 매니저를 선택해준다.
b1 = new Button("첫번째 버튼"); //버튼 인스턴스를 생성한다.
b2 = new Button("두번째 버튼");
b3 = new Button("세번째 버튼");
b4 = new Button("네번째 버튼");
b5 = new Button("다섯번째 버튼");
add(b1); //프레임에 b1버튼을 추가해서 화면에 보이게 한다.
add(b2);
add(b3);
add(b4);
add(b5);
b1.addActionListener(this); //이벤트를 위해 액션리스너에 b1을 추가한다.
b2.addActionListener(this);
b3.addActionListener(this);
b4.addActionListener(this);
b5.addActionListener(this);
}
@Override //상속을 하였음으로 액션리스너 메서드를 오버라이드한다.
public void actionPerformed(ActionEvent e) {
card.next(this);
}
public static void main(String[] args) {
CardLayoutTest test = new CardLayoutTest(); //클래스 인스턴스 생성
test.setSize(300, 400); //사이즈를 정함
test.setVisible(true); //창이 보여지게 함
}
}
<주로 쓰이는 레이아웃>
Layout중에서는
FlowLayout, BroderLayout, gridLayout
가 주로 쓰이며 나머지는 AWT이후에 나온 Swing에
이미 더 좋은 기능이 나와있기 떄문에 참고만 하면 된다.
지금까지 재료(Component)와 디자인(Layout)을 알아보았다.
이제 동작(Event)을 알아보자
6. 동작(Event)
- 어떤 사건이 일어나는 것을 말한다.
- 이벤트에는 세 가지 요소가 있다.
1) 이벤트 소스 (컴퍼넌트)
- 원본, 진원지
- 어디에서 사건이 발생했는가? 위치를 파악한다.
- 위치는 결국 재료(Component)를 말한다.
- 어느 Component에서 사건이 일어났는지를 가장 먼저 파악해야한다.
2) 이벤트 클래스 (어떤사건?)
(1) 어떤 사건인지를 사건의 종류를 파악한다.
예) 클릭을 했는지, 더블클릭을 했는지, 드레그를 헀는지 알아본다.
(2) java.util.EventObject ( java.base > java.util > EventObject) 에
java의 모든 Event 클래스, 사건관련 클래스가 들어있다.
자식클래스를 보면 AWTEvent가 있음을 볼 수 있다.
(3) AWTEvent에서 중요한 자식클래스는 아래 다섯 가지이다.
①ActionEvent
- 컴퍼넌트가 활성화 될 때 발생하는 이벤트
- 컴퍼넌트를 무언가 선택하면 선택된 표시가 발생하는 이벤트
- 선택만 하면 발생하기 때문에 거의 모든 이벤트에 발생한다.
②AdjustmentEvent
- 소리음량 조절 스크롤 바와 같이 조정가능한 컴퍼넌트에서
조정이 일어날 때 발생한다.
- 스크롤바를 선택하면 윈도우도 선택되기 때문에 AdjustmentEvent와
ActionEvent도 함께 발생된다.
- 하지만 프로그래밍에서는 함께 발생된다고 하더라고 한개만 처리해야한다.
- ActionEvent는 선택 뿐만 아니라 어떤 위치 값을 가지고 있는지도 나온다.
- 똑같이 발생해도 어떤 선택을 할 것인가에 따라서 표면적으로 사용하는 클래스가 달라진다.
③ComponentEvent
- 자식에게 물려주기 위한 용도이다. 아래의 자식클래스들이 실제로 사용된다.
└ ContainerEvent
- 컨테이너의 컴퍼넌트가 추가/삭제되는 경우 발생하는 이벤트
- 실행중에 원래 없던 디자인이 추가되거나 이미 있던 디자인이 삭제되면 쓴다.
- 동적 디자인의 경우 사용되지만 거의 쓸 일은 없다.
└ FocusEvent
- 컴퍼넌트에 포커스가 들어왔을 때 발생하는 이벤트
- 키보드나 마우스를 특정 텍스트 박스를 눌렀을 때 깜박거리면 발생하는 이벤트
- 무언가 관심을 받았을 때 발생하는 이벤트이다.
- 액션이벤트와 겹친다.
└ Inputevent
- 입력할 때마다 발생하는 이벤트.
- 인풋 이벤트 자체는 사용되지 않으면 자식클래스가 사용된다.
└ KeyEvent : 키를 입력할 때 발생한다.
└ MouseEvent : 마우스를 클릭하거나 움직일 때 발생한다.
└ PaintEvent
- 그래픽이나 멀티미디어 쪽에서 쓰이게 된다.
- 컴퍼넌트가 다시 그려질 때 발생하는 이벤트
- 화면에서 새 창을 열었다가 닫았을 때 창이 지워졌다가 다시 그려지는 것이다.
- 무언가 가렸다가 치웠을 때 다시 그리면서 발생한다.
- MouseEvent와 겹친다.
└ WindowEvent
- 윈도우가 활성화 또는 닫힐 때 발생하는 이벤트
- 액션이벤트와 겹친다.
④ItemEven
- 리스트, 초이스와 같이 선택항목이 존재하는
컴퍼넌트에서 선택항목이 선택 될 때 발생하는 이벤트
- 리스트에서 선택항목에 무언가를 선택할 때
액션, 포커스, 마우스, 윈도우 많은 이벤트가 겹친다.
이렇게 여러 이벤트가 겹칠 때에도 내가 원하는 행동에서
가장 가까운 것이 아이템 이벤트라면 아이템 이벤트를 선택하면 된다.
⑤TextEvent
- 텍스트 컴퍼넌트(글자를 입력할 수 있는 컴퍼넌트)의 내용이 변화될 때 발생하는 이벤트
- 글자는 쓰거나 수정 할 때 사용한다.
- 키 이벤트와 겹치지만 용도가 다르기 때문에 예제를 반복하면 쓰임을 알 수 있다.
3) 이벤트 핸들러 (처리, 인터페이스로 만들어져 있음)
이벤트핸들러는 이벤트를 어떻게 처리할지 조정한다.
- 사건에 따라 대응 메뉴얼이 있다.
- 대응 메뉴얼에 따라 사건처리를 한다.
- 클래스가 아닌 인터페이스로 만들어져 있다.
- 이벤트만 처리하는 인터페이스를 '리스너(listener) 인터페이스'라고 한다.
- 이벤트는 스윙을 해도 달라지지 않는다.
java.desktop > java.awt.event
- api를 보면 리스너 인터페이스 이름이 클래스 이름과 비슷하다는 것을 알 수 있다.
- 리스너 인터페이스는 이벤트클래스를 처리하기 위해서 나온 인터페이스이다.
- 어떤 이벤트 클래스를 쓸지 알아야 리스너 인터페이스를 쓸 수 있다.
- 거의 특별한 정보가 아니라면 액션 이벤트를 쓴다.
4) 이벤트소스와 핸들러의 연결
- 이벤트소스.add 이벤트클래스Listener(핸들러의 주소);
5) 이벤트 코드 처리 방식
① 이벤트 소스와 이벤트 핸들러가 같은 클래스인 경우 : 지금까지 했던 모든 예제
② 이벤트 소스와 이벤트 핸들러가 다른 클래스인 경우
③ 이벤트 핸들러가 내부 클래스인 경우
④ 이벤트 핸들러가 무명 클래스인 경우
- 일반적인 경우 취향의 따라서 하면 된다
① 이벤트 소스와 이벤트 핸들러가 같은 클래스인 경우 : 지금까지 했던 모든 예제
package event;
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
//버튼을 클릭하면 활성화 될 수 있도록 액션리스너를 상속받는다.
public class EventTest1 extends Frame implements ActionListener{
private Button btn1, btn2; //인스턴스변수를 생성한다.
private TextArea ta;
EventTest1(){ //생성자를 생성한다
btn1 = new Button("눌러주세요."); //인스턴스를 생성한다.
btn2 = new Button("종료");
ta = new TextArea();
add("North", btn1); //화면에 보이도록 Frame에 위치를 지정해 더해준다.
add("Center", ta);
add("South", btn2);
btn1.addActionListener(this); // 버튼을 핸들러에 연결한다.
btn2.addActionListener(this); // 버튼을 핸들러에 연결한다.
}
@Override //이벤트핸들러이다. 이벤트를 어떻게 처리할지 조정한다.
public void actionPerformed(ActionEvent arg0) {
//String cmd = arg0.getActionCommand(); //현재 이벤트소스의 레이블값을 가져온다.
// -----아래 두줄과 위에 주석처리 된 한 줄과 같다.------
// 이벤트소스가 가진 모든 기능을 쓸 수 있도록 넘겨준다.
// 부모클래스와 자식클래스의 참조관계를 살펴보자.
// 자식클래스에 다시 넘겨서 자식이 가진 기능을 다 쓸 수 있게 한다.
//.getSource()는 자식 클래스의 모든 메소드를 쓸 수 있게 해준다.
Button btn = (Button)arg0.getSource();
// 현재 이벤트 소스의 레이블값을 가져온다.
// 부모클래스 + 버튼의 모든 기능을 쓸 수 있다.(상속에서 부모자식간의 참조관계 참고)
// 부모클래스의 더 많은 기능을 쓰고 싶을 때 사용한다.
String cmd = btn.getLabel();
if(cmd.equals("눌러주세요.")) { //cmd의 텍스트가 같다면
btn.setBackground(Color.GREEN); //컬러를 바꾸고
ta.setText(ta.getText() + "버튼이 눌렸어요.\n"); //버튼이 눌렀어요가 입력된다.
} else {
dispose(); //아니면 사라진다.
}
}
public static void main(String[] args) {
//TODO 이벤트 소스와 핸들러가 같은 클래스인 경우
EventTest1 test = new EventTest1(); // 인스턴스를 생성한다.
test.setSize(300, 400);
test.setVisible(true);
}
}
※ 결과값
② 이벤트 소스와 이벤트 핸들러가 다른 클래스인 경우
- 이벤트를 클래스가 공동으로 쓸 경우에 사용한다.
package event;
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class EventHandler implements ActionListener{
private TextArea ta; //EventTest2의 변수를 쓰려면 Getter and Setter를 쓰든지, 생성자를 호출할 불러오면 된다.
private Button btn1, btn2; //버튼 변수를 선언한다.
private Frame f; //EventTest2의 주소값을 넘겨받을 변수를 선언한다.
EventHandler(TextArea ta, Button btn1, Button btn2, Frame f){ //생성자를 써서 변수를 호출한다.
this.ta = ta; // 핸들러주소값의 변수 ta에 EventTest2변수 ta를 넣겠다.
this.btn1 = btn1; // 핸들러주소값의 변수 btn1에 EventTest2변수 btn1를 넣겠다.
this.btn2 = btn2; // 핸들러주소값의 변수 btn2에 EventTest2변수 btn2를 넣겠다.
this.f = f; // 핸들러주소값을 EventTest2 변수f를 넣겠다.
}
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
String cmd = arg0.getActionCommand(); //현재 이벤트소스의 레이블값을 가져온다.
if(cmd.equals("눌러주세요.")) { //cmd의 텍스트가 같다면
btn1.setBackground(Color.GREEN); //컬러를 바꾸고
ta.setText(ta.getText() + "버튼이 눌렸어요.\n"); //버튼이 눌렀어요가 입력된다.
}else {
f.dispose();
}
}
}
//버튼을 클릭하면 활성화 될 수 있도록 액션리스너를 상속받는다.
public class EventTest2 extends Frame {
private Button btn1, btn2; //인스턴스변수를 생성한다.
private TextArea ta;
EventTest2(){ //생성자를 생성한다
btn1 = new Button("눌러주세요."); //인스턴스를 생성한다.
btn2 = new Button("종료");
ta = new TextArea();
add("North", btn1); //화면에 보이도록 Frame에 위치를 지정해 더해준다.
add("Center", ta);
add("South", btn2);
// 핸들러 클래스의 인스턴스를 생성한다.
// 다른 클래스에 있는 경우 핸들러에 인스턴스 변수와 주소값을 인자값에 넘겨준다.
EventHandler handler = new EventHandler(ta, btn1, btn2, this);
btn1.addActionListener(handler); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.
btn2.addActionListener(handler); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.
}
public static void main(String[] args) {
//TODO 이벤트 소스와 핸들러가 다른 클래스인 경우
EventTest2 test = new EventTest2(); // 인스턴스를 생성한다.
test.setSize(300, 400);
test.setVisible(true);
}
}
※ 결과값
③ 이벤트 핸들러가 내부 클래스인 경우
- 이벤트를 클래스가 공동으로 쓰지 않고 자기만 쓰는 것이라면 내부클래스가 편하다.
package event;
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
//버튼을 클릭하면 활성화 될 수 있도록 액션리스너를 상속받는다.
public class EventTest2_1 extends Frame {
private Button btn1, btn2; //인스턴스변수를 생성한다.
private TextArea ta;
EventTest2_1(){ //생성자를 생성한다
btn1 = new Button("눌러주세요."); //인스턴스를 생성한다.
btn2 = new Button("종료");
ta = new TextArea();
add("North", btn1); //화면에 보이도록 Frame에 위치를 지정해 더해준다.
add("Center", ta);
add("South", btn2);
// 핸들러 클래스의 인스턴스를 생성한다.
// 다른 클래스에 있는 경우 핸들러에 인스턴스 변수와 주소값을 인자값에 넘겨준다.
EventHandler handler = new EventHandler();
btn1.addActionListener(handler); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.
btn2.addActionListener(handler); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.
}
class EventHandler implements ActionListener{ //내부클래스의 기능을 모두 쓴다.
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
String cmd = arg0.getActionCommand(); //현재 이벤트소스의 레이블값을 가져온다.
if(cmd.equals("눌러주세요.")) { //cmd의 텍스트가 같다면
btn1.setBackground(Color.GREEN); //컬러를 바꾸고
ta.setText(ta.getText() + "버튼이 눌렸어요.\n"); //버튼이 눌렀어요가 입력된다.
}else {
dispose();
}
}
}
public static void main(String[] args) {
//TODO 이벤트 소스와 핸들러가 다른 클래스인 경우
EventTest2_1 test = new EventTest2_1(); // 인스턴스를 생성한다.
test.setSize(300, 400);
test.setVisible(true);
}
}
※ 결과값
④ 이벤트 핸들러가 무명 클래스인 경우
- 액션리스너는 이벤트 핸들러를 상속받아 만들어주는 구현체이다.
액션 리스너가 있는 클래스는 한 번 만 쓰는 핸들러이기 때문에 축약해서 사용 할하는 문법을 만들었다.
<무명클래스>
- 인터페이스를 상속받는 별도의 구현체인 클레스를 만들지 않고 축약해서 만드는 방식
- 인터페이스로부터 클래스를 상속받아 클래스로 만들어야하는 과정을 생략한다.
- 하지만 클래스 이름은 없기 때문에 무명클래스라고 한다.
- 딱 한번만 만든다. 재활용 목적이 아니다.
- 무명클래스는 생성자를 만들 수 없다.
- 생성자를 쓸 수 없기 때문에 인자를 받지 못한다.
package event;
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
//버튼을 클릭하면 활성화 될 수 있도록 액션리스너를 상속받는다.
public class EventTest2_2 extends Frame {
private Button btn1, btn2; //인스턴스변수를 생성한다.
private TextArea ta;
EventTest2_2(){ //생성자를 생성한다
btn1 = new Button("눌러주세요."); //인스턴스를 생성한다.
btn2 = new Button("종료");
ta = new TextArea();
add("North", btn1); //화면에 보이도록 Frame에 위치를 지정해 더해준다.
add("Center", ta);
add("South", btn2);
//클래스를 메서드안에서 직접 만들어 버린다.
//인터페이스로부터 클래스를 상속받아 클래스로 만들어야하는 과정을 생략
//클래스 이름은 없기 때문에 무명클래스라고 한다.
//자바5 부터 추가된 문법이다.
ActionListener listen = new ActionListener() { //딱 한 번만 만든다.
@Override
public void actionPerformed(ActionEvent arg0) {
String cmd = arg0.getActionCommand(); //현재 이벤트소스의 레이블값을 가져온다.
if(cmd.equals("눌러주세요.")) { //cmd의 텍스트가 같다면
btn1.setBackground(Color.GREEN); //컬러를 바꾸고
ta.setText(ta.getText() + "버튼이 눌렸어요.\n"); //버튼이 눌렀어요가 입력된다.
}else {
dispose();
}
}
};
btn1.addActionListener(listen); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.
btn2.addActionListener(listen); // 버튼을 핸들러에 연결한다. 인자값에 핸들러를 호출한다.
}
public static void main(String[] args) {
//TODO 이벤트 소스와 핸들러가 다른 클래스인 경우
EventTest2_2 test = new EventTest2_2(); // 인스턴스를 생성한다.
test.setSize(300, 400);
test.setVisible(true);
}
}
※ 결과값
6. Adapter Class 어댑터클래스
Adapter Class는 왜 필요할까?
Interface MouseListener 안에 클래스를 살펴보자
mouseCliked 버튼을 클릭했을 때 발생하는 이벤트
mouseEntered 마우스가 버튼으로 들어갔을 때 발생하는 이벤트
mouseExited 마우스를 버튼 밖으로 나왔을 때 사용하는 이벤트
mousePressed 마우스를 눌렀을 때 발생하는 이벤트
mouseReleased 마우스를 눌렀다가 띄었을 때 발생하는 이벤트
mousePressed + mouseReleased = mouseCliked
앞에서는 액션리스너를 주로 상속 받았다.
액션리스너는 추상메서드가 하나밖에 없었기 때문에 오버라이딩도 하나만 했다.
그러나 마우스 리스너의 경우만 보아도 오버라이딩를 추상메서드 5개를 해야한다.
그렇게되면 코드가 너무 지저분해진다.
인터페이스를 미리 오버라이딩 해놓은 클래스를 어댑터 클래스라고 한다.
인터페이스를 중간에 미리 오버라이딩 해놓은 어댑터 클래스를
내가 필요한 메서드만 상속받기 위해서 상속한다.
MouseEvent
MouseAdapter
처럼,
각각의 리스너는 어댑터 클래스가 따로 있다.
메서드가 2개 이상 되는 리스너들만이 메서드가 있다.
액션리스너처럼 메서드가 1개 밖에 없는 리스너는 어댑터가 없다.
있을 필요가 없기 때문이다.
<어댑터 클래스를 이용하기 전>
package event;
import java.awt.Button;
import java.awt.Frame;
import java.awt.TextField;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class AdapterTest extends Frame implements WindowListener{
private TextField tf; //인스턴스 변수를 생성
private Button btnExit;
@Override
public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowClosed(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub
dispose();
}
@Override
public void windowDeactivated(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowDeiconified(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowIconified(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowOpened(WindowEvent e) {
// TODO Auto-generated method stub
}
public AdapterTest() {
tf = new TextField("x버튼을 누르면 종료합니다."); //인스턴스 생성
btnExit = new Button("종료");
add("North", tf);
add("Center", btnExit);
//윈도우리스너를 상속받아야 X버튼에 접근 할 수 있다.
//Frame 자체가 window의 포함되기 때문에 따로 이벤트 소스를 적지 않는다. (window만 해당된다.)
//같은 클래스에서 호출하기 때문에 this를 쓴다.
addWindowListener(this);
}
public static void main(String[] args) {
AdapterTest test = new AdapterTest();
test.setSize(300, 400);
test.setVisible(true);
}
}
※ 결과값
<어댑터 클래스를 이용할 때>
- 이벤트 소스와 이벤트 핸들러가 다른 클래스인 경우를 참고한다.
package event;
import java.awt.Button;
import java.awt.Frame;
import java.awt.TextField;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
//쓸데없는 오버라이딩을 줄이기 위해 사용하는 어댑터 클래스
class WindowExit extends WindowAdapter{
private Frame f;
WindowExit(Frame f){
this.f = f;
}
@Override //윈도우 아뎁터를 상속받아 필요한 기능만 오버라이딩 한다.
public void windowClosing(WindowEvent arg0) {
f.dispose();
}
}
public class AdapterTest extends Frame {
private TextField tf; //인스턴스 변수를 생성
private Button btnExit;
public AdapterTest() {
tf = new TextField("x버튼을 누르면 종료합니다."); //인스턴스 생성
btnExit = new Button("종료");
add("North", tf);
add("Center", btnExit);
//윈도우리스너를 상속받아야 X버튼에 접근 할 수 있다.
//Frame 자체가 window의 포함되기 때문에 따로 이벤트 소스를 적지 않는다. (window만 해당된다.)
//같은 클래스에서 호출하기 때문에 this를 쓴다.
//Frame에 윈도우 리스너를 연결하고 WindowExit에 주소값을 전달한다.
addWindowListener(new WindowExit(this));
}
public static void main(String[] args) {
AdapterTest test = new AdapterTest();
test.setSize(300, 400);
test.setVisible(true);
}
}
※ 결과값
<ItemListener 이용하기>
package event;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
//체크박스를 선택하거나 할 때
public class ItemTest1 extends Frame implements ItemListener{
Panel p; //인스턴스 변수를 만든다.
Checkbox c1, c2, c3, r1, r2;
CheckboxGroup g1;
TextArea area;
ItemTest1(){ //생성자를 생성한다.
//리스너에 생성된 WindowExit 인스턴스의 주소값을 넘겨준다.
addWindowListener(new WindowExit(this));
p = new Panel();
c1 = new Checkbox("딸기"); //인스턴스를 생성한다.
c2 = new Checkbox("사과");
c3 = new Checkbox("배");
g1 = new CheckboxGroup();
r1 = new Checkbox("남성", g1, true);
r2 = new Checkbox("여성", g1, false);
area = new TextArea();
p.add(c1); //패널에 체크박스를 추가한다.
p.add(c2);
p.add(c3);
p.add(r1);
p.add(r2);
add("North", p); //레이아웃을 꾸며준다.
add("Center", area);
c1.addItemListener(this); //아이템리스너에 주소값을 보낸다.
c2.addItemListener(this);
c3.addItemListener(this);
r1.addItemListener(this);
r2.addItemListener(this);
//API를 찾아보고 메서드를 써보자
}
@Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
ItemTest1 test = new ItemTest1(); //클래스 인스턴스 생성
test.setSize(300, 400); //사이즈를 정함
test.setVisible(true); //창이 보여지게 함
}
}
※ 결과값
package event;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
//체크박스를 선택하거나 할 때
public class ItemTest1 extends Frame implements ItemListener{
Panel p; //인스턴스 변수를 만든다.
Checkbox c1, c2, c3, r1, r2;
CheckboxGroup g1;
TextArea area;
ItemTest1(){ //생성자를 생성한다.
//리스너에 생성된 WindowExit 인스턴스의 주소값을 넘겨준다.
addWindowListener(new WindowExit(this));
p = new Panel();
c1 = new Checkbox("딸기"); //인스턴스를 생성한다.
c2 = new Checkbox("사과");
c3 = new Checkbox("배");
g1 = new CheckboxGroup();
r1 = new Checkbox("남성", g1, true);
r2 = new Checkbox("여성", g1, false);
area = new TextArea();
p.add(c1); //패널에 체크박스를 추가한다.
p.add(c2);
p.add(c3);
p.add(r1);
p.add(r2);
add("North", p); //레이아웃을 꾸며준다.
add("Center", area);
c1.addItemListener(this); //아이템리스너에 주소값을 보낸다.
c2.addItemListener(this);
c3.addItemListener(this);
r1.addItemListener(this);
r2.addItemListener(this);
//API를 찾아보고 딸기체크했습니다. 뜨게하기.
}
@Override
public void itemStateChanged(ItemEvent e) {
Checkbox cb = (Checkbox)e.getSource();
if(cb.getState()) {//if문 안의 내용은 true값이다.
area.setText(e.getItem() + "이(가) 선택됨"); //창애 선택된 내용이 입력된다.
}else {
area.setText(e.getItem()+ "이(가) 해제됨");
}
}
public static void main(String[] args) {
ItemTest1 test = new ItemTest1(); //클래스 인스턴스 생성
test.setSize(300, 400); //사이즈를 정함
test.setVisible(true); //창이 보여지게 함
}
}
다중선택 예제를 해보자
package event;
import java.awt.Button;
import java.awt.Choice;
import java.awt.Frame;
import java.awt.List;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
public class ItemTest2 extends Frame implements ItemListener, ActionListener{
//인스턴스 변수를 선언한다.
private Panel p;
private Button btnDisplay;
private Choice choice;
private List list;
private TextArea area;
private String[] items = {"서울", "경기", "인천", "수원"};
ItemTest2(){
addWindowListener(new WindowExit(this)); //x버튼을 누르면 꺼진다.
//인스턴스를 선언한다.
p = new Panel();
btnDisplay = new Button("List 출력");
choice = new Choice();
list = new List();
area = new TextArea();
//패널에 재료를 더한다.
p.add(choice);
p.add(list);
p.add(btnDisplay);
//패널의 내부 위치를 설정한다.
add("North", p);
add("Center", area);
/*
for(int i=0; i<4; i++) {
choice.add(items[i]);
list.add(items[i]);
*/
for(String item: items) {
choice.add(item);
list.add(item);
}
choice.addItemListener(this); //아이템리스너를 핸들러로 연결해준다.
list.setMultipleMode(true); //setMultipleMode() 메서드로 다중선택이 되도록한다.
btnDisplay.addActionListener(this); //액션리스너를 핸들러로 연결해준다.
}
@Override //상속받은 ActionListener 오버라이드
public void actionPerformed(ActionEvent e) {
area.setText("");
String[] items = list.getSelectedItems();//리스트선택시 데이터를 가져오는 역할
for(String item : items) {
area.setText(area.getText() + item + "선택됨 \n");
}
}
@Override //상속받은 ItemListener 오버라이드
public void itemStateChanged(ItemEvent e) {
//getSelectedItem()이미 메서드의 정보를 가지고 있기 때문에 바로 호출 할 수 있다.
area.setText(choice.getSelectedItem() + "이 선택됨");
}
public static void main(String[] args) {
ItemTest2 test = new ItemTest2(); //클래스 인스턴스 생성
test.setSize(300, 400); //사이즈를 정함
test.setVisible(true); //창이 보여지게 함
}
}
package event;
import java.awt.Button;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.TextEvent;
import java.awt.event.TextListener;
public class TextTest extends Frame implements TextListener, KeyListener{
private Button btn;
private TextField field;
private TextArea area;
public TextTest(){
addWindowListener(new WindowExit(this));
btn = new Button("OK");
field = new TextField();
area = new TextArea();
add("North", btn);
add("Center", area);
add("South", field);
field.addTextListener(this);
field.addKeyListener(this);
}
@Override //텍스트가 변하 때 마다 텍스트가 더해지는 리스너
public void textValueChanged(TextEvent e) {
//area.setText(area.getText() +
// "내용이 변했어요" + field.getText() + "\n");
}
@Override //문자출력 (주로 자주 씀) ㅏkeyTyped 문자출력을 조금 더 정교하게
public void keyPressed(KeyEvent e) {
if(e.getKeyChar() != KeyEvent.VK_BACK_SPACE) {//현재 입력된 키보드 값이 백스페이스가 아닐 때만 출력
//VK_BACK_SPACE가상키보드
//textValueChanged보다 한 템포 출력이 느리다.
//그래서 getKeyChar()현재입력된 키보드 값을 가져온다.
area.setText(area.getText() +
"내용이 변했어요" + e.getKeyChar() + "\n");
}
}
public static void main(String[] args) {
TextTest test = new TextTest();
test.setSize(300, 400);
test.setVisible(true);
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
package event;
import java.awt.Button;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Color;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
//간단한 신호등 제어 프로그램
//3등식 눌렀을 때 빨간, 노랑, 초록
//4등식 눌렀을 때 빨간, 노랑, 초록, 좌회전
public class EventHomework extends Frame implements ItemListener{
//인스턴스 변수 생성
private Panel p1, p2, p3;
private Checkbox rdoThree, rdoFour;
private CheckboxGroup g1;
private Checkbox chkRed, chkYellow, chkLeft, chkGreen;
private Button btnRed, btnYellow, btnLeft, btnGreen;
private TextArea area;
private boolean flag = true;
public EventHomework() {
addWindowListener(new WindowExit(this));
//재료 만들기
p1= new Panel(); //패널 인스턴스 생성
p2= new Panel();
p3= new Panel();
chkRed = new Checkbox("빨강"); //체크박스 인스턴스 생성
chkYellow = new Checkbox("노랑");
chkLeft = new Checkbox("좌회전");
chkGreen = new Checkbox("초록");
g1 = new CheckboxGroup(); //체크박스 그룹과 체크박스 인스턴스 생성
rdoThree = new Checkbox("3등식", g1, false);
rdoFour = new Checkbox("4등식", g1, true);
btnRed = new Button("빨강"); //버튼 인스턴스 생성
btnYellow = new Button("노랑");
btnLeft = new Button();
btnGreen = new Button("초록");
p1.add(rdoThree); //패널에 재료를 배치하여 디자인
p1.add(rdoFour);
p2.add(chkRed);
p2.add(chkGreen);
p2.add(chkLeft);
p2.add(chkYellow);
p3.setLayout(new GridLayout(1,4));
p3.add(btnRed);
p3.add(btnGreen);
p3.add(btnLeft);
p3.add(btnYellow);
add("North", p1); //레이아웃을 꾸며준다.
add("West", p2);
add("South", p3);
chkRed.addItemListener(this);
chkYellow.addItemListener(this);
chkLeft.addItemListener(this);
chkGreen.addItemListener(this);
rdoFour.addItemListener(this);
rdoThree.addItemListener(this);
}
//3등식 일 때는 btnLeft가 보이지 않는 메서드
void rdoThree () {
if(rdoThree.getState()) {
btnLeft.setEnabled(true);
}else {
}
}
@Override
public void itemStateChanged(ItemEvent arg0) {
//4등식 눌렀을 때는 4개만 불 나오고, 3등식을 눌렀을 때는 3개만 불이 나온다.
if(chkRed.getState()) {
btnRed.setBackground(Color.RED);
}else {
btnRed.setBackground(null);
}
if(chkYellow.getState()) {
btnYellow.setBackground(Color.YELLOW);
}else {
btnYellow.setBackground(null);
}
if(chkLeft.getState()&&rdoFour.getState()) {
btnLeft.setLabel("←");
btnLeft.setBackground(Color.PINK);
}else {
rdoThree();
btnLeft.setLabel("");
btnLeft.setBackground(null);
}
if(chkGreen.getState()) {
btnGreen.setBackground(Color.GREEN);
}else {
btnGreen.setBackground(null);
}
}
public static void main(String[] args) {
EventHomework test = new EventHomework(); //클래스 인스턴스 생성
test.setSize(300, 400); //사이즈를 정함
test.setVisible(true); //창이 보여지게 함
}
}
7. 메뉴
1) Pull Down Menu (고정식)
- 눌렀을 때 메뉴 전체가 아래로 나온다.
- 아래 3가지는 고정식 메뉴의 요소들이다.
① MenuBar
- 메뉴를 붙이기 위한 길다란 바
② Menu
- 메뉴바 하나하나에 있는 메뉴
③ MenuItem
- 메뉴 안에 있는 실행가능한 메뉴아이템
2) Pop Up Menu (이동식, Context Menu)
- 팝업창처럼 툭 튀어나온다.
- 위치에 따라서 각각의 메뉴가 달라진다.
- 키보드에도 context 키가 있다.
메뉴아이템은 절대로 메뉴를 만들 수 없다.
메뉴아이템을 가질 수 있는건 메뉴 밖에 없다.
<UX 와 Swing>
UX(User Experience Design): 사용자의 경험을 바탕으로 디자인 해야한다.
RIA (Rich Internet Application) : 웹 애플리케이션의 장점은 유지하면서
기존 웹 브라우저 기반 인터페이스의 단점인 늦은 응답 속도,
데스크톱 애플리케이션에 비해 떨어지는 조작성 등을 개선하기 위한 기술의 통칭이다.
예전에 많이 알려졌지만 지금은 사라짐
Swing은 UX를 생각하면서 만들었다.
package menu;
import java.awt.Frame;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import event.WindowExit;
;
public class MenuTest1 extends Frame{
private MenuBar bar; //인스턴스 변수 생성
private Menu file, edit, file_new;
private MenuItem file_open, file_save, file_exit;
private MenuItem edit_cut, edit_copy, edit_paste;
private MenuItem file_new_java, file_new_c;
public MenuTest1() { //외부 접근을 위해 public 을 한다.
addWindowListener(new WindowExit(this));
bar = new MenuBar(); //인스턴스 생성
file = new Menu("파일");
edit = new Menu("편집");
file_new = new Menu("새파일"); // 메뉴아이템은 절대로 메뉴를 만들 수 없다.
bar.add(file);
bar.add(edit);
file_open = new MenuItem("파일열기");
file_save = new MenuItem("파일저장");
file_exit = new MenuItem("종료");
edit_cut = new MenuItem("잘라내기");
edit_copy = new MenuItem("복사하기");
edit_paste = new MenuItem("붙여넣기");
file.add(file_new); //
file.add(file_open); //디자인 배치
file.add(file_save);
file.addSeparator(); //구분자
file.add(file_exit);
edit.add(edit_cut);
edit.add(edit_copy);
edit.add(edit_paste);
file_new_java = new MenuItem("자바");
file_new_c = new MenuItem("C");
file_new.add(file_new_java);
file_new.add(file_new_c);
setMenuBar(bar); //메뉴바를 담는 형식이다.
}
public static void main(String[] args) {
// TODO 고정식 메뉴
MenuTest1 test = new MenuTest1(); //클래스 인스턴스 생성
test.setSize(300, 400); //사이즈를 정함
test.setVisible(true); //창이 보여지게 함
}
}
package menu;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import event.WindowExit;
;
public class MenuTest2 extends Frame implements ActionListener{
private MenuBar bar; //인스턴스 변수 생성
private Menu file, edit, file_new;
private MenuItem file_open, file_save, file_exit;
private TextArea area;
private FileDialog fopen, fsave;
public MenuTest2() {
addWindowListener(new WindowExit(this));
bar = new MenuBar(); //인스턴스 생성
file = new Menu("파일");
area = new TextArea();
bar.add(file);
file_open = new MenuItem("파일열기");
file_save = new MenuItem("파일저장");
file_exit = new MenuItem("종료");
fopen = new FileDialog(this, "파일열기", FileDialog.LOAD);
fsave = new FileDialog(this, "파일저장", FileDialog.SAVE);
file.add(file_open); //디자인 배치
file.add(file_save);
file.addSeparator(); //구분자
file.add(file_exit);
setMenuBar(bar); //메뉴바를 담는 형식이다.
add("Center", area);
file_exit.addActionListener(this); //오버라이드 연결해주는 핸들러
file_open.addActionListener(this);
file_save.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("종료")) { //종료메뉴를 누르면 종료됨
dispose();
}else if(e.getActionCommand().equals("파일열기")) {
//아래 내용은 java I/O 참고
try {
fopen.setVisible(true); //파일열기
String filepath = fopen.getDirectory() + "\\" +
fopen.getFile();
FileReader freader = new FileReader(filepath);//파일리더
BufferedReader br = new BufferedReader(freader);
String input = null;
while((input = br.readLine()) != null) {
area.append(input + "\n");
}
}catch(Exception err) {
err.printStackTrace();
}
}else {
try {
fsave.setVisible(true); //파일저장하기
String filepath = fsave.getDirectory() + "\\" +
fsave.getFile();
FileWriter fw = new FileWriter(filepath);
fw.write(area.getText());
fw.close();
}catch(Exception err) {
err.printStackTrace();
}
}
}
public static void main(String[] args) {
// TODO 고정식 메뉴
MenuTest2 test = new MenuTest2(); //클래스 인스턴스 생성
test.setSize(300, 400); //사이즈를 정함
test.setVisible(true); //창이 보여지게 함
}
}
파일이 열리고 저장된다.
package menu;
import java.awt.Frame;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import event.WindowExit;
public class MenuTest3 extends Frame implements MouseListener{
PopupMenu pmenu;
MenuItem fileopen, filesave, exit;
public MenuTest3() {
addWindowListener(new WindowExit(this));
pmenu = new PopupMenu();
fileopen = new MenuItem("파일열기");
filesave = new MenuItem("파일저장");
exit = new MenuItem("종료");
pmenu.add(fileopen);
pmenu.add(filesave);
pmenu.add(exit);
add(pmenu);
addMouseListener(this);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
MenuTest3 test = new MenuTest3(); //클래스 인스턴스 생성
test.setSize(300, 400); //사이즈를 정함
test.setVisible(true); //창이 보여지게 함
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
pmenu.show(this, e.getX(), e.getY());
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
어디를 클릭해도 팝업메뉴가 나온다.