簡體   English   中英

如何判斷Graphics.drawImage()實際完成的時間

[英]How to tell when Graphics.drawImage() has actually completed

這是我第一次在這里問一個問題,我希望得到一個能幫到我的答案或想法。

我正在繪制一個大圖像並使用drawImage()縮小它。 然后我立即用drawImage()繪制另一個圖像,我期望在前一個(第二個)之上繪制。 問題是drawImage會立即返回,即使縮放和渲染第一個圖像需要大約50毫秒。 大多數情況下,第二張圖像最終位於第一張圖像的下方,因為它首先被繪制,而第一張圖像正在被處理。 反正基本上是強制drawImage()阻止直到它完成,或以某種方式檢查它何時完成?

我知道ImageObserver參數,從Internet或其他東西下載圖像時工作正常,但是當使用已經加載的BufferedImage時,它只是在縮放和繪制之后才會觸發ImageUpdate()。 基本上,由於第一個圖像已經“加載”,它從不接觸ImageObserver,它只需要約50毫秒的自己的線程來處理,從不通知它何時完成。

有誰知道如何強迫它阻止或等到它完全完成縮放和blitting圖像? 顯然使用Thread.sleep(xx)是一個完整的黑客,由於計算機速度之間的差異而不可行。 所有這些渲染都發生在paint(Graphics g)方法中的Event線程上。

謝謝!

編輯:以下是我目前要給你的問題的代碼:

public void paint(Graphics window)
{
    window.setColor(Color.WHITE);
    window.fillRect(0, 0, Settings.width * Settings.aaFactor, Settings.height * Settings.aaFactor);

    Graphics2D window2D = (Graphics2D) window;
    window2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    window2D.drawImage(this.image, 0, 0, Settings.width, Settings.height, null);

    try
    {
        Thread.sleep(50);
    }
    catch (InterruptedException e)
    {
        e.printStackTrace();
    }

    window2D.drawImage(this.image2, 0, 0, null);

    repaint();
}

編輯2:為了更好地解釋我正在談論的問題,我制作了一些示例代碼,這些代碼做得更好,我正在嘗試解釋。 運行它,你會看到它閃爍,有時第一個圖像在底部(就像它應該是),但大多數時候它將是一個頂部(第二個),這是錯誤的。 只需將文件路徑更改為小圖像和大圖像。

public class Main extends Applet implements ImageObserver
{
    private BufferedImage imageA;
    private BufferedImage imageB;

    @Override
    public void init()
    {
        try
        {
            this.imageA = ImageIO.read(new File("C:\\LargeImage.jpg"));
            this.imageB = ImageIO.read(new File("C:\\SmallImage.jpg"));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    @Override
    public void update(Graphics g)
    {
        paint(g);
    }

    @Override
    public void paint(Graphics g)
    {
        Graphics2D w = (Graphics2D) g;
        w.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        w.drawImage(this.imageA, 0, 0, 50, 50, this);// This takes a while to do (scaling down and drawing)...
        w.drawImage(this.imageB, 10, 10, null);// While this is drawn quickly, before A is done.

        repaint();
    }

    @Override
    public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
    {
        System.out.println("ImageObserver fired, done drawing image.  NEVER CALLED!");
        return false;
    }
}

drawImage的最后一個參數(傳遞null的地方)是一個ImageObserver 如果您提供自己的接口實現( 請參閱JavaDoc ),則會在實際繪制圖像時通知您。

無法知道Swing何時實際將Graphics對象的內容呈現給屏幕。 知道的是,直到paint方法返回之后才會發生這種情況(因為Graphics對象在渲染之前尚未完成渲染)。

你應該做的是讓你正在繪制的Component決定什么時候需要更新,這是它的設計方式...( Component實現ImageObserver

以下示例在調整幀大小時不斷重新縮放主背景圖像

在此輸入圖像描述

public class TestPaint03 {

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

    public TestPaint03() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new PaintPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class PaintPane extends JPanel {

        private BufferedImage background;
        private BufferedImage foreground;
        private Image scaled;

        public PaintPane() {

            try {
                background = ImageIO.read(new File("/path/to/background/image));
                foreground = ImageIO.read(new File("path/to/foreground/image"));
            } catch (Exception e) {
            }

        }

        @Override
        public void invalidate() {
            scaled = null;
            super.invalidate();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            if (background != null) {

                if (scaled == null) {
                    int size = Math.min(getWidth(), getHeight());
                    scaled = background.getScaledInstance(-1, size, Image.SCALE_SMOOTH);
                }

                int x = (getWidth() - scaled.getWidth(this)) / 2;
                int y = (getHeight() - scaled.getHeight(this)) / 2;
                g.drawImage(scaled, x, y, this);

                x = (getWidth() - foreground.getWidth()) / 2;
                y = (getHeight() - foreground.getHeight()) / 2;
                g.drawImage(foreground, x, y, this);

            }
        }
    }
}

雖然我確定你有自己的理由,但我個人會避免Applet支持JApplet ,事實上,我個人會避免使用applet。 我開始編寫applet的職業生涯,他們只是一種痛苦,特別是當你想要做的就是測試一個想法時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM