1

ここで質問するのはこれが初めてで、私に役立つ答えやアイデアが得られることを願っています.

大きな画像を描画し、drawImage() で縮小しています。次に、drawImage() を使用して、前のイメージ (2 番目) の上に描画されると予想される別のイメージをすぐに描画します。問題は、最初の画像のスケーリングとレンダリングに約 50 ミリ秒かかる場合でも、drawImage がすぐに返されることです。ほとんどの場合、2 番目の画像は最初の画像の下に配置されます。これは、最初の大きな画像が処理されている間に、2 番目の画像が最初にペイントされるためです。基本的に、drawImage() が完了するまで強制的にブロックしたり、完了したときに何らかの形でチェックしたりする方法はありますか?

インターネットなどから画像をダウンロードするときに正常に機能する ImageObserver パラメーターを認識していますが、既に読み込まれている BufferedImage を使用する場合、スケーリングと描画の直後に ImageUpdate() を起動することはありません。基本的に、最初の画像はすでに「ロード」されているため、ImageObserver に接続することはありません。独自のスレッドで処理するのに約 50 ミリ秒かかり、完了しても通知されません。

強制的にブロックする方法、または画像のスケーリングとブリッティングが完全に完了するまで待つ方法を知っている人はいますか? そして、明らかに Thread.sleep(xx) の使用は完全なハックであり、コンピューターの速度の違いにより実行できません。このすべてのレンダリングは、paint(Graphics g) メソッド内のイベント スレッドで行われます。

ありがとう!

編集: 以下は、私が現在問題のアイデアを提供する必要があるコードです:

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();
}

EDIT 2:私が話している問題をよりよく説明するために、私が説明しようとしているものをより良くするサンプルコードをいくつか作成しました。実行すると、最初の画像が下にある場合にちらつきが表示されることがありますが (本来あるべきように)、ほとんどの場合は 1 つ上 (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;
    }
}
4

2 に答える 2

1

drawImage(null を渡す場所)への最後の引数はImageObserver. そのインターフェースの独自の実装を提供する場合 ( JavaDoc を参照)、画像が実際に描画されたときに通知されます。

于 2013-01-26T01:36:39.293 に答える
1

GraphicsSwing が実際にオブジェクトのコンテンツを画面に表示するタイミングを知ることは不可能です。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、実際にはアプレットやアプレットを一緒に避けるでしょう. 私は自分のキャリアをコーディング アプレットから始めました。特にアイデアをテストするだけの場合は、アプレットは単に苦痛です。

于 2013-01-26T03:56:38.507 に答える