Java 프린터 미리보기와 출력 프로그램 (명찰 출력)

2025. 11. 25. 17:24·Java

 

 

 

개요

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

 

 

실행 화면

 

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

 

 

 

 

  • 상단 출력하기 버튼 클릭 시 나타나는 화면
  • 내 PC에 연결된 모든 프린터를 불러온다. 

 

 

 

전체 구조 요약

  1. Person 클래스: 출력할 데이터 구조 정의 (이름, 역할, 직책)
  2. PrintTest 클래스: Printable 구현 → 페이지 단위로 인쇄 가능
  3. PreviewPanel 클래스: 스크롤 가능한 미리보기 패널
  4. 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
'Java' 카테고리의 다른 글
  • Java 상속(Inheritance) 이해하기 - 업캐스팅, 다운캐스팅
  • [Java] isEmpty()와 isBlank()의 차이
  • [Java] 그래프 너비 우선 탐색 알고리즘 Breadth-First Search
  • [Java] 트리 순회 알고리즘
오은이
오은이
  • 오은이
    오은이 하우스
    오은이
  • 전체
    오늘
    어제
    • 분류 전체보기 (86) N
      • 일기 (2)
      • Python (1)
      • Java (5) N
      • CS (2)
      • 코딩테스트 (26)
        • 백준 (25)
        • 프로그래머스 (1)
      • 웹 개발 (18)
        • Spring (7)
        • JavaScript (3)
        • WebSquare (5)
        • React (3)
      • DB (5)
        • MySQL (4)
        • Oracle (1)
      • 서버&인프라 (18)
        • Server (5)
        • Cloud (12)
        • Linux (1)
      • 자격증 (9)
        • 정보처리기사 (2)
        • AICE (7)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    Associate
    dockerspring
    EC2
    클라우드
    백준자바
    Java
    클라우드 배포
    docker
    백준
    react
    톰캣
    MySQL
    db
    티스토리챌린지
    Apache
    AICE Associate
    SpringBoot
    cloud DB
    AICE
    리액트
    웹스퀘어
    알고리즘
    머신러닝
    docker배포
    Spring
    websquare
    오블완
    tomcat
    AI
    자바
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
오은이
Java 프린터 미리보기와 출력 프로그램 (명찰 출력)
상단으로

티스토리툴바