在MVC模型的Swing中使用撤消/重做? [英] using undo/redo in Swing for an MVC model?

查看:97
本文介绍了在MVC模型的Swing中使用撤消/重做?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个MVC模型,我正在尝试向其添加撤消/重做功能. 用户可以在JTextField中放置一个数字,当他们单击UNDO按钮时,应该将其删除. 我已经为实现此目标的类提供了代码.我得到的错误在底部.

I have an MVC model,and Im trying to add an undo/redo feature to it. User can place a number in a JTextField, and when they click the UNDO button, it should be erased. I have provided the code for my classes that implement this. The error I get is at the bottom.

控制包:

程序包控制;

/** *此类将控制GUI的按钮动作.它实现actionListener()方法 *,并根据所单击的按钮来初始化 *模型类中的相应组件. * */

/** * This class will control the button actions of the GUI.It implements the actionListener() method * and based on the button that was clicked, it initializes the * corresponding component in the model class. * */

public class ButtonGUIControl implements ActionListener{
private SudokuModel model;
private ButtonGUI bgui;
final UndoManager manager = new UndoManager();



public ButtonGUIControl(SudokuModel model) {
    this.model = model;
}

/*This method will listen for user events, and act accordingly
 * */

public void actionPerformed(ActionEvent e) {
    try {   
         if(e.getActionCommand().equals("Check My Answer!")){

            model.checkGame();
        }


         else if (e.getActionCommand().equals("Undo")){

             try {

                    manager.undo();
                } catch (CannotUndoException ex) { ex.printStackTrace(); }
                finally {
                    //updateButtons();
                }                   
         }
         else if (e.getActionCommand().equals("Redo")){

             manager.redo();
             System.out.println("e.getActionCommand().equals redo");
         }

        //otherwise, it simply places the selected number in the grid
        else{

            model.setNumber(Integer.parseInt(e.getActionCommand()));
        }

    } catch (NumberFormatException e1) {}

    catch (IOException e1) {}
    catch (CannotUndoException ex) {
        System.out.println("Unable to undo: " + ex);
        ex.printStackTrace();
        }
    catch (CannotRedoException ex) {
        System.out.println("Unable to redo: " + ex);
        ex.printStackTrace();
    }    

}

public void undoableEditHappened(UndoableEditEvent evt) {

    manager.addEdit(evt.getEdit());

    //bgui.updateButtons();

}

}

在视图包中: ButtonGUI.java

In the view package: ButtonGUI.java

我在按钮上添加了一个actionListner:

I add an actionListner to the buttons:

RedoBttn.addActionListener(buttonController);

RedoBttn.addActionListener(buttonController);

UndoBttn.addActionListener(buttonController);

UndoBttn.addActionListener(buttonController);

在Grid.java中,它扩展了JTextField:

In the Grid.java, which extends the JTextField:

public class Grid extends JTextField {
private int x;       
private int y; 

final UndoManager manager = new UndoManager();


public Grid(int x, int y) {
    super("");
    this.x = x;
    this.y = y;
    getDocument().addUndoableEditListener(manager);



    setPreferredSize(new Dimension(40, 40));
    setBorder(BorderFactory.createLineBorder(Color.GREEN));
    setOpaque(true);
}


public void setNumber(int number, boolean userInput)  {


    if(number > 0 & !userInput){
        setText(""+number);
        setEditable(false);


    }

    //These set of numbers are the only ones that the user can undo/redo
    else if (number > 0 & userInput){
        setText(""+number);
        setEditable(true);
}
    else
    setText("");


我还为视图包中另一个类的每个JTextField添加了一个鼠标侦听器. 所以我认为我具有撤消/重做结构的权利. 当我运行程序时,我可以选择一个数字并将其放置在JTextField(grid)中,但是当我按下撤消"时,我会得到以下异常:


I also added a mouse listenr to each of the JTextFields in another class in the view package. So I think I have the undo/redo structure right. When I run the program, I can select a number and place it in a JTextField(grid), but as soon as I hit "undo" I get the following exception:

    javax.swing.undo.CannotUndoException
at javax.swing.undo.UndoManager.undo(UndoManager.java:411)
at control.ButtonGUIControl.actionPerformed(ButtonGUIControl.java:76)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6505)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
at java.awt.Component.processEvent(Component.java:6270)
at java.awt.Container.processEvent(Container.java:2229)
at java.awt.Component.dispatchEventImpl(Component.java:4861)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
at java.awt.Container.dispatchEventImpl(Container.java:2273)
at java.awt.Window.dispatchEventImpl(Window.java:2713)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:707)
at java.awt.EventQueue.access$000(EventQueue.java:101)
at java.awt.EventQueue$3.run(EventQueue.java:666)
at java.awt.EventQueue$3.run(EventQueue.java:664)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:680)
at java.awt.EventQueue$4.run(EventQueue.java:678)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:677)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

第76行是我打电话给的地方

and line 76 is where I call:

    manager.undo() 

在try/catch块中.

in a try/catch block.

有什么想法吗?是我的撤消/重做实现还是其他?

Any idea whats wrong? Is it my undo/redo implementation or something else?

谢谢!

推荐答案

尝试像这样包装manager.undo();:

if(manager.canUndo())
    manager.undo();

我怀疑JTextField的默认UndoListener实现不会添加系统更新(即,将setText(""+number);调用到撤消队列)-仅从UI更新.

I suspect the default UndoListener implementation of JTextField doesn't add system updates (ie. calling setText(""+number); to the undo queue) - only updates from the UI.

编辑

做完一些测试后,setText("")函数似乎确实在UndoManager中添加了撤消功能,所以这不是您遇到的问题.因此,您可以通过确保有任何可撤消的操作来撤消来避免错误.但是,如果您在UndoManager中没有执行任何可撤消的操作,则问题可能出在代码的其他地方.

After doing some testing, it seems that the setText("") function does add undos to the UndoManager, so that's not the problem you're running into. So you can prevent the error by making sure there's any undo-able actions to undo; But if you're not getting any undo-able actions in your UndoManager, the problem is probably happening somewhere else in the code.

这篇关于在MVC模型的Swing中使用撤消/重做?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆