3

私はJava、Swing、およびGUIプログラミングの初心者なので、Swingとその背後にあるスレッドモデルを使用してGUIを構築する際の中心的なポイントをいくつか見逃している可能性があります。私が試している演習は、キャンバス上でフィギュアを作成、移動、サイズ変更するための小さなアプリケーションで構成されています。さらに、ビューを可能な限り動作しないようにしようとしています。プレゼンターオブジェクトは、目的の動作を注入する責任があります。言い換えると、ビューに図形や図形の描画方法を知らせたくありません。プレゼンターが、状態を表すために描画する必要があるものを認識しているオブジェクトを提供するためのsetUpdater()メソッドを提供するだけです。モデル。

しかし、私は問題を発見しました。ある状況下では、数字が失われます。たとえば、アプリケーションウィンドウをアイコン化してから非アイコン化するとします。キャンバスコンポーネントのpaintComponent()が呼び出されていないと思いましたが、ブレークポイントで問題が異なることがわかりました。呼び出されて図形がペイントされた後、消えました。

ボタン、スライダー、さらにはモデルなしで問題を表示するために、コードを単純化しようとしました。ただし、この分離は私の目的にとって重要であるため、ビューとプレゼンター用に別々のクラスを保持しています。

簡略化した例をテストしているマシンでは、paintComponentが呼び出されたときに描画される図(常に同じ円)は、アイコン化解除後だけでなく、ペイントされるたびに消えます。

何が起こっているのか、そしてそれを解決する方法を理解するのを手伝ってください。

TYIA。

PS1:簡略化されたコードは次のとおりです。

import java.awt.*;
import javax.swing.*;

interface ViewUpdater {
    void updateCanvas(Graphics2D g2d);
}

class View {
    private JFrame windowFrame;
    private JPanel canvasPanel;
    private ViewUpdater updater;
    public static final Color CANVAS_COLOR = Color.white;
    public static final int CANVAS_SIDE = 500;

    public View() {
        windowFrame = new JFrame();
        windowFrame.
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        canvasPanel = new JCanvas();
        canvasPanel.setBackground(CANVAS_COLOR);
        canvasPanel.
            setPreferredSize(new Dimension(CANVAS_SIDE,
                                           CANVAS_SIDE));
        windowFrame.getContentPane().add(canvasPanel);
        windowFrame.pack();
        windowFrame.setResizable(false);
    }

    public void setVisible() {
        windowFrame.setVisible(true);
    }

    public void setUpdater(ViewUpdater updater) {
        this.updater = updater;
    }

    public void updateView() {
        System.out.println("BEGIN updateView");
        Graphics2D g2d =(Graphics2D) canvasPanel.getGraphics();
        g2d.setColor(CANVAS_COLOR);
        g2d.fillRect(0, 0, CANVAS_SIDE, CANVAS_SIDE);
        if (updater != null) {
            System.out.println("GOING TO updateCanvas");
            updater.updateCanvas(g2d);
        }
        System.out.println("END updateView");
   }

    private class JCanvas extends JPanel {

        private static final long serialVersionUID =
                                    7953366724224116650L;

        @Override
        protected void paintComponent(Graphics g) {
            System.out.println("BEGIN paintComponent");
            super.paintComponent(g);
            updateView();
            System.out.println("END paintComponent");
        }
    }
}

class Presenter {
    private View view;
    private static final Color FIGURE_COLOR = Color.black;

    public Presenter(View view) {
        this.view = view;
        this.view.setUpdater(new ProjectViewUpdater());
        this.view.setVisible();
    }

    private class ProjectViewUpdater
        implements ViewUpdater {
        @Override
        public void updateCanvas(Graphics2D g2d) {
            g2d.setColor(FIGURE_COLOR);
            g2d.drawOval(100, 100, 300, 300);
            // The circle immediately disappears!
        }
    }
}

public class Main {
    public static void main(String[] args) {
        new Presenter(new View());
    }
}

PS2: Swingの使用に関連するスレッドモデルを理解するためにhttp://www.javaworld.com/javaworld/jw-08-2007/jw-08-swingthreading.htmlを読んでいますが、まだ特別なことは何もしていません。私のコードのスレッドを制御するため。

PS3:グーグルの問題に対する答えが見つかりませんでした。最も類似した問題は、おそらくhttp://www.eclipse.org/forums/index.php/t/139776/で答えられていない問題です。

4

1 に答える 1

4

問題は、JPanelを呼び出してGraphicsオブジェクトを取得していることです。getGraphics()このようにして取得したGraphicsオブジェクトは長持ちしないため、次の再描画時に同様に描画されたものはすべて消えます。

解決策:これを行わないでください。また

  • JVMによってpaintComponentメソッドに与えられたGraphicsオブジェクトを使用して描画するか、
  • getGraphics()またはをBufferedImageで呼び出してGraphicsまたはGraphics2Dオブジェクトを取得し、これを使用して描画し、破棄してから、JVMから渡されたGraphicsオブジェクトを使用しcreateGraphics()てJComponentまたはJPanelのメソッドでBufferedImageを再度描画します。paintComponent(...)

あなたの状況では、BufferedImage、または上記のポイント2を使用するのが最善だと思います。

于 2012-05-01T02:03:14.803 に答える