You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java打印文本文件问题:解决深色L&F下JTextArea打印变白

解决方案:Swing文本编辑器打印功能适配与深色L&F打印问题处理

一、核心需求解决思路

针对你提出的「带应用图标、系统原生风格的打印对话框」「强制打印文本为黑色」两个核心需求,我们可以通过手动控制PrinterJob流程+自定义Printable渲染逻辑来实现,既规避L&F对打印颜色的影响,又能让用户自主选择打印参数。

二、完整实现代码

import java.awt.*;
import java.awt.print.*;
import javax.swing.*;
import javax.swing.text.*;

public class EditorPrinter {
    private final JTextArea textArea;
    private final Window parentWindow;

    public EditorPrinter(JTextArea textArea, Window parentWindow) {
        this.textArea = textArea;
        this.parentWindow = parentWindow;
    }

    public void startPrint() {
        PrinterJob printerJob = PrinterJob.getPrinterJob();
        printerJob.setJobName("文本编辑器打印任务");

        // 自定义打印渲染逻辑,强制文本为黑色
        printerJob.setPrintable((graphics, pageFormat, pageIndex) -> {
            Graphics2D g2d = (Graphics2D) graphics;
            // 偏移到打印可绘制区域
            double x = pageFormat.getImageableX();
            double y = pageFormat.getImageableY();
            g2d.translate(x, y);

            // 强制设置文本颜色为黑色,不受L&F影响
            g2d.setColor(Color.BLACK);

            // 适配打印区域的字体(保留原字体样式,可按需调整缩放比例)
            Font originalFont = textArea.getFont();
            Font printFont = originalFont.deriveFont((float) (originalFont.getSize2D() * 0.95));
            g2d.setFont(printFont);

            // 处理文本分页与绘制
            Document doc = textArea.getDocument();
            try {
                String content = doc.getText(0, doc.getLength());
                LineBreakMeasurer measurer = new LineBreakMeasurer(
                        new AttributedString(content).getIterator(), g2d.getFontRenderContext());
                float drawY = 0;
                float lineHeight = printFont.getSize2D() * 1.2f; // 行间距
                float printWidth = (float) pageFormat.getImageableWidth();

                while (measurer.getPosition() < content.length()) {
                    if (drawY + lineHeight > pageFormat.getImageableHeight()) {
                        return pageIndex == 0 ? Printable.PAGE_EXISTS : Printable.NO_SUCH_PAGE;
                    }
                    TextLayout layout = measurer.nextLayout(printWidth);
                    drawY += layout.getAscent();
                    layout.draw(g2d, 0, drawY);
                    drawY += layout.getDescent() + layout.getLeading();
                }
                return pageIndex == 0 ? Printable.PAGE_EXISTS : Printable.NO_SUCH_PAGE;
            } catch (BadLocationException e) {
                e.printStackTrace();
                return Printable.NO_SUCH_PAGE;
            }
        });

        // 初始化打印属性集(可添加默认纸张、方向等设置)
        PrintRequestAttributeSet attrSet = new HashPrintRequestAttributeSet();
        attrSet.add(MediaSizeName.ISO_A4);

        // 弹出系统原生打印对话框,自动继承父窗口图标
        boolean userConfirmed = printerJob.printDialog(parentWindow, attrSet);
        if (userConfirmed) {
            try {
                printerJob.print(attrSet);
            } catch (PrinterException e) {
                JOptionPane.showMessageDialog(parentWindow, "打印失败:" + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
}

三、关键细节说明

  • 强制黑色文本:通过在Printable的print方法中直接设置g2d.setColor(Color.BLACK),完全绕过L&F对组件前景色的设置,确保打印文本始终为黑色。
  • 系统适配对话框:PrinterJob.printDialog()调用系统原生打印界面,自动适配Windows/Mac的系统风格;同时传入父窗口Window,对话框会自动继承应用图标(需提前给父窗口设置图标:parentWindow.setIconImage(new ImageIcon("your-app-icon.png").getImage()))。
  • 用户自主选择:必须经过用户确认对话框后才执行打印,避免直接使用默认打印机。
  • 分页逻辑:通过LineBreakMeasurer处理文本自动换行与分页,保证内容在打印区域内正常显示。

四、使用方式

在你的编辑器主逻辑中,直接调用工具类即可:

// 假设textArea是你的编辑区域实例,mainFrame是应用主窗口
EditorPrinter printer = new EditorPrinter(textArea, mainFrame);
printer.startPrint();

内容的提问来源于stack exchange,提问作者user21603351

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:42:47