我该如何修复此代码错误?

时间:2013-05-19 04:26:49

标签: java swing paintcomponent jtabbedpane

我正在尝试使用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()时,当前CanvasPanelView的大小不得超过,因为它会返回0。我以前遇到过这个问题,而我的解决方案是#3中的这些代码:

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

当调用paintComponent()时,CanvasPanelView必须在此时被赋予大小,但是在调用getZoomFactor()时则不行。 paintComponent(),因此也就是setZoomFit(),显然是在getZoomFactor()之后。

如何在图片打开时正确显示图像的缩放级别?

1 个答案:

答案 0 :(得分:4)

基本上,你有一种竞争条件(尽可能多地在单线程中)。

正在发生的事情是您正在添加新视图,希望它能够立即布局。这不是Swing中的工作原理。向容器添加新组件时,会发出请求以更新层次结构中所有组件的布局,并布置所有已标记为无效的容器。在当前的调用周期完成且Event Dispatching Thread有时间处理所有请求之前,这种情况不会发生。

相反,您可以通过向事件调度线程的末尾添加请求来安排稍后查找。这可以确保您的请求将在EDT上的所有当前任务执行之前执行(可能还有其他人要遵循,但您已经挤进去了。)

以下示例说明了这一点。

它向JTabbedPane添加一个新面板,转储它的当前大小,使用SwingUtilities.invokeLater在将来一次请求回调并再次转储面板大小。您会发现第一个请求是0x0,第二个请求是有效值(取决于框架的大小和外观)

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


}