【问题标题】:Drawing text over a bufferedimage on a panel在面板上的缓冲图像上绘制文本
【发布时间】:2019-12-11 20:12:13
【问题描述】:

我正在编写一个由三个不同面板组成的程序。

这是我底部面板的一部分。我使用 BufferedImage 显示图像,我想创建一些文本,这些文本将出现在图像中 350 像素左右,向下 15 像素。我无法让它工作并覆盖在缓冲图像上。

我当前的代码如下(对于底部面板):

public class BtmPanel extends JPanel {
    BtmPanel(){
        try {
            JLabel imgLabel = new JLabel();
            final BufferedImage img = ImageIO.read(new File("image.png"));
            ImageIcon icon = new ImageIcon(img);
            imgLabel.setIcon(icon);
            this.add(imgLabel);
        }
        catch(IOException ie){
            System.out.println("image does not exist");
        }
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawString("Y:  " + MiddlePanel.y ,350,15);
    }
}

【问题讨论】:

  • 要了解为什么您的代码不起作用,请阅读 A Closer Look at the Painting Mechanism 上的 Swing 教程中的部分。问题是标签被绘制在面板顶部,因此它会覆盖面板的自定义绘制。您可以扩展 JLabel 来进行自定义绘画。另外,为什么要使用幻数? 350 和 15 有什么关系。可能还有其他选项,例如将 JLabel 添加到 JLable 并使用布局管理器来定位文本。

标签: java swing text label awt


【解决方案1】:

根据您的需要和愿望,您可以通过多种方式实现这一目标。

例如,您可以直接自己绘制而不是使用JLabel 来显示图像,例如...

public class BtmPanel extends JPanel {
    private BufferedImage image;
    BtmPanel(){
        try {
            image = ImageIO.read(new File("image.png"));
        }
        catch(IOException ie){
            System.out.println("image does not exist");
        }
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (image != null) {
            g.drawImage(0, 0, image, this);
        }
        g.drawString("Y:  " + MiddlePanel.y ,350,15);
    }
}

这样做的原因是你没有(真的)控制图像在JLabel 中的位置(很多事情都会影响它的位置)。

另一种解决方案是将文本直接绘制到BufferedImage 本身上。您将使用哪个取决于文本的动态程度以及许多其他因素

【讨论】:

    【解决方案2】:

    执行此操作的方法与您的示例完全相反,覆盖 JPanel 的绘画方法绘制 BufferedImage(使用您的图像创建背景),然后您通常可以在 JPanel 扩展上添加带有文本的 JLabel。

    请注意,如果 JPanel 已调整大小并且您不希望背景质量不佳,则必须手动创建调整大小的版本以适应容器,或者至少调整缓冲图像的大小保持宽度/高度比的逻辑......没那么容易! 对于基本版本,您可以尝试以下内容(取自一个工作示例)paintComponent 覆盖函数:

    @Override
    protected void paintComponent(Graphics g) {
        Image background = backgroundImage.getScaledInstance(this.getWidth(), this.getHeight(), Image.SCALE_DEFAULT);
    
        super.paintComponent(g);
        if (backgroundImage != null) {
            g.drawImage(background, 0, 0, null);
        }
    }
    

    希望这会有所帮助;)

    【讨论】:

    • (1-) 您不应该在 paintComponent() 方法中读取图像。您不想在每次需要重新绘制组件时都读取图像。
    • 我这样做了(或者,更好,更复杂的版本,我没有在此处粘贴以保持答案简单)因为当用户调整容器大小时我需要调整大小,但是是的,更好的方法应该是使用窗口侦听器而不是重绘方法......但这对我来说是诀窍并且效果很好,即使它不是一个完美的解决方案。所以,对不起,如果我没有复制粘贴我的完整解决方案:)
    • 如果您需要调整大小以填充窗口,您可以使用:g.drawImage(0, 0, getWidth(), getHeight(), null)。不需要 WindowListener 或每次都创建缩放图像。
    • 感谢您的解释!所以..你能解释一下你的解决方案与在绘制之前手动调整图像大小有什么区别吗?手动调整图像大小并按原样绘制(就像我以前一样)和使用绘制方法调整大小之间是否有任何真正的性能差异?我一直认为 JVM 执行的代码没有真正的实际差异。这对你来说是一种代码风格的好习惯吗?非常感谢!
    • 我不知道是否有任何真正的区别。但是你正在做额外的工作。您必须创建图像并在图像上绘画。然后你将图像绘制到面板上,所以你要绘制两次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-12
    • 2012-06-25
    • 2017-07-07
    • 1970-01-01
    相关资源
    最近更新 更多