当前位置: 首页 > 知识库问答 >
问题:

在swing中在JTable中撤消

颛孙成益
2023-03-14
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.text.TabExpander;
import javax.swing.undo.*;


public class UndoTable
{
    public static void main(String[] args)
    {
        Object data[][] = {
            {"AMZN", "Amazon", 41.28, "BUY"},
            {"EBAY", "eBay", 41.57, "BUY"},
            {"GOOG", "Google", 388.33, "SELL"},
            {"MSFT", "Microsoft", 26.56, "SELL"},
            {"NOK", "Nokia Corp", 17.13, "BUY"},
            {"ORCL", "Oracle Corp.", 12.52, "BUY"},
            {"SUNW", "Sun Microsystems", 3.86, "BUY"},
            {"TWX",  "Time Warner", 17.66, "SELL"},
            {"VOD",  "Vodafone Group", 26.02, "SELL"},
            {"YHOO", "Yahoo!", 37.69, "BUY"}
        };
        String columns[] = {"Symbol", "Name", "Price", "Guidance"};

        final JvUndoableTableModel tableModel = new JvUndoableTableModel(data, columns);
       final JTable table = new JTable(tableModel);
        JScrollPane pane = new JScrollPane(table);

        JvUndoManager undoManager = new JvUndoManager();
        tableModel.addUndoableEditListener(undoManager);

        JMenu editMenu = new JMenu("Edit");

        Action addrowaction = new AbstractAction("Add Row") {
            private static final long serialVersionUID = 1433684360133156145L;


            public void actionPerformed(ActionEvent e) {
                tableModel.insertRow(table.getRowCount(), new Object[]{"YHOO", "Yahoo!", 37.69, "BUY"});


            }
        };
        editMenu.add(undoManager.getUndoAction());
        //editMenu.add(undoManager.getRedoAction());

        JMenuBar menuBar = new JMenuBar();
        menuBar.add(editMenu);
        editMenu.add(addrowaction);


        JFrame frame = new JFrame("Undoable JTable");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setJMenuBar(menuBar);
        frame.add(pane, BorderLayout.CENTER);
        frame.setSize(300, 150);
        frame.setLocation(200, 300);
        frame.setVisible(true);
    }
}


class JvUndoableTableModel extends DefaultTableModel
{
    public JvUndoableTableModel(Object[][] data, Object[] columnNames)
    {
        super(data, columnNames);
    }


    public Class getColumnClass(int column)
    {
        if (column >= 0 && column < getColumnCount())
            return getValueAt(0, column).getClass();

        return Object.class;
    }



    @Override
    public void setValueAt(Object value, int row, int column)
    {
        setValueAt(value, row, column, true);
    }


    public void setValueAt(Object value, int row, int column, boolean undoable)
    {
        UndoableEditListener listeners[] = getListeners(UndoableEditListener.class);
        if (undoable == false || listeners == null)
        {
            super.setValueAt(value, row, column);
            return;
        }


        Object oldValue = getValueAt(row, column);
        super.setValueAt(value, row, column);

        JvCellEdit cellEdit = new JvCellEdit(this, oldValue, value, row, column);
        UndoableEditEvent editEvent = new UndoableEditEvent(this, cellEdit);
        for (UndoableEditListener listener : listeners)
            listener.undoableEditHappened(editEvent);

    }

    //adding new cell to the table
    public void insertRow(int row, Object[] rowData){
        insertRow(row, rowData, true);
    }

    public void insertRow(int row,
            Object[] rowData,boolean undoable){
        UndoableEditListener listeners[] = getListeners(UndoableEditListener.class);
        if (undoable == false || listeners == null)
        {
            super.insertRow(row, rowData);
            return;
        }

        super.insertRow(row, rowData);
        JvCellNew cellNew = new JvCellNew(this, rowData, row);

        UndoableEditEvent editEvent = new UndoableEditEvent(this, cellNew);
        for (UndoableEditListener listener : listeners)
            listener.undoableEditHappened(editEvent);

    }


    //removing row from the table
    public void removeRow(int row){
        removeRow(row, true);
    }
    public void removeRow(int row, boolean undoable){
        UndoableEditListener listeners[] = getListeners(UndoableEditListener.class);
        if (undoable == false || listeners == null)
        {
            super.removeRow(row);
            return;
        }
        super.removeRow(row);
        JvCellNew cellNew = new JvCellNew(this, row);
        UndoableEditEvent editEvent = new UndoableEditEvent(this, cellNew);
        for (UndoableEditListener listener : listeners)
            listener.undoableEditHappened(editEvent);

    }


    public void addUndoableEditListener(UndoableEditListener listener)
    {
        listenerList.add(UndoableEditListener.class, listener);
    }
}


class JvCellEdit extends AbstractUndoableEdit
{
    protected JvUndoableTableModel tableModel;
    protected Object oldValue;
    protected Object newValue;
    protected int row;
    protected int column;


    public JvCellEdit(JvUndoableTableModel tableModel, Object oldValue, Object newValue, int row, int column)
    {
        this.tableModel = tableModel;
        this.oldValue = oldValue;
        this.newValue = newValue;
        this.row = row;
        this.column = column;
    }


    @Override
    public String getPresentationName()
    {
        return "Cell Edit";
    }


    @Override
    public void undo() throws CannotUndoException
    {
        super.undo();

        tableModel.setValueAt(oldValue, row, column, false);
    }
}
class JvCellNew extends AbstractUndoableEdit
{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    protected JvUndoableTableModel tableModel;
    protected Object[] rowData;
    protected int row;

    public JvCellNew(JvUndoableTableModel tableModel, Object[] rowData, int row)
    {
        this.tableModel = tableModel;        
        this.rowData = rowData;
        this.row = row;

    }
    public JvCellNew(JvUndoableTableModel tableModel, int row)
    {
        this.tableModel = tableModel;        
        this.row = row;

    }
    @Override
    public String getPresentationName()
    {
        return "Cell New";
    }
    public void undo() throws CannotUndoException
    {
        super.undo();
        tableModel.removeRow(row);

    }
}


class JvUndoManager extends UndoManager
{
    protected Action undoAction;
   // protected Action redoAction;


    public JvUndoManager()
    {
        this.undoAction = new JvUndoAction(this);
        synchronizeActions();           // to set initial names
    }


    public Action getUndoAction()
    {
        return undoAction;
    }



    @Override
    public boolean addEdit(UndoableEdit anEdit)
    {
        try
        {
            return super.addEdit(anEdit);
        }
        finally
        {
            synchronizeActions();
        }
    }


    @Override
    protected void undoTo(UndoableEdit edit) throws CannotUndoException
    {
        try
        {
            super.undoTo(edit);
        }
        finally
        {
            synchronizeActions();
        }
    }


    protected void synchronizeActions()
    {
        undoAction.setEnabled(canUndo());
        undoAction.putValue(Action.NAME, getUndoPresentationName());
    }
}


class JvUndoAction extends AbstractAction
{
    protected final UndoManager manager;


    public JvUndoAction(UndoManager manager)
    {
        this.manager = manager;
    }


    public void actionPerformed(ActionEvent e)
    {
        try
        {
            manager.undo();
        }
        catch (CannotUndoException ex)
        {
            ex.printStackTrace();
        }
    }
}

共有1个答案

董嘉祯
2023-03-14

问题似乎与这样一个事实有关:撤消的执行导致一个动作再次被存储为可撤消的动作。(由于移除一行会创建一个新的jvcellnew,根据名称,它可能表明添加了一个新行,这一点特别令人困惑)

可以通过指定已撤消的操作不能再次撤消来解决“症状”:

class JvCellNew
{
    ....
    public void undo() throws CannotUndoException
    {
        super.undo();

        // Pass in "false" as the second argument here, to indicate
        // that this row removal should NOT cause an undoable edit
        tableModel.removeRow(row, false);
    }
}

在打印一些调试信息时,可以更容易地找到类似的内容,例如

class JvCellNew extends AbstractUndoableEdit
{
    ....
    @Override
    public String getPresentationName()
    {
        return "Cell New "+row;  // Print the row number
    }

    // Provide a useful toString implementation
    @Override
    public String toString()
    {
        return getPresentationName();
    }
}


class JvUndoManager extends UndoManager
{
    ....

    @Override
    public boolean addEdit(UndoableEdit anEdit)
    {
        try
        {
            boolean b = super.addEdit(anEdit);

            // Print the current state of this manager 
            System.out.println("After adding "+anEdit);
            for (UndoableEdit e : this.edits)
            {
                System.out.println(e);
            }
            return b;

        }
        finally
        {
            synchronizeActions();
        }


    }


    @Override
    protected void undoTo(UndoableEdit edit) throws CannotUndoException
    {
        try
        {
            super.undoTo(edit);

            // Print the current state of this manager 
            System.out.println("After undo to "+edit);
            for (UndoableEdit e : this.edits)
            {
                System.out.println(e);
            }

        }
        finally
        {
            synchronizeActions();
        }
    }
}
 类似资料:
  • 我对这个很陌生,所以也许有什么我错过了,或者只是不知道。

  • 我已经学会了如何在帧中显示JTable,但我不知道如何实际更改数据。我已经读了很多关于这个主题的教程,但似乎没有什么是合适的。你能回答一些关于下面代码的问题吗? 1)在actionListener中,我调用tab.getModel()。getValueAt(1,1)和tab.getValueAt(1,1)。我得到相同的数据,“佩蒂”如果“getModel()”提供相同的数据,它是必要的吗? 我认为

  • 我有一个Jtable,我在其中添加了这样的JComobox。 我像这样添加了一个jtable的鼠标事件。 但是当我点击我添加Jcombobox的单元格时,它并没有给出该行和列的放置。我仍然在组合框点击事件中调用了表的点击事件,但它给出了所有时间行0,甚至列0在这里的屏幕截图。 那么,我如何解决它,这样我就可以有行和列?

  • 问题内容: 我想做的事: 我想列出数据库的一些记录。此列表应显示在 JFrame弹出窗口中。 描述: 我有3节课: Main.java(运行程序) PeopleTableModel.java(保存数据,扩展AbstractTableModel) PeopleTable.java(保存逻辑,扩展JTable) 将JFrame设置为 可见时,为什么会出现ArrayIndexOutOfBoundsExc

  • 我创建了一个表单,其中添加了一个,它有3列。第二列和第三列有编辑器。 我希望当我们选择第二列组合框的第一项时,第三列组合框的第一个组合框也应该被选择,反之亦然。 我该怎么做?

  • 问题内容: 我想在第1列的JTable(3,3)内添加JComboBox。但是在第1列中,每一行都有其自己的ComboBox元素集。当我尝试使用 每行都设置为同一组ComboBox值。但是我希望每一行ComboBox都有不同的项目。 问题答案: java2s.com上的示例看起来可以正常工作,然后再进行示例(例如,我将JComboBoxes编码为快速示例,并为今天的Swing添加/更改) 只需添加