1

MVC デザイン パターンを使用して、Java で画像編集アプリケーションを作成しようとしています。したがって、イベント処理はコントローラーにあり、状態と状態に関連する操作はモデルに保存され、ユーザーが見るものはすべてビューに保存されます。

画像を開くと、表示されている画像のズーム レベルを表示するズーム ボックスがあります。ズームは、最初にレンダリングされるときに自動的に計算されますpaintComponent()(手順 3 を参照)。画像を開くときに、ズームレベルを計算されたものに設定したいと思います。問題は、ズーム レベルが 0と表示されることです。その理由はわかっています。説明させてください:

1. 開いActionListener ているメニュー項目の が起動されます

JPSController:

class MenuBarFileOpenListener implements ActionListener {
    public void actionPerformed(ActionEvent event) {
        File fileChooserReturnValue = view.showAndGetValueOfFileChooser();

        if (fileChooserReturnValue != null) {
            try {
                // irrelevant code omitted
                view.addDocument(newDocument);
            } catch(IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}

2. view.addDocument() 呼ばれる

注:これが問題の根源です

JPSView:

public void addDocument(DocumentModel document) {
    // irrelevant code omitted

    // CanvasPanelView extends JPanel
    documentsTabbedPane.add(newDocumentView.getCanvasPanelView());

    // THIS IS THE ROOT OF THE PROBLEM
    double currentZoomFactor = getCurrentCanvasPanelView().getZoomFactor();

    // formatting the text
    String zoomLevelText = statusBar_zoomLevelTextField_formatter.format(currentZoomFactor);
    // setting the text of the text field
    statusBar_zoomLevelTextField.setText(zoomLevelText);
}

3. しばらくして、 paintComponent() 実行されます

CanvasPanelView では、JPanel を拡張します。

public void paintComponent(Graphics g) {
    super.paintComponent(g);

    if (initialRender) {
        initialRender = false;

        // calculates a good zoom level
        setZoomFit();
    }

    // irrelevant code omitted

    g.drawImage(image, destinationX1, destinationY1, destinationX2,
                destinationY2, sourceX1, sourceY1, sourceX2, sourceY2, null);
    }

パート 2 には、次のコード行があります。

double currentZoomFactor = getCurrentCanvasPanelView().getZoomFactor();

getZoomFactor()呼び出されると、 currentCanvasPanelViewは を返すため、サイズを持ってはなりません0。私は以前にこの問題を抱えていましたが、私の解決策は #3 の次のコード行でした。

if (initialRender) {
    initialRender = false;
    setZoomFit();
}

paintComponent() が呼び出されたCanvasPanelViewとき、それまでに にサイズが指定されている必要がありますが、getZoomFactor() が呼び出されたときではありません。paintComponent()、したがって setZoomFit() も、明らかに getZoomFactor() の後に来ます。

画像を開いたときに画像のズーム レベルを正しく表示するにはどうすればよいですか?

4

1 に答える 1

4

基本的に、一種の競合状態があります(シングルスレッドで可能な限り)。

何が起こっているかというと、すぐにレイアウトされることを期待して、新しいビューを追加しています。これは、Swing での動作とは異なります。新しいコンポーネントをコンテナーに追加すると、階層内のすべてのコンポーネントのレイアウトを更新し、無効としてマークされたすべてのコンテナーをレイアウトする要求が行われます。これは、現在の呼び出しサイクルが完了し、イベント ディスパッチ スレッドがすべての要求を処理する時間ができるまで発生しません。

代わりに、イベント ディスパッチ スレッドの最後にリクエストを追加することで、後でルックアップをスケジュールできます。これにより、EDT の現在のすべてのタスクがその前に実行された後に、リクエストが実行されることが保証されます (従うべきタスクが他にもあるかもしれませんが、絞り込みました)。

次の例は、その点を示しています。

に新しいパネルを追加し、JTabbedPane現在のサイズSwingUtilities.invokeLaterをダンプし、将来一度にコールバックを要求するために使用し、パネルのサイズを再度ダンプします。0x0最初のリクエストが有効で、2 番目のリクエストが有効な値であることがわかります (フレームのサイズとルック アンド フィールによって異なります)。

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestTabbedPane01 {

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

    private JTabbedPane tabbedPane;

    public TestTabbedPane01() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                tabbedPane = new JTabbedPane();
                JButton btnAdd = new JButton("Add");
                btnAdd.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        final JPanel panel = new JPanel(new GridBagLayout());
                        panel.add(new JLabel(String.valueOf(tabbedPane.getComponentCount())));
                        tabbedPane.add(String.valueOf(tabbedPane.getComponentCount()), panel);
                        System.out.println("New Panel Size = " + panel.getSize());
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                System.out.println("New Panel Size (later) = " + panel.getSize());
                            }
                        });
                    }
                });

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(tabbedPane);
                frame.add(btnAdd, BorderLayout.SOUTH);
                frame.setSize(200, 200);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }


}
于 2013-05-19T05:21:27.187 に答える