[java] JFrame에서 이미지를 제대로 새로 고치는 방법은 무엇입니까?



Answers

이것이 내가 생각해 낸 것입니다.

private static class MyJPanel extends JPanel {
    private Image img = null;

    public MyJPanel() {}

    public void setImage(Image value) {
        if (img != value) {
            Image old = img;
            this.img = value;
            firePropertyChange("image", old, img);
            revalidate();
            repaint();
        }
    }

    public Image getImage() {
        return img;
    }

    @Override
    public Dimension getPreferredSize() {
        return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(this), img.getHeight(this));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (img != null) {
            Graphics2D g2d = (Graphics2D) g.create();

            int width = getWidth();
            int height = getHeight();
            double scaleFactor = getScaleFactorToFit(new Dimension(img.getWidth(this), img.getHeight(this)), getSize());
            int x = (int) ((width - (img.getWidth(this) * scaleFactor)) / 2);
            int y = (int) ((height - (img.getHeight(this) * scaleFactor)) / 2);

            AffineTransform at = new AffineTransform();
            at.translate(x, y);
            at.scale(scaleFactor, scaleFactor);
            g2d.setTransform(at);
            g2d.drawImage(img, 0, 0, this);
            g2d.dispose();
        }
    }

    public double getScaleFactor(int iMasterSize, int iTargetSize) {
        return (double) iTargetSize / (double) iMasterSize;
    }

    public double getScaleFactorToFit(Dimension original, Dimension toFit) {
        double dScale = 1d;
        if (original != null && toFit != null) {
            double dScaleWidth = getScaleFactor(original.width, toFit.width);
            double dScaleHeight = getScaleFactor(original.height, toFit.height);
            dScale = Math.min(dScaleHeight, dScaleWidth);
        }
        return dScale;
    }
}

private static class MyJFrame extends JFrame implements Runnable {
    private BufferedImage img = null;
    private MyJPanel panel = null;

    public MyJFrame(BufferedImage image, String title) {
        super(title);
        img = image;
    }

    @Override
    public void run() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {}

        panel = new MyJPanel();
        panel.setImage(img);

        setLayout(new BorderLayout());
        add(BorderLayout.CENTER, panel);
        setLocation(200, 200);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        pack();
        setVisible(true);
    }

    public void changeImage(BufferedImage image) {
        if ((panel != null) && (panel.getImage() != image)) panel.setImage(image);
    }
}

@MadProgrammer가 제공 한 예제의 복사 - 붙여 넣기는 매우 간단합니다.

남은 유일한 것은 EDT 사용법입니다. 이것은 나를 위해 마술 입니다. 더러운 방식 으로이 코드를 호출하고 있습니다.

MyJFrame mjf = null;
javax.swing.SwingUtilities.invokeLater(mjf = new MyJFrame(buffer, "RDP"));
...
mjf.changeImage(buffer);

내 질문은 : EDT 와 함께 changeImage 메서드를 어떻게 사용합니까?

Question

이 문제는 지금 몇 시간 동안 나를 방해하고 나 스스로 해결할 수없는 문제입니다 ...

비슷한 주제가 인터넷에서 발견되었지만 잘 설명 되고 가능한 한 간단한 해결책을 찾지 못했습니다. 또한 EDTSwingWorker API 문서를 살펴 봤지만 너무 복잡했습니다. (

자, 요점을 알려 드리겠습니다. JLabel이 포함 된 간단한 JFrame이 내부 이미지로 구성되어 있습니다.

private static class MyJLabel extends JLabel {
    private ImageIcon img = null;

    public MyJLabel(ImageIcon img) {
        super();
        this.img = img;
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(img.getImage(), 0, 0, getWidth(), getHeight(), this);
    }
}

private static class MyJFrame extends JFrame implements Runnable {
    private BufferedImage img = null;
    private MyJLabel label = null;

    public MyJFrame(BufferedImage image, String title) {
        super(title);
        img = image;
    }

    @Override
    public void run() {
        Dimension dims = new Dimension(img.getWidth(), img.getHeight());
        dims = new Dimension(dims.width / 2, dims.height / 2);

        label = new MyJLabel(new ImageIcon(img));
        label.setPreferredSize(dims);

        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                label.repaint();
            }
        });
        setLayout(new BorderLayout());
        getContentPane().add(BorderLayout.CENTER, label);
        setLocation(200, 200);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        pack();
        setVisible(true);
    }

    public void changeImage(BufferedImage image) {
        img = image;
        if (label != null) {
            label.setIcon(new ImageIcon(img));
            label.repaint();
        }
    }
}

다음 코드에 의해 호출됩니다.

buffer = receiveImage(in); // download image

MyJFrame f = null;
javax.swing.SwingUtilities.invokeLater(f = new MyJFrame(buffer, "RDP"));

int x = 0;
while (x <= 15) {
    txt.println("next"); // notify server that we are ready

    while (true) { // wait for server
        if (reader.readLine().equals("ready")) break;
    }

    buffer = receiveImage(in); // download image

    // do some magic here and refresh image somehow :(
    f.changeImage(buffer); // does not work!

    x++;
}

불행히도, changeImage 메서드를 사용한 나의 접근 방식은 작동하지 않습니다. 아무 일도 일어나지 않습니다 (GUI는 시작하지만 결코 업데이트되지 않습니다).

이걸 좀 도와 주셔서 감사합니다. 적절한 설명이있는 간단 하고 실제적인 예제가 가장 만족 될 것입니다;)

인사말!




Links