java JFrame 具有虚拟绘图空间的缩放 UI 显示

标签 java jframe jpanel scale paint

我有一个应用程序,其图形被认为以 1024x768 显示。

我想让应用程序的大小灵活,而不需要重写所有绘图代码、位置计算等。

为了实现这一点,我尝试通过以下方式重写 JFrame 容器的绘制方法:

@Override
public void paint(Graphics g)
{
    BufferedImage img = new BufferedImage(this.desiredWidth, this.desiredHeight, BufferedImage.TYPE_INT_ARGB);

    Graphics2D gi = (Graphics2D) img.getGraphics();
    gi.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
    gi.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    gi.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);

    super.paint(gi);
    gi.dispose();

    ((Graphics2D) g).drawImage(img, screenScale, null);

}

而 screenScale 是我在构造函数中创建的 AffineTransform 对象,它根据目标大小进行适当的缩放。

现在的问题是:我的子组件被绘制和缩放,但受到父 JFrame 的限制。因此,如果我的父框架的尺寸为 640x480,我添加到其中的子图层只能在其所绘制的 1024x768 BufferedImage 的 640x480 部分内进行绘制。 我猜想在某些地方子组件使用 JFrame 父组件的 getPreferredSize ,因为子组件始终将此值作为边界。所以最终我的缩放策略与 children 的绘画行为相冲突,因为他们完全忽略了他们所交付的用于绘画的图形对象的边界。

最后,无论我做什么,当目标尺寸小于我的“虚拟”屏幕尺寸时,我的子图层(如果重要的话,从 jpanel 派生)都会被切断。

任何人都可以提供更好的解决方案或提示我如何避免忽略图形边界的奇怪行为吗?

编辑:使用未缩放的输出、期望输出和结果输​​出更新上述代码的结果

expected output resulted output

更新:工作测试代码

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.print.attribute.standard.OrientationRequested;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class AffineTransformTest
{

private static TransformingFrame    canvas;
private static JButton button;
private static TestLayer layer;

public static void main(String[] args)
{
    canvas = new TransformingFrame();
    canvas.addMouseWheelListener(new ScaleHandler());

    layer=new TestLayer(canvas.originalSize);
    canvas.getContentPane().add(layer);
    layer.setVisible(true);
    button = new JButton("asdf");
    canvas.setUndecorated(true);
    button.setVisible(true);
    canvas.getContentPane().add(button);


    canvas.pack();



    canvas.setLayout(new BorderLayout());
    canvas.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    canvas.setPreferredSize(canvas.originalSize);
    canvas.setSize(canvas.originalSize);
    canvas.setLayout(null);

    canvas.setVisible(true);
    canvas.validate();
}

@SuppressWarnings("serial")
private static class TransformingFrame extends JFrame
{
    private double  scale;
    private final Dimension originalSize;
    private AffineTransform tx = new AffineTransform();

    TransformingFrame()
    {
        originalSize=new Dimension(800,600);
        scale = 1;
    }

    @Override
    public void paint(Graphics g)
    {
        BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB);
        Graphics bufferGraphics=offscreenBuffer.getGraphics();
        super.paint(bufferGraphics);
        bufferGraphics.dispose();

        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g.setColor(Color.black);
        g.fillRect(0, 0, getWidth(), getHeight());
        ((Graphics2D) g).drawImage(offscreenBuffer, tx,null);
    }
    @Override
    public void paintComponents(Graphics g)
    {
        BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB);
        Graphics bufferGraphics=offscreenBuffer.getGraphics();
        super.paintComponents(bufferGraphics);
        bufferGraphics.dispose();

        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g.setColor(Color.black);
        g.fillRect(0, 0, getWidth(), getHeight());
        ((Graphics2D) g).drawImage(offscreenBuffer, tx,null);

    }
    @Override
    public void paintAll(Graphics g)
    {
        BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB);
        Graphics bufferGraphics=offscreenBuffer.getGraphics();
        super.paintAll(bufferGraphics);
        bufferGraphics.dispose();

        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g.setColor(Color.black);
        g.fillRect(0, 0, getWidth(), getHeight());
        ((Graphics2D) g).drawImage(offscreenBuffer, tx,null);
}

}

@SuppressWarnings("serial")
private static class TestLayer extends JPanel{

public TestLayer(Dimension originalSize)
{
    this.setPreferredSize(originalSize);
    this.setSize(originalSize);
    setOpaque(false);
    setDoubleBuffered(false);
}

@Override
public void paint(Graphics g)
{
    Graphics2D ourGraphics = (Graphics2D) g;
    super.paint(ourGraphics);
    ourGraphics.setColor(Color.green);
    ourGraphics.fillRect(0, 0, getWidth(), getHeight());
    ourGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    ourGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    ourGraphics.setColor(Color.BLACK);

    ourGraphics.drawRect(50, 50, 50, 50);
    ourGraphics.fillOval(100, 100, 100, 100);
    ourGraphics.drawString("Test Affine Transform", 50, 30);
    ourGraphics.drawString(canvas.tx.toString(), 50, 250);
}

}

private static class ScaleHandler implements MouseWheelListener
{
    public void mouseWheelMoved(MouseWheelEvent e)
    {
        if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL)
        {

            // make it a reasonable amount of zoom
            // .1 gives a nice slow transition
            canvas.scale += (.1 * e.getWheelRotation());
            // don't cross negative threshold.
            // also, setting scale to 0 has bad effects
            canvas.scale = Math.max(0.00001, canvas.scale);
            canvas.tx.setTransform(new AffineTransform());
            canvas.tx.scale(canvas.scale, canvas.scale);
            canvas.setPreferredSize(new Dimension((int)(canvas.originalSize.width*canvas.scale),(int)(canvas.originalSize.height*canvas.scale)));
            canvas.setSize(new Dimension((int)(canvas.originalSize.width*canvas.scale),(int)(canvas.originalSize.height*canvas.scale)));
            canvas.validate();
            canvas.repaint();
        }
    }
}

}

由于某种原因,这段代码正在工作(除了按钮消失)..也许我的错误是在子层的其他地方..我会去调查

好吧,经过几个小时的摆弄,我得出的结论是,子面板在其 Paint(Graphics g) 方法中受到的绘图限制不允许绘制超过父面板的大小。在示例中它有效,但在完整的应用程序中则无效。似乎某些设置会在我的应用程序上强制执行该行为,但不会在演示应用程序上执行。

最佳答案

So if my parent frame has the dimension 640x480 the child layers that i have added to it can only draw inside a 640x480 fraction of the 1024x768

创建JFrame --> 放在那里JScrollPane --> 到 JScrollPane 中放置:

1) JPanelJComponent 覆盖 paintComponentn(Graphics g) 而不是 paint(Graphics g)

2) 你写了关于 BufferedImage 的内容,那么更好的方法是将 BufferedImage 写为 IconJLabel

关于java JFrame 具有虚拟绘图空间的缩放 UI 显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8403651/

相关文章:

java - JFrame 表单边框状态不改变

java - 每次在 Java Swing 中单击 JFrame 中的 JButton 时,如何添加一个新的 JPanel 实例

java - 如何在jframe上的java swing面板之间切换?

java - 无法在 Java 中的图像面板中显示图像

java - 如何将实体保存到数据库中?

java - 在类内部扩展线程。在哪里放置另一个类创建?

java - .pack() 导致组件位于错误的位置,但在窗口大小调整后有效

java - 在java中存储数字对

java - 从 JPA 中的对象中选择列表

java - actionPerformed 函数中的 if/else 语句不起作用