Swing

AWT -> Swing -> JavaFX

AWT
- 초창기 나왔기 때문에 지금 보면 기능이 빈약함
- JAVA + C 이기 때문에 호환성이 부족

Swing
- JAVA만으로도 사용이 가능함
- 지금 만들어도 괜찮은 퀄리티


1) 패키지 명이 javax로 시작 : javax.swing.*


클래스 이름 앞에 J로 시작하면 swing이다. (J가 없으면 AWT이다.)



package swing;

import java.awt.FlowLayout;

import javax.swing.ImageIcon;

import javax.swing.JButton;

import javax.swing.JFrame;

import event.WindowExit;

public class SwingTest1 extends JFrame{

    private JButton btn;                        //버튼인스턴스변수 생성

    private ImageIcon icon;                        //이미지를 저장하는 창고

    private ImageIcon icon2;                    //이미지를 저장하는 창고

    

    

    

    public SwingTest1() {                         //생성자

        

        setLayout(new FlowLayout());             // 자동정렬

        

        //addWindowListener(new WindowExit(this)); // x를 끄면 꺼진다.(awt에서 클래스를 만들어 사용)

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //x를 끄면 꺼진다.(Swing에서 사용)

        

        btn = new JButton("버튼");                 //버튼 인스턴스 생성

        

        icon = new ImageIcon(getClass().getResource("/images/duke (1).gif")); //이미지를 불러온다.

        icon2 = new ImageIcon(getClass().getResource("/images/duke (2).gif")); //이미지를 불러온다.

        //경로가 /로 시작하면 절재로 경로가 바뀌지 않는 절대경로이다.

        // /는 프로젝트의 처음 시작위치이다.

        

        btn.setIcon(icon);                      //버튼을 누르면 이미지를 호출한다. JIcon의 메서드.

        btn.setPressedIcon(icon2);               //눌렀을 때 이미지가 바뀐다.

        add(btn);                              //버튼을 Frame 추가

        

    }

    

    public static void main(String[] args) {

        

        SwingTest1 test = new SwingTest1();   //클래스 인스턴스 생성

        test.setSize(300, 400);                  //사이즈를 정함

        test.setVisible(true);                  //창이 보여지게 함 창을 끄면 false 상태가 됨.

    }

}



버튼이 바뀐다.







스윙은 테두리를 내가 원하는 테투리로 갈아 끼울 수 있다.

라벨에 테두리를 갈아 끼워보자.


java.desktop  > javax.swing.boader 

테두리를 모아놓은 패키지.




package swing;

import java.awt.Color;

import java.awt.FlowLayout;

import javax.swing.ImageIcon;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.border.BevelBorder;

public class SwingTest2 extends JFrame{

    private JButton btn;

    private ImageIcon icon;

    private JLabel lab;

    

    

    public SwingTest2() {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new FlowLayout());

        

        btn = new JButton("버튼");

        icon = new ImageIcon(getClass().getResource("/images/duke (3).gif"));

        lab = new JLabel("스윙 라벨입니다.", icon, JLabel.CENTER);

        

        //lab.setBorder(new EtchedBorder(Color.BLUE, Color.RED));//프레임의 틀을 바꾸자

        lab.setBorder(new BevelBorder(BevelBorder.LOWERED));//프레임의 틀을 바꾸자

        

        add(btn);

        add(lab);

                

    }

    

    public static void main(String[] args) {

        SwingTest2 test = new SwingTest2();   //클래스 인스턴스 생성

        test.setSize(300, 400);                  //사이즈를 정함

        test.setVisible(true);                  //창이 보여지게 함 창을 끄면 false 상태가 됨.

    }

}








package swing;


import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;


import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JOptionPane;

import javax.swing.JTextField;


//확인버튼이 떴을 때 글자가 그대로

public class SwingTest3 extends JFrame implements ActionListener, KeyListener{

private JTextField field;

private JButton btnOk;

private JLabel lab;

public SwingTest3(){

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

field = new JTextField(30);

btnOk = new JButton("확인");

lab = new JLabel("안녕하세요.");

add("Center", field);

add("East", btnOk);

add("South", lab);

btnOk.addActionListener(this);

field.addKeyListener(this);

}

@Override

public void actionPerformed(ActionEvent arg0) {

if(field.getText().isEmpty()) { //만약 값이 비어있다면

//값이 비어 있다면 확인하고 값을 넣어달라고 창을 띄운다.

//JOptionPane.showMessageDialog(null, "반드시 데이터를 입력하시오");

//값이 비어있다면 확인하고 값을 입력하기 위해 창을 띄움

//String name = JOptionPane.showInputDialog("이름을 입력하세요.");

//lab.setText(name);

//값이 비어있다면 선택한다. 앞의 null은 주소값인데 별 의미는 없다.

int result = JOptionPane.showConfirmDialog(null, "예/아니오 선택");

lab.setText(new String().valueOf(result)); //주소값이 나오게 한다.

}else {

lab.setText(field.getText());

}

}

@Override

public void keyPressed(KeyEvent e) { //엔터키를 치면 입력된다.

if(e.getKeyChar() == KeyEvent.VK_ENTER) {

lab.setText(field.getText());

}

}


@Override

public void keyReleased(KeyEvent e) {

// TODO Auto-generated method stub

}


@Override

public void keyTyped(KeyEvent e) {

// TODO Auto-generated method stub

}


public static void main(String[] args) {

SwingTest3 test = new SwingTest3();   //클래스 인스턴스 생성

test.setSize(300, 100);       //사이즈를 정함

test.setVisible(true);       //창이 보여지게 함 창을 끄면 false 상태가 됨.


}


}





<Swing에서 트리구조 만들기>


tree

'트리'를 보여줄 수 있게 해주는 하나의 공간을 '트리'라고 한다.

실제로 트리 안에 아이템을 만들어주는 클래스는 따로 있다.



DefaultMutableTreeNode 

이 클래스는 트리구조의 아이템을 만들수 있도록 해준다.



트리에 어떻게 값을 넣을 수 있을까?

마우스 리스너의 기능 중 일부를 쓰기 위해 마우스 리스너를 상속받는 마우스 어댑터를 사용한다.

마우스를 눌렀을 때 이벤트가 발생하는 메소드 오버라이드해보자.


여기에 값을 넣으려면 두 개의 메서드를 이용하여 활용한다.


java.desktop >  JTree


.getRowForLocation() 행의 위치를 알고 싶을 때 사용

.getPathForLocation() 경로와 위치를 알고 싶을 때 사용


final JTree tree = ...;

MouseListener ml = new MouseAdapter() {

     public void mousePressed(MouseEvent e) {

         int selRow = tree.getRowForLocation(e.getX(), e.getY());

         TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());

         if(selRow != -1) {

             if(e.getClickCount() == 1) {

                 mySingleClick(selRow, selPath);

             }

             else if(e.getClickCount() == 2) {

                 myDoubleClick(selRow, selPath);

             }

         }

     }

};




tree.addMouseListener(ml);

getRowForLocation(e.getX(), e.getY())

getRowForLocation 행의 위치를 알려줄 때 사용

(MouseEvent e)의 x좌표 y좌표는 (e.getX(), e.getY())


이렇게 행의 위치를 알려준다.



getPathForLocation 은 경로와 위치를 알고 싶을 때 사용




package swing;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JScrollPane;

import javax.swing.JTree;

import javax.swing.tree.DefaultMutableTreeNode;

import javax.swing.tree.TreePath;

public class SwingTest4 extends JFrame{

    

    private JLabel lab;            // 레이블 변수를 만든다.

    private JTree tree;            // 트리구조의 구조공간 변수 생성

    private JScrollPane scroll; // 비어있는 스크롤이 달려있는 판을 준비하고

                                // 트리구조를 담을 수 있도록 한다.

    

    public SwingTest4() {

        

        //트리구조의 아이템을 만들어 준다.

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode root =

                new DefaultMutableTreeNode("커피");

        

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode step1 =

                new DefaultMutableTreeNode("자바 커피");

        

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode step2 =

                new DefaultMutableTreeNode("원두 커피");

        

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode step2_1 =

                new DefaultMutableTreeNode("아메리카노");

        

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode step2_2 =

                new DefaultMutableTreeNode("헤이즐넛");

        

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode step2_3 =

                new DefaultMutableTreeNode("라떼");        

        

        root.add(step1);                                //root에 step1,2 를 담는다.

        root.add(step2);

        

        step2.add(step2_1);                                // step2에 step2_1,2,3을 담는다.

        step2.add(step2_2);

        step2.add(step2_3);

        tree = new JTree(root);                            //트리의 인스턴스를 생성하고

        scroll = new JScrollPane(tree);                    //스크롤바 판에 트리를 붙여 인스턴스 생성

        lab = new JLabel("여기에 선택한 항목이 나타납니다.");    //라벨을 붙힌다.

        

        

        

        add(scroll);                                    //트리 붙은 스크롤바 판을 프레임에 더한다.

        add("South", lab);                                //아래쪽에 라벨을 프레임에 더한다.

        

        tree.addMouseListener(new TreeMouseHandler());    //핸들러를 만든다.

        

    }

    

    class TreeMouseHandler extends MouseAdapter{

        //마우스 리스너의 기능 중 일부를 쓰기 위해 마우스 리스너를 상속받는 마우스 어댑터를 사용한다.

        

        @Override    //마우스를 눌렀을 때 이벤트가 발생하는 메소드 오버라이드

        public void mousePressed(MouseEvent e) {

            

            //System.out.println(tree.getRowForLocation(e.getX(), e.getY()));    //행의 위치를 알고 싶을 때 사용

            //System.out.println(tree.getPathForLocation(e.getX(), e.getY()));     //경로와 위치를 알고 싶을 때 사용

            

            int row = tree.getRowForLocation(e.getX(), e.getY());        //행의 위치값을 row변수에 담는다.

            TreePath path = tree.getPathForLocation(e.getX(), e.getY());//path라는 리턴값에 경로와 위치를 담는다.

                                                                                        //누르면 누른 값이 마지막 값으로 나온다.

            

            if(row != -1) { //선택했을 때만 결과가 나올 수 있도록 처리한다.

                lab.setText(path.getLastPathComponent().toString());

                //lab변수안에

                //.setText()안의 문자를 넣어라.

                //path.getLastPathComponent().toString()의 문자를 넣어라

                //path.getLastPathComponent()는 행의 마지막 값을 아래에 출력

            }

            

        }

    

        

        

        

    }

    

    public static void main(String[] args) {

        SwingTest4 test = new SwingTest4();               //클래스 인스턴스 생성

        test.setSize(300, 400);                              //사이즈를 정함

        test.setVisible(true);                              //창이 보여지게 함 창을 끄면 false 상태가 됨.

    }

}











2) MVC(Model View Controller) 패턴 설계

- 쉽게 말하면 역할분담이다.

- 데이터는 별도로 따로 처리하자

- 하나의 데이터로 다양하게 활용하자.


mvc는 역할이다.

- M 데이터, 자료이다.

- C 모델과 뷰의 관계의 소통이 원활 할 수 있도록 제어, swing에서는 내장되어 있다.

- V 뷰는 보여지는 것, 디자인 


- mvc를 기반으로 다양한 모델들이 파생된다.


- 데이터와 테이블은 분리되어 있다. 테이블은 뷰의 역할이다.

- 뷰는 데이터의 주로를 가지고 있다.





package swing;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.table.TableModel;

public class SwingTest5 extends JFrame implements ActionListener{

    private JTable table;

    private JButton btnDisplay;

    private String title[] = {"이름", "나이", "성별"}; //타이틀 데이터 준비

    private String data[][] = {                        //테이블에 들어갈 데이터 준비

            {"홍길동", "20", "남자"},

            {"임꺽정", "22", "남자"},

            {"신사임당", "25", "여자"}

        };

    private JScrollPane scroll;

    

    

    public SwingTest5() {

        //x버튼 누르면 끝남

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        

        //인스턴스 생성

        table = new JTable(data, title);

        scroll = new JScrollPane(table);

        btnDisplay = new JButton("콘솔에 출력");

        

        

        //fram에 붙여줌

        add("Center", scroll);      //스크롤 바를 넣으면 없던 제목이 생긴다.

        add("South", btnDisplay); //제목을 보고 싶으면 스크롤 바를 넣어야한다.

        btnDisplay.addActionListener(this);    //액션 리스너를 만들어 준다.

        

    }

    

    @Override

    public void actionPerformed(ActionEvent e) {

    TableModel model = table.getModel();           // 뷰인 테이블이 가리키는 데이터의 주소를 가져온다.

    

    for(int i=0; i<model.getColumnCount(); i++) {            //열의 개수

        System.out.print(model.getColumnName(i) + "\t");    //제목을 출력한다.

    }

    

    System.out.println();

    System.out.println("----------------------------------");

    

    for(int i=0; i<model.getRowCount(); i++) {                  //행의 개수만큼 출력할 수 있게

        for(int j=0; j<model.getColumnCount(); j++) {         //열의 개수만큼 출력할 수 있게

            System.out.print(model.getValueAt(i, j) + "\t"); //.getValueAt(i, j) 행과 열의 데이터를 출력하겠다.

        }

        System.out.println();

    }

    

    

    }

    

    public static void main(String[] args) {

        SwingTest5 test = new SwingTest5();               //클래스 인스턴스 생성

        test.setSize(300, 400);                              //사이즈를 정함

        test.setVisible(true);                              //창이 보여지게 함 창을 끄면 false 상태가 됨.

    }

}




출력하면 이클립스에 결과가 나온다.


※ 콘솔 출력 값


이름    나이    성별    

----------------------------------

홍길동    20    남자    

임꺽정    22    남자    

신사임당    25    여자    







package swing;


import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.FocusEvent;

import java.awt.event.FocusListener;


import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.JTextField;

import javax.swing.event.MouseInputListener;

import javax.swing.table.DefaultTableModel;



//https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html 참조

public class SwingTest6 extends JFrame implements ActionListener, FocusListener{

private JTable table; //인스턴스 변수 생성



private JScrollPane scroll;

private String title[] = {"이름", "나이", "성별"};

private JButton btnAdd, btnDel;

private JPanel panel;

private JTextField tfName, tfAge, tfGender;


public SwingTest6() {//////////////////////////////////////생성자

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

///////////////////////////////////////////////////////인스턴스 변수생성

btnAdd = new JButton("추가");

btnDel = new JButton("삭제");

tfName = new JTextField("이름", 6);

tfAge = new JTextField("나이", 3);

tfGender = new JTextField("성별", 2);

panel = new JPanel();

//데이터의 실체가 없기 때문에 데이터가 있는 모델객체를 따로 만들어야 데이터를 가져올 수 있다.

DefaultTableModel model = new DefaultTableModel(title, 0); 

                //데이터를 보관할 수 있는 model 객체를 만들어 준다.

table = new JTable(model); //데이터를 모델객체에 담아준다.

scroll = new JScrollPane(table);//스크롤바에 테이블을 담아준다.

add("Center", scroll); //프레임 가운데에 스크롤바와 테이블을 담아준다.

panel.add(tfName); //패널에 이름을 담아준다.

panel.add(tfAge); //패널에 이름을 담아준다.

panel.add(tfGender); //패널에 이름을 담아준다.

panel.add(btnAdd); //패널에 이름을 담아준다.

panel.add(btnDel); //패널에 이름을 담아준다.

add("South", panel); //프레임 아래에 패널을 담아준다.

btnAdd.addActionListener(this);//addActionListener 핸들러를 만들어 준다.

btnDel.addActionListener(this);

tfGender.addFocusListener(this);//addFocusListener 핸들러를 만들어준다

tfAge.addFocusListener(this);

tfName.addFocusListener(this);

}

@Override //액션 오버라이드 메서드를 만든다.

public void actionPerformed(ActionEvent e) {

if(e.getActionCommand().equals("추가")) {  //"추가"를 눌렀을 때

//연관된 데이터이므로 배열로 3개를 준비한다.

String[] data = new String[3];

data[0] = tfName.getText();

data[1] = tfAge.getText();

data[2] = tfGender.getText();

//table의 자식클래스인 DefaultTableModel에 모델의 주소를 테이블에 물어본다.

DefaultTableModel model = (DefaultTableModel)table.getModel();

//모델에 한 행에 데이터를 추가한다.

model.addRow(data);

}

else {

//System.out.println(table.getSelectedRow());//삭제 버튼을 누르면 선택 행 주소가 출력됨

int row = table.getSelectedRow();

if(row == -1) { //로우 값이 없다면 -1이라면

JOptionPane.showMessageDialog(null, "반드시 선택해야합니다.");

return; //현재위치에서 즉시 원위치로 돌아간다. 메서드 종료. 

//actionPerformed를 호출한 놈에게 돌아감 -> 시스템으로 돌아감  = 종료

}

else {

//table의 자식클래스인 DefaultTableModel에 모델의 주소를 테이블에 물어본다.

DefaultTableModel model = (DefaultTableModel)table.getModel();

//모델에 선택된 현재 행에 데이터를 삭제한다.

model.removeRow(row);

}

}

}


@Override//클릭하면 이름이 지워지고 입력이 가능하도록 포커스 리스너를 만든다.

public void focusGained(FocusEvent arg0) {

JTextField add = (JTextField)arg0.getComponent();

//add.setText("");

add.setText(add.getSelectedText());

                

                //.setText() 수정하는 메소드

          //.getSelectedText() 이 TextComponent에 격납되어있는 선택된 텍스트를 돌려줍니다. 

          //선택 범위가 null이거나 문서가 비어 있으면 null을 반환합니다.

}


@Override

public void focusLost(FocusEvent arg0) {

// TODO Auto-generated method stub

}


public static void main(String[] args) {

SwingTest6 test = new SwingTest6();    //클래스 인스턴스 생성

test.setSize(300, 400);       //사이즈를 정함

test.setVisible(true);       //창이 보여지게 함 창을 끄면 false 상태가 됨.


}


}





+ Recent posts