JOptionPane

 자바 Swing에서 경고창 혹은 의사 결정(확인/취소)을 위한 확인창으로 JOptionPane이 존재한다. 위 캡쳐에 나온 화면은 ErrorMessage 아이콘을 사용한 것인데 이 아이콘을 커스텀해보자.

 

 

 

 위는 자바에서 기본적으로 제공하는 아이콘이다. 나는 개인적으로 쓰는 프로그램에 경고창을 띄우던 중 기본 아이콘들이 너무 옛날 느낌을 주기도 하고 상황에 맞게 사용할 수 있는 아이콘이 매우 제한적이라는 생각이 들어 커스텀을 찾아보게 되었다. 

 

 

import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JOptionPane;

public class JOptionPaneTest {
	public static void main(String[] args) {
		ImageIcon originIcon = new ImageIcon("res//arrow_cycle.png");
		Image resizeImg = originIcon.getImage().getScaledInstance(30, 30, Image.SCALE_SMOOTH);
		ImageIcon icon = new ImageIcon(resizeImg);
		JOptionPane.showConfirmDialog(null, "다시 실행하시겠습니까?", "확인", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, icon);
	}
}

 메시지 창을 띄우기 위해 굳이 JFrame까지 사용할 필요는 없다. 위처럼 해주기만 해도 메시지 창을 띄울 수 있다. 테스트에 사용된 이미지 파일은 프로젝트 폴더에 "res" 폴더를 생성한 뒤 안에 넣어주었다.

 

 

 ImageIcon 객체를 생성하고 프로젝트 폴더에 추가한 이미지 파일을 불러온다. 예제에 사용한 이미지 파일은 메시지 창에 쓰기에는 꽤나 크기 때문에 그대로 사용하면 이미지 크기가 들어가는 만큼 메시지 창이 컵져 버리기 때문에 조절이 필요하다. 아이콘으로 쓰기 적당한 파일 크기는 30x30 ~ 50x50이기 때문에 적절히 값을 바꾸어 가며 맞는 값을 찾으면 된다. 코드에서 리사이즈 작업을 해줘도 되지만 그림판, 포토샵 등으로 이미지 파일의 자체 크기를 조정해줘도 된다.

 

 아이콘을 설정했으면 JOptionPane에서 원하는 타입의 다이얼로그(메서드)를 선택한 다음, Icon 객체를 파라미터로 받는 (오버로딩된)메서드를 선택하고 인자로 ImageIcon 객체를 넘겨준다. 그리고 프로그램을 실행하면 아래와 같은 결과를 얻을 수 있다.

 

 

 

 

 윈도우 탐색기에서 마우스로 파일을 선택하여 프로그램으로 드래그하는 것으로 파일을 읽는 것을 Drag and Drop 라고 한다. 간단하게 구현 방법을 알아보자.

 

Drag and Drop

 

DropTarget

public DropTarget(Component c, DropTargetListener dtl)

 드래그 앤 드롭을 적용할 Component와 드롭되었을 때 적절한 처리를 해줄 DropTargetListener를 생성자 파라미터로 받는다.

 

DropTargetListener

Method 설명
public void drop(DropTargetDropEvent dtde) 파일이 드래그 된 후 타겟 위에서 마우스 동작을 종료했을 때 호출
public void dragEnter(DropTargetDragEvent dtde) 파일이 타겟 위에 드래그 된 시점에서 호출
public void dragOver(DropTargetDragEvent dtde) 파일이 드래그 된 후 타겟 위에서 마우스 포인터가 존재할 때 호출
public void dropActionChanged(DropTargetDragEvent dtde) 파일이 드래그 된 후 제스쳐가 변경되었을 때 호출
public void dragExit(DropTargetEvent dte) 파일이 드래그 된 상태에서 포인터가 타겟에서 벗어났을 때 호출

 드래그 앤 드롭 과정에서 발생하는 콜백 메서드들이다. 다른 메서드는 그다지 쓰이지 않고 drop을 구현하는 것이 일반적이다.

 

 

Code

import java.awt.Color;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.io.File;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JTextArea;

public class GUI extends JFrame implements DropTargetListener{
	JTextArea jta_log;
	
	public GUI () {
		setTitle("Swing");
		setBounds(10, 10, 400, 300);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		getContentPane().setBackground(Color.gray);
		setLayout(null);
		
		DropTarget dropTarget = new DropTarget(this, this);
		setDropTarget(dropTarget);
		
		jta_log = new JTextArea();
		jta_log.setBounds(10, 10, 360, 200);
		add(jta_log);
	}
	
	@Override
	public void drop(DropTargetDropEvent dtde) {
		jta_log.append("파일이 드롭되었습니다.\n\n");
		try {
			dtde.acceptDrop(DnDConstants.ACTION_MOVE);
			List<File> files = (List<File>)dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
			for(File file : files) {
				jta_log.append(file.getPath() + "\n");
			}
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void dragEnter(DropTargetDragEvent dtde) { }

	@Override
	public void dragOver(DropTargetDragEvent dtde) { }

	@Override
	public void dropActionChanged(DropTargetDragEvent dtde) { }

	@Override
	public void dragExit(DropTargetEvent dte) { }
}

 

 예제는 JTextArea를 배치하여 드롭된 파일 목록을 출력한다. DropTargetListener는 이름에서 짐작할 수 있듯이 파일을 드래그해 올 때 이벤트를 감지하고 처리하는 인터페이스이고, DropTarget은 파일을 드롭시킬 Target Component와 이벤트를 설정할 수 있다. JFrame을 Target으로 하고 이벤트도 현재 클래스에서 implements 했으므로 (this, this)를 넘겨주었다.

 

 파일을 Drop하게 되면 Drop 메서드에서 File 타입 객체들을 List로 읽어올 수 있다. 바로 처리할 것이 아니라면 File 타입의 리스트를 멤버 변수로 생성해두고 파일이 드래그될 때마다 누적시켜서 처리하는 것이 좋다. 

문제가 발생한 예
클릭을 해야만 정상적으로 화면이 표시된다.

 Swing으로 화면을 구성했을 때 Frame에 배치한 컴포넌트들이 보이지 않고 마우스로 해당 자리를 클릭해야만 컴포넌트가 표시되거나 클릭해도 표시되지 않을 때가 있다.

 

 

public class Main {
	public static void main(String args[]) {
		GUI gui = new GUI();
	}
}

class GUI extends JFrame {
	public GUI () {
		..
		this.setVisible(true);
		..
    }
}

 JFrame을 상속한 GUI 클래스가 있을 때 해당 클래스 내부에서 setVisible을 호출할 경우 위와 같은 현상이 발생한다.

 

 

public class Main {
	public static void main(String args[]) {
		GUI gui = new GUI();
		gui.setVisible(true);
	}
}

 내부에서 setVisible을 호출하지 않고 객체화한 후 호출하도록 하자.

+ Recent posts