【问题标题】:JPanel Layout Image CutoffJPanel 布局图像截断
【发布时间】:2010-03-17 14:10:03
【问题描述】:

我正在向 JPanel 添加图像,但图像被截断。我最初是在尝试 BorderLayout ,但这只适用于一个图像并添加其他图像截止。所以我切换到其他布局,我能得到的最好和最接近的布局是 BoxLayout,但是它增加了一个非常大的截止,这也是不可接受的。

基本上是这样;如何将图像(来自自定义 JComponent)添加到自定义 JPanel 而不会产生不良影响,例如代码中存在的效果。

自定义 JPanel:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.Timer;

public class GraphicsPanel extends JPanel implements MouseListener {
    private Entity test;
    private Timer timer;
    private long startTime = 0;
    private int numFrames = 0;
    private float fps = 0.0f;

    GraphicsPanel() {      
        test = new Entity("test.png");
        Thread t1 =  new Thread(test);
        t1.start();

        Entity ent2 = new Entity("images.jpg");
        ent2.setX(150);
        ent2.setY(150);
        Thread t2 = new Thread(ent2);
        t2.start();

        Entity ent3 = new Entity("test.png");
        ent3.setX(0);
        ent3.setY(150);
        Thread t3 = new Thread(ent3);
        t3.start();

        //ESSENTIAL COMMENT ANY OF THESE and you will see the problem immediately
        //You can use ANY image to reproduce the problem
        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
        add(test);
        add(ent2);
        add(ent3);

        //GAMELOOP
        timer = new Timer(30, new Gameloop(this));
        timer.start();
        addMouseListener(this);
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setClip(0, 0, getWidth(), getHeight());

        g2.setColor(Color.BLACK);
        g2.drawString("FPS: " + fps, 1, 15);
    }

    public void getFPS()
    {
        ++numFrames;
        if (startTime == 0) {
            startTime = System.currentTimeMillis();
        } else {
            long currentTime = System.currentTimeMillis();
            long delta = (currentTime - startTime);
            if (delta > 1000) {
                fps = (numFrames * 1000) / delta;
                numFrames = 0;
                startTime = currentTime;              
            }
        }
    }

    public void mouseClicked(MouseEvent e) {}
    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) { }
    public void mouseExited(MouseEvent e) { }

    class Gameloop implements ActionListener
    {
        private GraphicsPanel gp;

        Gameloop(GraphicsPanel gp) {
            this.gp = gp;
        }

        public void actionPerformed(ActionEvent e) {
            try {
                gp.getFPS();
                gp.repaint();
            } catch (Exception ez) { }
        }
    }
}

主类:

import java.awt.EventQueue;
import javax.swing.JFrame;

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

    private JFrame frame;
    private GraphicsPanel gp = new GraphicsPanel();

    MainWindow()
    {
        EventQueue.invokeLater(new Runnable() {
            public void run() {

                frame = new JFrame("Graphics Practice");
                frame.setSize(680, 420);
                frame.setVisible(true);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                frame.add(gp);
            }
        });
    }
}

自定义 JComponent

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.JComponent;

public class Entity extends JComponent implements Runnable {
    private BufferedImage bImg;
    private int x = 0;
    private int y = 0;
    private int entityWidth, entityHeight;
    private String filename;

    Entity(String filename) {
        this.filename = filename;       
    }

    public void run() {
        bImg = loadBImage(filename);
        entityWidth = bImg.getWidth();
        entityHeight = bImg.getHeight();
        setPreferredSize(new Dimension(entityWidth, entityHeight));
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();

        g2d.drawImage(bImg, x, y, null);

        g2d.dispose();
    }

    public BufferedImage loadBImage(String filename) {
        try {
            bImg = ImageIO.read(getClass().getResource(filename));
        } catch (Exception e) { }
        return bImg;
    }

    public int getEntityWidth() { return entityWidth; }
    public int getEntityHeight() { return entityHeight; }

    public int getX() { return x; }
    public int getY() { return y; }
    public void setX(int x) { this.x = x; }
    public void setY(int y) { this.y = y; }
}

【问题讨论】:

  • 我可以通过让实体加载一堆组件来轻松解决问题,但我觉得这很可能不是最佳实践。

标签: java swing graphics layout java-2d


【解决方案1】:

我注意到的一件事是您的首选尺寸计算不正确。您将首选大小设置为图像的大小。问题是您在 (x, y) 处绘制图像。所以首选尺寸需要考虑到这一点。

否则我不明白这个问题,运行代码也无济于事,因为我不知道你的图片的大小是否应该是大、小、相同大小等等。

【讨论】:

  • 当我将一个对象添加到 GraphicsPanel 时,布局无法正常工作。例如,图像竞争自定义 JPanel 空间。基本上添加组件并不像使用常规 jpanel 那样直观和容易。另外,在设置首选尺寸时如何计算 x、y 位置?
  • 所有组件都相同。您将相同的代码用于常规组件或将自定义组件用于面板。这假设您正确地创建了组件并设置了它的属性。正确。通常,当您将图标添加到标签时,图像会绘制在位置 (0, 0)。如果您在自定义组件中在 (x, y) 处绘制图像,则组件的首选大小会增加 x, y 的数量。
【解决方案2】:

@camickr 可能正确地解释了为什么您现有的方法没有得到您想要的结果。

作为替代方案,您可以考虑在JDesktopPane 中使用JInternalFrame。这样,您的图像将成为可以单独移动、调整大小和滚动的文档。文章How to Use Internal Frames 给出了这样一个实现的外观的想法。这个example 展示了一种交错帧并从菜单中选择它们的简单方法。

【讨论】:

    猜你喜欢
    • 2013-11-03
    • 2019-08-13
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    • 2020-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多