带有背景图的JTextArea内部填充问题

6
我的最终目标是拥有一个带有背景图片的 JTextArea。我在网上找到了代码,教我如何做到这一点,但现在我遇到一个问题,就是文本叠在图片上面。
这就是我的意思: Text overlapping image 有没有办法添加一种向内的缩进,使文本不会重叠在图片边缘上?
这是原始的评论气泡图像。 Comment bubble
以下是代码:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.GrayFilter;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class myBackgroundSample {

    String file;

    public myBackgroundSample(String i) {
        file = i;
        setItUp();
    }

    public void setItUp() {
        final ImageIcon imageIcon = new ImageIcon(file);
        JTextArea textArea = new JTextArea() {
            Image image = imageIcon.getImage();

            public void paint(Graphics g) {
                setOpaque(false);
                g.drawImage(image, 0, 0, this);
                super.paint(g);
            }
        };
        JFrame frame = new JFrame("Background Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JScrollPane scrollPane = new JScrollPane(textArea);
        Container content = frame.getContentPane();
        content.add(scrollPane, BorderLayout.CENTER);
        frame.setSize(400, 400);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String right = "chat1.jpg";
        myBackgroundSample temp = new myBackgroundSample(right);

    }
}

这是chat1的图片: https://lh4.googleusercontent.com/-uhDR71VGYfA/TuRNiM2DfOI/AAAAAAAAADU/DqOuEi8c3lg/s334/chat1.jpg - user1091968
1
  1. 为什么要使用 JTextArea(而不是 JLabel 或其他样式组件)?
  2. 我认为最好使用一个自定义边框,即 CommentBubbleBorder
  3. Swing 组件应该重写 paintComponent(Graphics),而不是 paint(Graphics)
- Andrew Thompson
你是否该选择一些早期问题的答案了? - Andrew Thompson
4个回答

12

使用扩展AbstractBorder的自定义边框。 可以使用以下类似的代码:

文本气泡边框

如何获得精确的形状和颜色留给读者作为练习。 :)

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.AbstractBorder;

class TextBubbleBorder extends AbstractBorder {

    private Color color;
    private int thickness = 4;
    private int radii = 8;
    private int pointerSize = 7;
    private Insets insets = null;
    private BasicStroke stroke = null;
    private int strokePad;
    private int pointerPad = 4;
    RenderingHints hints;

    TextBubbleBorder(
        Color color) {
            new TextBubbleBorder(color, 4, 8, 7);
    }

    TextBubbleBorder(
        Color color, int thickness, int radii, int pointerSize) {
            this.thickness = thickness;
            this.radii = radii;
            this.pointerSize = pointerSize;
        this.color = color;

        stroke = new BasicStroke(thickness);
        strokePad = thickness/2;

        hints = new RenderingHints(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

        int pad = radii + strokePad;
        int bottomPad = pad + pointerSize + strokePad;
        insets = new Insets(pad,pad,bottomPad,pad);
    }

    @Override
    public Insets getBorderInsets(Component c) {
        return insets;
    }

    @Override
    public Insets getBorderInsets(Component c, Insets insets) {
        return getBorderInsets(c);
    }

    @Override
    public void paintBorder(
        Component c,
        Graphics g,
        int x, int y,
        int width, int height) {

        Graphics2D g2 = (Graphics2D)g;

        int bottomLineY = height-thickness-pointerSize;

        RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(
            0+strokePad,
            0+strokePad,
            width-thickness,
            bottomLineY,
            radii,
            radii
            );

        Polygon pointer = new Polygon();

        // left point
        pointer.addPoint(
            strokePad+radii+pointerPad,
            bottomLineY);
        // right point
        pointer.addPoint(
            strokePad+radii+pointerPad+pointerSize,
            bottomLineY);
        // bottom point
        pointer.addPoint(
            strokePad+radii+pointerPad+(pointerSize/2),
            height-strokePad);

        Area area = new Area(bubble);
        area.add(new Area(pointer));

        g2.setRenderingHints(hints);

        Area spareSpace = new Area(new Rectangle(0,0,width,height));
        spareSpace.subtract(area);
        g2.setClip(spareSpace);
        g2.clearRect(0,0,width,height);
        g2.setClip(null);

        g2.setColor(color);
        g2.setStroke(stroke);
        g2.draw(area);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JLabel l = new JLabel(
                    "The quick brown fox jumped over the lazy dog!");

                l.setBorder(new TextBubbleBorder(Color.MAGENTA.darker(),2,4,0));
                l.setOpaque(true);
                l.setBackground(Color.BLACK);
                JOptionPane.showMessageDialog(null, l);
            }
        });
    }
}

谢谢!有几个问题: 左边的小“i”气泡是什么? 这段代码的哪一部分可以编辑,以便单词换行而不是拉伸文本区域? “以便对话气泡从右侧发出? 我的总体目标是模拟聊天的对话视图。 - user1091968
请参阅编辑中的进一步信息(以及重复的问题)以获取答案。 - Andrew Thompson

6

您应该使用Border,更具体地说,您应该使用BorderFactory.createEmptyBorder(int top, int left, int bottom, int right)

textArea.setBorder(BorderFactory.createEmptyBorder(10,10,15,10));

你应该重写 paintComponent 而不是 paint。另外,使用 setRows()setColumns() 来设置文本区域的大小,然后你可以使用 pack() 而不是 setSize(400,400),因为这不是一个推荐的方法。请参考以下示例:
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;


public class Test extends JFrame {

    class MyTextArea extends JTextArea {

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D)g;
            g2.setColor(Color.PINK);
            g2.setStroke(new BasicStroke(4));
            g2.drawRoundRect(3, 3, getWidth()-7, getHeight()-7, 5, 5);
        }

    }

    public Test() {
        JPanel panel = new JPanel(new BorderLayout());
        JTextArea textArea = new MyTextArea();
        textArea.setRows(3);
        textArea.setColumns(25);
        textArea.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        panel.add(textArea, BorderLayout.NORTH);

        add(panel);
        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    public static void main(String[] args) {
        new Test();
    }

}

1
不错的例子,但我仍然认为自定义边框是这个问题的解决方法。;) - Andrew Thompson
@AndrewThompson:你说得对。这取决于他想要做多少更改。这个单行修复可能有所帮助,但不一定是最佳解决方案。对你的解决方案点赞。 - Jonas
+1. 对于那些不擅长图形设计的人来说,这是最简单的解决方案 :) - camickr
谢谢! 我正在使用这行代码: textArea.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); ...来创建一个边框,使得文本看起来像是被限制在气泡图像内部。 - user1091968

1

发布代码,每行缩进四个空格。

我假设您正在覆盖paintComponent()*以适应您的JTextArea。如果是这样,请确保它是透明的,方法是添加

setOpaque(false);

*如果您覆盖paint(),这也可以工作,但正如trashgod所正确指出的那样,这将干扰paintBorder()


Swing程序应该重写paintComponent()而不是重写paint()。—AWT和Swing中的绘图:绘图方法 - trashgod

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接