프로그래밍

3. 간단한 메모장 - 자바 넷빈즈 IDE로 하는 스윙 프로그래밍 입문

할랑할랑 2007. 11. 16. 18:01
반응형

자바 API 찾을 줄 아시고, Java NetBeans IDE 좀 익숙해지셨으면 사실 이 글 보실 필요가 없으실텐데요. 괜히 길게 안쓰고 간단하게 필요한 구성 요소 추가와, 각 요소별 메소드 함수만 말씀드리겠습니다.

3. 간단한 메모장(편집기, Editor) - 자바 넷빈즈 IDE로 하는 스윙 프로그래밍 입문

그림과 같이 기본 Swing JFrame 폼을 디자인했습니다. 메뉴는 JMenuBar 개체를 넣으면 되고, 메뉴바에 있는 각각의 큰 메뉴는 JMenuBar에다가 JMenu를 추가하시면 됩니다. JMenu의 하위 팝업메뉴는 JMenuItem을 추가하여만듭니다. 가장 중요한 에디터 창은, 각종 기능이 제공되는 JEditorPane을 넣었습니다. 자동으로 JScrollPane과 함께 들어가게 됩니다.

사용자 삽입 이미지

각 메뉴에 대한 Action은 Inspector에서 메뉴를 연 후, 각 메뉴를 마우스 우클릭 > Event > Action으로 지정할 수 있습니다.

사용자 삽입 이미지

파일 입출력을 위해서는 우선 파일 선택 대화창(FileDialog)를 이용할 필요가 있습니다. 윈도우에서 흔히 보는 파일 선택 대화창 다이얼로그인데, 다음과 같이 사용하시면 됩니다.

(변수선언)
private String file; // 파일명
private String directory; // 파일 디렉토리 패스명
private FileDialog d; // 파일 대화창

(사용방법)
d = new FileDialog(this, "파일 다이얼로그");

(파일 읽기 모드 일때)
d.setTitle("불러오기...");
d.setMode(FileDialog.LOAD);
d.setVisible(true);
if( d.getFile() == null ) // d.getFile()이 null이면 "취소"를 눌렀다는 뜻입니다.
     return;
file = d.getFile();
directory = d.getDirectory();
this.setTitle("["+file+"] - 소스 편집기"); // 주 JFrame 창의 제목을 바꿔줍니다.

(파일 쓰기 모드 일때)
d.setTitle("다른 이름으로 저장...");
d.setMode(FileDialog.SAVE);
d.setVisible(true);
// 나머지는 위와 같음

JEditorPane은 입력 스트림(InputStream) 및 출력기(Writer)에 대해서 직접 읽기 및 쓰기(read, write) 메소드를 제공합니다. 파일 입출력 함수를 괜히 많이 쓸 필요없이, 제공해주는 파일 입출력 기능을 이용합니다.

(각종 패키지 클래스 및 메소드가 필요하므로 import를 여러개 했습니다)
import javax.swing.text.*;
import java.util.*;
import java.lang.*;
import java.awt.*;
import java.io.*;

(파일 입력)
File infile = new File(directory, file);
if( infile != null ) {
  try {
    // 파일 입력 스트림은 반드시 try-carch로 묶어주거나 throw 해주어야함
    FileInputStream instream = new FileInputStream(infile);
    String tmpStr = null;
    // jEditorPane.read(InputStream, Object) 메소드
    // Object는 스트림에서 받을 데이터의 자료형을 나타내는 임시 변수입니다.
    // 저는 그냥 tmpStr을 하나 만든 다음 넘겨주었습니다. 값은 필요없으므로
    // null로 해줬습니다.
    jEditorPane_editor.read(instream, tmpStr);
    this.setTitle("["+file+"] - 소스 편집기");
    instream.close();
  } catch( Exception e ) {
    System.err.println(e.toString());
  }
  infile = null;
}

(파일 출력)
File outfile = new File(directory, file);
if( outfile != null ) {
  try {
    FileWriter filewriter = new FileWriter(outfile);
    // JEditorPane의 write 메소드는 Writer 클래스를 필요로 합니다.
    jEditorPane_editor.write(filewriter);
    filewriter.close();
  } catch (Exception e) {
    System.err.println(e.toString());
  }
}

종료 버튼은 간단하게 System.exit()를 이용하면 됩니다.

private void jMenuItem_exitActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
  System.exit(-1);
}

특정 문자열 바꾸기 기능입니다. 문자열을 하나씩 찾아서 바꿀때는, 특정 문자열의 위치를 파악해야 하므로, JEditorPane 전체의 text를 getText()로 String 값으로 얻은 다음, String의 indexOf 메소드를 이용해 찾아줍니다. 주의할 점은, JEditorPane의 caret(키보드 입력 커서) 위치 산정 기준이, String의 문자열 개수와는 다르다는 것입니다. String의 indexOf에서는 New Line(\n)의 개수를 문자 하나로 치지만, caret 위치 계산때에는 new line 값이 포함되지 않습니다. 따라서 임시 변수에 string을 담아서 "\n"을 모두 없애준 다음, indexOf를 해야 정확한 caret의 위치가 계산됩니다.

// 현재 커서로 부터 아래 방향으로 찾는다.
String txt = jEditorPane_editor.getText();
// String 내부에서 new line(\n) 문자도 한 글자로 치지만
// jEditorPane의 carret position 산출시에는 \n는 제외한다
txt = txt.replace("\n","");
int pos = jEditorPane_editor.getCaretPosition(); // 현재 캐럿 위치
int new_pos = txt.indexOf(str, pos); // 다음 문자열 위치
if( new_pos < 0 )
  System.out.println("더 이상 같은 문자열이 없습니다.");
else {
  // JEditorPane의 문자열을 하나씩 조작할때는, document를 얻어서 작업해야함
  Document doc = jEditorPane_editor.getDocument();
  // Document.remove / insertString도 try - catch가 필요
  try {
    // 말 그래도 문자열 삭제, 추가 기능
    doc.remove( new_pos, str.length() );
    doc.insertString( new_pos, replace, null );
  } catch (BadLocationException ble) {
    System.err.println(ble);
  }
  doc = null;
  jEditorPane_editor.setSelectionStart( new_pos );
  jEditorPane_editor.setSelectionEnd( new_pos + replace.length() );
}
txt = null;

Document.insertString 활용 방법으로, 문서의 끝부분에 문자열을 추가하고 싶으면 doc.insertString( JEditorPane.getText().length(), strToAdd, null ); 를 하시면 됩니다.

문자열 전체 한꺼번에 바꾸기 기능입니다. 전체적으로 모두 바꾸면 되므로, 그냥 String을 얻은 후 replace 함수로 한꺼번에 바꿔버리고 다시 setText를 해주면 됩니다.

String txt = jEditorPane_editor.getText();

if ( txt.indexOf(str)>= 0 ) {
  txt = txt.replace( str, replace );
  jEditorPane_editor.setText(txt);
}

replaceAll 메소드와 헷갈리면 안되는데, replace 함수도 전체 문자열을 모두 찾아서 교환해줍니다. 괜히 replaceAll 함수는 입력값이 regex(Regular Expression, 정규식) 이기 때문에, 문자대 문자 100% 일치하는 문자열만 비교할 때에는 적합하지 않습니다. regex로는 특정 규칙에 맞는 문자열을 지정할 수가 있는데, 자세한건 API나 여러 홈페이지에서 regex에 관한 정보를 검색해보시는 것이 좋을 듯합니다. regex를 이용하려면, 여러모로 애매모호한 점이 있어서 열심히 내용을 보고 테스트 해봐야합니다.

연재 식으로 진행하려했지만 별 의미가 없는 것 같아서, 앞으로는 제가 필요할때마다 찾아놓은 각 클래스의 메소드에 대해서만 그때그때 정리할까 합니다.

※ 관련글
- 1. 넷빈즈 설치 및 기본 프로젝트 작성 - 자바 넷빈즈 IDE로 하는 스윙 프로그래밍 입문
- 2. 간단한 계산기 제작 및 JAVA API 찾는법
- 간단한 컴파일 오류 잡기 - try catch 및 import가 필요한 경우
- 프로그램에서 거꾸로 다이어그램 얻기
- 창 위의 창 대화창(다이얼로그) 띄우기

반응형