개요
A4 용지 기준으로 여러 사람의 정보를 6칸씩 나눠서 출력하고, 출력 전 미리보기를 제공하는 프로그램이다.
실행 화면


- 미리보기 화면으로 A4용지 전체 내용이 표시됨
- 하단 이전, 다음 버튼으로 총 페이지의 미리보기가 가능

- 상단 출력하기 버튼 클릭 시 나타나는 화면
- 내 PC에 연결된 모든 프린터를 불러온다.
전체 구조 요약
- Person 클래스: 출력할 데이터 구조 정의 (이름, 역할, 직책)
- PrintTest 클래스: Printable 구현 → 페이지 단위로 인쇄 가능
- PreviewPanel 클래스: 스크롤 가능한 미리보기 패널
- main 메서드: 프레임 구성, 버튼, 페이지 전환, 출력 기능 구현
Person 클래스
private static class Person {
String name, role, position;
Person(String name, String role, String position) {
this.name = name;
this.role = role;
this.position = position;
}
}
- 6칸짜리 A4 출력용 정보를 담는 객체
- 이름, 역할, 직책을 담음
Printable 구현: print 메서드
@Override
public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException {
int totalPages = (int) Math.ceil(people.length / (double) PAGE_SIZE);
if (pageIndex >= totalPages)
return NO_SUCH_PAGE;
- Printable 인터페이스 구현 → PrinterJob이 이 메서드를 호출하여 페이지 단위로 그림을 그림
- pageIndex는 현재 출력할 페이지 번호
- NO_SUCH_PAGE → 페이지 끝, 출력 안 함
페이지 내 구역 계산
int cols = 2;
int rows = 3;
double cellWidth = pageWidth / cols;
double cellHeight = pageHeight / rows;
- A4 한 페이지를 2열 × 3행 → 6개의 영역으로 분할
- 각 칸의 크기를 cellWidth, cellHeight로 계산
각 Person 출력
for (int i = start; i < end; i++) {
Person p = people[i];
int localIndex = i - start;
int col = localIndex % 2;
int row = localIndex / 2;
double x = pf.getImageableX() + col * cellWidth;
double y = pf.getImageableY() + row * cellHeight;
g2.drawRect((int)x, (int)y, (int)cellWidth, (int)cellHeight);
g2.drawString("이름: " + p.name, (int)x + 20, (int)y + 30);
g2.drawString("역할: " + p.role, (int)x + 20, (int)y + 50);
g2.drawString("직책: " + p.position, (int)x + 20, (int)y + 70);
}
- 행/열 위치 계산 → (col, row)
- drawRect → 칸 테두리 그리기
- drawString → 이름/역할/직책 출력
- 좌표에 20,30px 정도 오프셋 줘서 테두리와 글자가 겹치지 않게 함
PreviewPanel 클래스 (미리보기)
static class PreviewPanel extends JPanel {
Printable printable;
PageFormat pf;
int pageIndex;
double scale = 1.0;
- Printable 객체를 JPanel 위에서 그대로 그림
- scale → 미리보기 크기 조절 가능
- paintComponent → 실제 프린터 출력과 동일하게 렌더링
main 메서드
JFrame 구성
JFrame frame = new JFrame("A4 미리보기");
frame.setLayout(new BorderLayout());
- 중앙: 미리보기 스크롤 (JScrollPane)
- 하단: 페이지 이동 버튼 + 페이지 라벨
- 상단: 출력 버튼
페이지 이동
prevBtn.addActionListener(e -> { ... });
nextBtn.addActionListener(e -> { ... });
- pageIndex를 증감 → PreviewPanel.setPage 호출 → repaint
- 총 페이지 수를 Math.ceil(people.length / 6.0)으로 계산
실제 출력
printBtn.addActionListener(e -> {
job.setPrintable(printT);
if (job.printDialog()) {
try { job.print(); } catch (Exception ex) { ex.printStackTrace(); }
}
});
- PrinterJob → OS 프린터 대화상자 호출
- PrintTest.print가 실제로 각 페이지를 그림
전체 코드
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class PrintTest implements Printable {
// 6개의 구역에 들어갈 정보
private static class Person {
String name, role, position;
Person(String name, String role, String position) {
this.name = name;
this.role = role;
this.position = position;
}
}
private Person[] people = {
new Person("김OO", "개발", "사원"),
new Person("홍OO", "기획", "과장"),
new Person("이OO", "디자인", "대리"),
new Person("성OO", "QA", "주임"),
new Person("임OO", "운영", "팀장"),
new Person("신OO", "관리", "부장"),
new Person("강OO", "관리", "부장") // 7명 → 페이지 2개 필요
};
// 1페이지 = 6명
private final int PAGE_SIZE = 6;
@Override
public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException {
int totalPages = (int) Math.ceil(people.length / (double) PAGE_SIZE);
// 페이지 범위를 벗어나면 끝
if (pageIndex >= totalPages)
return NO_SUCH_PAGE;
Graphics2D g2 = (Graphics2D) g;
g2.setFont(new Font("Malgun Gothic", Font.PLAIN, 14));
double pageWidth = pf.getImageableWidth();
double pageHeight = pf.getImageableHeight();
int cols = 2;
int rows = 3;
double cellWidth = pageWidth / cols;
double cellHeight = pageHeight / rows;
int start = pageIndex * PAGE_SIZE; // 첫 사람 index
int end = Math.min(start + PAGE_SIZE, people.length);
for (int i = start; i < end; i++) {
Person p = people[i];
int localIndex = i - start;
int col = localIndex % 2;
int row = localIndex / 2;
double x = pf.getImageableX() + col * cellWidth;
double y = pf.getImageableY() + row * cellHeight;
g2.drawRect((int)x, (int)y, (int)cellWidth, (int)cellHeight);
g2.drawString("이름: " + p.name, (int)x + 20, (int)y + 30);
g2.drawString("역할: " + p.role, (int)x + 20, (int)y + 50);
g2.drawString("직책: " + p.position, (int)x + 20, (int)y + 70);
}
return PAGE_EXISTS;
}
// ───────────────────────────────
// 여러 페이지 미리보기 패널
// ───────────────────────────────
static class PreviewPanel extends JPanel {
Printable printable;
PageFormat pf;
int pageIndex;
double scale = 0.95; // 기본 축소율
PreviewPanel(Printable p, PageFormat pf) {
this.printable = p;
this.pf = pf;
setPreferredSize(new Dimension((int)(pf.getWidth() * scale), (int)(pf.getHeight() * scale)));
}
public void setPage(int index) {
this.pageIndex = index;
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.scale(scale, scale);
try {
printable.print(g2, pf, pageIndex);
} catch (Exception e) {
e.printStackTrace();
}
g2.dispose();
}
}
public static void main(String[] args) {
PrintTest printT = new PrintTest();
PrinterJob job = PrinterJob.getPrinterJob();
PageFormat pf = job.defaultPage();
int totalPages = (int)Math.ceil(printT.people.length / 6.0);
// 미리보기 패널
PreviewPanel preview = new PreviewPanel(printT, pf);
// 프레임
JFrame frame = new JFrame("A4 미리보기");
frame.setLayout(new BorderLayout());
// 스크롤
JScrollPane scrollPane = new JScrollPane(preview);
frame.add(scrollPane, BorderLayout.CENTER);
// 페이지 이동 버튼
JPanel bottomPanel = new JPanel();
JButton prevBtn = new JButton("◀ 이전");
JButton nextBtn = new JButton("다음 ▶");
JLabel pageLabel = new JLabel("1 / " + totalPages);
bottomPanel.add(prevBtn);
bottomPanel.add(pageLabel);
bottomPanel.add(nextBtn);
frame.add(bottomPanel, BorderLayout.SOUTH);
// 현재 페이지
final int[] pageIndex = {0};
// 이전 페이지
prevBtn.addActionListener(e -> {
if (pageIndex[0] > 0) {
pageIndex[0]--;
preview.setPage(pageIndex[0]);
pageLabel.setText((pageIndex[0] + 1) + " / " + totalPages);
}
});
// 다음 페이지
nextBtn.addActionListener(e -> {
if (pageIndex[0] < totalPages - 1) {
pageIndex[0]++;
preview.setPage(pageIndex[0]);
pageLabel.setText((pageIndex[0] + 1) + " / " + totalPages);
}
});
// 실제 출력 버튼
JButton printBtn = new JButton("출력하기");
printBtn.addActionListener(e -> {
job.setPrintable(printT);
if (job.printDialog()) {
try {
job.print();
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
frame.add(printBtn, BorderLayout.NORTH);
frame.setSize(700, 900);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
반응형
'Java' 카테고리의 다른 글
| Java 상속(Inheritance) 이해하기 - 업캐스팅, 다운캐스팅 (0) | 2025.04.14 |
|---|---|
| [Java] isEmpty()와 isBlank()의 차이 (0) | 2024.01.29 |
| [Java] 그래프 너비 우선 탐색 알고리즘 Breadth-First Search (0) | 2023.01.20 |
| [Java] 트리 순회 알고리즘 (1) | 2023.01.20 |