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()被调用时,当前CanvasPanelView不能有大小,因为它返回0. 我之前遇到过这个问题,我的解决方案是使用 #3 中的这些代码行:

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

当调用paintComponent() 时,CanvasPanelView必须已经给定了尺寸,但在调用getZoomFactor() 时没有。paintComponent(),因此还有 setZoomFit(),显然在 getZoomFactor() 之后。

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

4

1 回答 1

4

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

正在发生的事情是您正在添加新视图,并期望它立即布局。这不是 Swing 中的工作方式。当您向容器添加新组件时,系统会请求更新层次结构中所有组件的布局,并对所有标记为无效的容器进行布局。在当前调用周期完成并且事件调度线程有时间处理所有请求之前,这不会发生。

相反,您可以通过将请求添加到事件调度线程的末尾来安排稍后的查找。这确保了您的请求将在 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);
            }
        });
    }


}
于 2013-05-19T05:21:27.187 回答