JTable没有更新,调用setValueAt方法似乎不起作用

时间:2013-11-19 22:38:11

标签: java swing jtable

我正在创建一个数独游戏,我在使用JTables时遇到了一些麻烦...... 我只是无法让它触发事件,出于某种原因,即使从主类调用setValueAt也没有任何反应。它在模型本身内部工作时确实有用...... 正如你所看到的,我已经尝试了一个tableModelListener,但这也不起作用。

总结一下我的问题:为什么我的表没有触发事件而且setValuesAt方法没有做任何事情?

abstractModel:

import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.table.AbstractTableModel;

class SudokuTableModel extends AbstractTableModel
    {
        private int[][] data;
        private int[][] originalBoard;

        /**
         * 
         * @param board the board to be played with
         */


        public SudokuTableModel(int[][] board)
        {
            data = board;
            originalBoard = board;



        }

        @Override
        public int getColumnCount() 
        {
            return 9;
        }


        @Override
        public int getRowCount() {
            // this
            return 9;
        }

        @Override
        public boolean isCellEditable(int row, int col)
        {
            System.out.println("Is it editable?");
                if(originalBoard[row][col]<0) //if the value is -1 -> it is not one of the hints and thus can be edited
                    //it has to be checked with the original board because the user might want to change something they did
                    return true;
            return false;

        }

        /**
         * @return the value at row, col
         */
        @Override
        public Object getValueAt(int arg0, int arg1) 
        {//if its a "sudoku" number, return it, otherwise return null
            //^thta doesn't seem to work so we'll just return the value. With the size of the grid, number that is not exactly 1 char will be displayed as 3 dots so its fine
            return (data[arg0][arg1]<0)?-1:data[arg0][arg1]; 
        }

        /**
         * 
         * @param value changes to this value @
         * @param row
         * @param col
         */
        public boolean setValueAt(int value, int row, int col, int randomValue)
        {
            originalBoard[row][col]=value;
            System.out.println("Setting value");
            fireTableCellUpdated(row, col);
            return true;

        }

         public Class getColumnClass(int c) {
                return getValueAt(0, c).getClass();
            }

    }

主要代码:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.*;

import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.*;
import javax.swing.border.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;





/**
 * @Program Sudoku
 * 
 * @author Tomas Svitil
 * @date November 2013
 * @school CTU
 * @hardware MacBook Pro 17", mid 2010, i7, 8GiB RAM
 * @IDE eclipse SDK 4.3.1
 * @purpose this is the main playing board. Options such as save and load will be handled by a helper class -SudokuTable Helper
 *
 */

public class SudokuTablePreRenderer extends JFrame implements TableModelListener
{


      JTable table;
        int[][] board;



    /**
     * 
     * @param toBeUsed the board to be used
     * @param isSolution if true the 'close' button just disposes the window
     */
    public SudokuTablePreRenderer(int[][] toBeUsed,boolean isSolution) 
    {

        //lets use our sudoku model
        SudokuTableModel model = new SudokuTableModel(toBeUsed);
        //make a copy of the passed 
        board=toBeUsed;
        table = new JTable( model )
        {
            public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
            {
                Component c = super.prepareRenderer(renderer, row, column);
                JComponent jc = (JComponent)c;
                if(!isRowSelected(row))
                {
                    c.setBackground(toBeGray(row,column) ? Color.WHITE : Color.LIGHT_GRAY);
                    boolean top = top(row);
                    boolean left = left(column);
                    boolean bottom = bottom(row);
                    boolean right = right(column);
                    jc.setBorder(new MatteBorder(top?1:0,left?1:0,bottom?1:0,right?1:0, Color.BLACK));
                }
                return c;
            }
            //each returns true if the cell should have a *method name* border
            private boolean top(int row)
            {
                if(row==0||row==3||row==6)
                    return true;

                return false;
            }

            private boolean left(int col)
            {
                if(col==0||col==3||col==6)
                    return true;
                return false;
            }
            private boolean bottom(int row)
            {
                if(row==8)
                    return true;

                return false;
            }
            private boolean right(int col)
            {
                if(col==8)
                    return true;
                return false;
            }

            //returns true if cell should be shaded in gray
            private boolean toBeGray(int row, int col)
            {
                ArrayList<Integer> SetA = new ArrayList<Integer>();
                ArrayList<Integer> SetB = new ArrayList<Integer>();
                int[] a = {0,1,2,6,7,8};
                int[] b = {3,4,5};

                for(int i=0;i<a.length;i++ )
                    SetA.add(a[i]);
                for(int i=0;i<b.length;i++)
                    SetB.add(b[i]);


                if((SetA.contains(row)&&SetA.contains(col))||(SetB.contains(row)&&SetB.contains(col)))
                        return true;                    
                return false;

            }
        };

        //we don't need the table header
        table.setTableHeader(null);
        //set the base GOOEY stuff
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        table.changeSelection(0, 0, false, false);
        JScrollPane scrollPane = new JScrollPane( table );
        getContentPane().add( scrollPane );

        //we're going to store only single digits, so the size we want is exactly one digit
        table.getColumnModel().getColumn(0).setMaxWidth(15);
        table.getColumnModel().getColumn(1).setMaxWidth(15);
        table.getColumnModel().getColumn(2).setMaxWidth(15);
        table.getColumnModel().getColumn(3).setMaxWidth(15);
        table.getColumnModel().getColumn(4).setMaxWidth(15);
        table.getColumnModel().getColumn(5).setMaxWidth(15);
        table.getColumnModel().getColumn(6).setMaxWidth(15);
        table.getColumnModel().getColumn(7).setMaxWidth(15);
        table.getColumnModel().getColumn(8).setMaxWidth(15);

        //if this table is used to display the result, "closing" the window will just dispose it, and not quit the program
        if(isSolution)
            setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        else setDefaultCloseOperation( EXIT_ON_CLOSE );
        pack();

        //put it somewhere nice
        setLocationRelativeTo( null );
        //set the size so that its only the size of the 
        setSize(143,176);
        //and we want it at one size only
        setResizable(false);
        setVisible(true);
        table.getModel().addTableModelListener(this);
         TableModelListener tableModelListener = new TableModelListener()
           {

            @Override
            public void tableChanged(TableModelEvent e) 
            {
                if(e.getType()==TableModelEvent.UPDATE)
                {
                    System.out.println("YA?");
                }
            }

           };


    }

   @Override
    public void tableChanged(TableModelEvent e) 
    {
        int row = e.getFirstRow();
        int column = e.getColumn();
        TableModel model = (TableModel)e.getSource();
        String columnName = model.getColumnName(column);
        Object data = model.getValueAt(row, column);
        table.setValueAt(4, row, column);
        System.out.println("Something happened yay");
        // Do something with the data...
    }


//    
    /**
     * 
     * @return a copy of the board 
     */
   public int[][] getBoard()
   {
       int[][] returnee = new int[9][9];
       for(int i = 0; i < board.length; i++)
                returnee[i] = board[i].clone();
       return returnee;
   }

   /**
    * @return reference to the "real" board
    * @WARNING - By manipulating the array from this method you're manipulating the methods array itself! IF NOT SURE USE THE GetBoard METHOD!
    * 
    */
   public int[][] getRealBoard()
   {
    return board;   
   }

   //------debugging---------------------------
   private void setValue()
   {
      System.out.println(table.getValueAt(3,4));
   }

   public void doStuffs()
   {
       System.out.println(table.isCellEditable(2,2));
   }

   //----------main just for debugging----------
    public static void main(String[] args)
    {

        int[][] hi = new int[9][9];
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
                hi[i][j]=-1;
        hi[3][3]=0;
        SudokuTablePreRenderer frame = new SudokuTablePreRenderer(hi,false);
        frame.setValue();
        frame.doStuffs();
    }



}

1 个答案:

答案 0 :(得分:2)

  • 由于某种原因,您的模型中有两个二维int数组,data和originalBoard。
  • 第一个数组,数据,您通过getValueAt(...)
  • 显示JTable中的信息
  • 第二个数组originalBoard,您可以通过setValueAt(...)向模型添加数据。
  • 这种差异意味着向模型中添加数据不会对JTable中显示的数据产生任何影响,这会引发问题 - 为什么您的模型以这种方式设置?

你说,

  

总结一下我的问题,为什么我的桌子不会触发事件而且不能设置ValuesAt。

我敢打赌,表事件实际上已被触发,但由于数据数组保存的数据永远不会改变,因此JTable永远不会改变其显示。

如果要添加新数据以更新显示,则获取数据的数组应与显示数据的数组相同。至少这似乎对我来说最有意义。


修改

关于:

  可悲的是,我认为不是这样的。这个设计是我在发现数组只是'引用'之前所做的,所以实际上两个数组应该是同一个。另一个问题是我将一个System.out.print放入setValueAt,当我从模型内部调用它(从外部调用get valueAt,并调用setValueAT)时,它工作得很好,它设置了值,它甚至被触发当我从外部调用该方法虽然它不起作用

你是对的,对不起。我撤回上面的答案。

然而,另一个潜在的问题是:你的setValueAt方法不是真正的覆盖,永远不会被调用,你调用的实际AbstractTableModel setValueAt方法永远不会被覆盖,也不会有效。

删除TableModelListener,并将setValueAt更改为:

@Override
public void setValueAt(Object value, int row, int col) {
  originalBoard[row][col] = ((Integer) value).intValue();
  System.out.println("Setting value");
  fireTableCellUpdated(row, col);
  // return true;
}