我正在创建一个数独游戏,我在使用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();
}
}
答案 0 :(得分:2)
getValueAt(...)
setValueAt(...)
向模型添加数据。你说,
总结一下我的问题,为什么我的桌子不会触发事件而且不能设置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;
}