I have a JTable on which I show some info and color backgrounds accordingly. I am however having problems whenever data is changed, the table does't update it's color. Looking trough SO I found several questions saying these examples should work:
table.revalidate();
or
((CustomTableModel)table.getModel()).fireTableDataChanged();
or
table.repaint();
or
tableModel.fireTableCellUpdated(row, col);
I've tried these methods inside the tableModel, in the JPanel class holding the table itself and even inside the tablerenderer but nothing seems to work (the table doesn't change a bit)
I've checked if the data received when updating the table changes and it does but the table itself doesn't update. It only does when I restart the application.
I have tried making a Minimal, Complete, and Verifiable example just by copying the code but before I could make it work in the same way it had become way to long and complicated for anyone to understand...
Therefor I decided to upload the entire project to github but you may be able to find the error in these classes here:
package Interface;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.StringTokenizer;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import DataBase.Booking;
import DataBase.Room;
import Logics.Globals;
public class TablePanel extends JPanel{
private static TablePanel MainLogicInctance;
private JTable table;
private CustomTableModel model;
private JPopupMenu popup;
private JMenuItem view;
private JMenuItem confirm;
private JMenuItem unconfirm;
private JMenuItem edit;
private JMenuItem delete;
int x=0,y=0;
public TablePanel(){
model = new CustomTableModel(getObjectArray(), 0);
popup = new JPopupMenu();
view = new JMenuItem("view");
confirm = new JMenuItem("confirm");
unconfirm = new JMenuItem("unconfirm");
edit = new JMenuItem("edit");
delete = new JMenuItem("delete");
popup.add(view);
popup.add(confirm);
popup.add(unconfirm);
popup.add(new JPopupMenu.Separator());
popup.add(edit);
popup.add(delete);
this.setLayout(new BorderLayout());
this.setBackground(new Color(255,255,255));
table = new JTable(model);
MouseAdapter adapter = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if(e.getSource() != view && e.getSource() != confirm && e.getSource() != unconfirm && e.getSource() != edit && e.getSource() != delete){
x=table.rowAtPoint(e.getPoint());
y=table.columnAtPoint(e.getPoint());
System.out.println(Integer.toString(x)+"|"+Integer.toString(y));
}
if(e.getSource() == view){
Booking booking = Globals.getBookingByDateAndRoom(x, y);
System.out.println(Integer.toString(x)+"|"+Integer.toString(y));
System.out.println(booking.toString());
if(booking!=null){
JFrame frame = new PopupFrame("view",booking);
}
}
if(e.getSource() == confirm){
Booking booking = Globals.getBookingByDateAndRoom(x, y);
System.out.println(Integer.toString(x)+"|"+Integer.toString(y));
if(booking!=null){
Globals.updateBooking(booking.getName(), booking.getSurname(), booking.getPersons(), booking.getBegin(), booking.getEnd(), booking.getRoomID(), booking.getId(), true);
TablePanel.getInctance().updateAll();
}
}
if(e.getSource() == unconfirm){
Booking booking = Globals.getBookingByDateAndRoom(x, y);
if(booking!=null){
Globals.updateBooking(booking.getName(), booking.getSurname(), booking.getPersons(), booking.getBegin(), booking.getEnd(), booking.getRoomID(), booking.getId(), false);
TablePanel.getInctance().updateAll();
}
}
if(e.getSource() == edit){
Booking booking = Globals.getBookingByDateAndRoom(x, y);
if(booking!=null){
JFrame frame = new PopupFrame("edit booking",booking);
TablePanel.getInctance().updateAll();
}
}
if(e.getSource() == delete){
Booking booking = Globals.getBookingByDateAndRoom(x, y);
if(booking!=null){
JFrame frame = new PopupFrame("delete booking",booking);
TablePanel.getInctance().updateAll();
}
}
}
};
table.addMouseListener(adapter);
view.addMouseListener(adapter);
confirm.addMouseListener(adapter);
unconfirm.addMouseListener(adapter);
edit.addMouseListener(adapter);
delete.addMouseListener(adapter);
table.setComponentPopupMenu(popup);
table.setEnabled(false);
table.getColumnModel().setColumnSelectionAllowed(true);
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.getTableHeader().setReorderingAllowed(false);
table.getTableHeader().setResizingAllowed(false);
table.getColumnModel().getColumn(0).setMinWidth(0);
table.getColumnModel().getColumn(0).setMaxWidth(0);
table.getColumnModel().getColumn(0).setWidth(0);
this.add(table.getTableHeader(), BorderLayout.NORTH);
this.setAllColoumnsRenderer();
this.add(table,BorderLayout.CENTER);
}
private void setAllColoumnsRenderer(){
for(int i=0; i<368;i++){
table.getColumnModel().getColumn(i).setCellRenderer(new CustomRenderer());
}
}
private Object[] getObjectArray() {
try {
BufferedReader reader = new BufferedReader(new FileReader("Recources/TableData/HeaderData.txt"));
String s;
s = reader.readLine();
StringTokenizer str = new StringTokenizer(s,",");
String tmp;
int i=0;
Object[] resault = new Object[368];
while(str.hasMoreTokens() && i<368){
tmp=str.nextToken();
if(!tmp.isEmpty()){
resault[i]=tmp;
}else{
resault[i]=" - ";
}
i++;
}
return resault;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private Object[] getRoomObjectArray(String room,int roomId) {
Object[] resault = new Object[549];
resault[0]=roomId;
resault[1]=room;
return resault;
}
public void addRoom(String roomname,int roomId){
this.remove(table);
((CustomTableModel) model).addRow(getRoomObjectArray(roomname,roomId));
table = new JTable(model);
((CustomTableModel) model).fireTableRowsInserted(0, ((CustomTableModel)model).getRowCount());
this.add(table);
this.revalidate();
this.repaint();
}
public static TablePanel getInctance() {
if (MainLogicInctance == null)
MainLogicInctance = new TablePanel();
return MainLogicInctance;
}
public JTable getTable(){
return table;
}
public void updateAll() {
System.out.println("forceUpdateRunning");
int rowCount = model.getRowCount();
for (int i = rowCount - 1; i >= 0; i--) {
((CustomTableModel) model).removeRow(i);
}
Room rooms[] = Globals.displayAllRooms();
for(Room room : rooms){
this.addRoom(room.getName(),room.getRoomId());
}
Booking bookings[] = Globals.displayAllBookings();
for(Booking booking : bookings){
this.addBooking(booking);
}
System.out.println("Time To Update!! :)");
table.revalidate();
((CustomTableModel)table.getModel()).fireTableDataChanged();
table.repaint();
}
public void addBooking(Booking booking){
int begin=0,end=0,current;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate currentDate = LocalDate.parse(booking.getBegin(), formatter);
try {
begin = getDateNumber(booking.getBegin())+2;
end = getDateNumber(booking.getEnd())+2;
current = begin;
while(booking.getRoomID()>=model.getRowCount())
booking.setRoomID(booking.getRoomID()-1);
while(current<=end){
if(Globals.YEAR==currentDate.getYear()){
if(current == begin){
setCell(current,booking.getRoomID(),booking.getName());
}
if(current-1 == begin){
setCell(current,booking.getRoomID(),booking.getSurname());
}
}
currentDate.plusDays(1);
current++;
}
} catch (ParseException e) {
e.printStackTrace();
}
}
public int getDateNumber(String dateString) throws ParseException{
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate date = LocalDate.parse(dateString, formatter);
return date.getDayOfYear();
}
public int getYear(String dateString){
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate date = LocalDate.parse(dateString, formatter);
return date.getYear();
}
public void setCell(int x,int y,String name){
model.setValueAt(name, y, x);
}
}
CustomTableModel:
package Interface;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import javax.swing.table.DefaultTableModel;
import DataBase.Booking;
import Logics.Globals;
public class CustomTableModel extends DefaultTableModel{
private Booking[] bookings;
public CustomTableModel(Object[] data, int i){
super(data,i);
bookings = Globals.displayAllBookings();
}
public int getStatus(int row, int col) {
for(Booking booking : bookings){
System.out.println(booking.toString());
int begin=0,end=0,current;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate currentDate = LocalDate.parse(booking.getBegin(), formatter);
try {
begin = getDateNumber(booking.getBegin())+2;
end = getDateNumber(booking.getEnd())+2;
current = begin;
while(booking.getRoomID()>=super.getRowCount())
booking.setRoomID(booking.getRoomID()-1);
while(current<=end){
if(Globals.YEAR==currentDate.getYear()){
if(current == col && booking.getRoomID() == row){
if(booking.isConfirmed())
return booking.getPersons();
return booking.getPersons()+10;
}
}
currentDate.plusDays(1);
current++;
}
} catch (ParseException e) {
e.printStackTrace();
}
}
return 0;
}
public int getDateNumber(String dateString) throws ParseException{
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate date = LocalDate.parse(dateString, formatter);
return date.getDayOfYear();
}
public boolean isCellEditable(int rowIndex, int columnIndex){
return false;
}
}
CustomRenderer:
package Interface;
import java.awt.Color;
import java.awt.Component;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
public class CustomRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
CustomTableModel tableModel = (CustomTableModel) table.getModel();
//====================Confirmed================
if (tableModel.getStatus(row,col) == 1) {
l.setBackground(new Color(255, 128, 128));
} else if (tableModel.getStatus(row,col) == 2) {
l.setBackground(new Color(255, 102, 102));
} else if (tableModel.getStatus(row,col) == 3) {
l.setBackground(new Color(255, 77, 77));
} else if (tableModel.getStatus(row,col) == 4) {
l.setBackground(new Color(255, 51, 51));
} else if (tableModel.getStatus(row,col) == 5) {
l.setBackground(new Color(255, 26, 26));
} else if (tableModel.getStatus(row,col) == 6) {
l.setBackground(new Color(255, 0, 0));
} else if (tableModel.getStatus(row,col) == 7) {
l.setBackground(new Color(230, 0, 0));
} else if (tableModel.getStatus(row,col) == 8) {
l.setBackground(new Color(204, 0, 0));
//===================Not Confirmed=============
} else if (tableModel.getStatus(row,col) == 11) {
l.setBackground(new Color(255, 204, 128));
} else if (tableModel.getStatus(row,col) == 12) {
l.setBackground(new Color(255, 194, 102));
} else if (tableModel.getStatus(row,col) == 13) {
l.setBackground(new Color(255, 184, 77));
} else if (tableModel.getStatus(row,col) == 14) {
l.setBackground(new Color(255, 173, 51));
} else if (tableModel.getStatus(row,col) == 15) {
l.setBackground(new Color(255, 163, 26));
} else if (tableModel.getStatus(row,col) == 16) {
l.setBackground(new Color(255, 153, 0));
} else if (tableModel.getStatus(row,col) == 17) {
l.setBackground(new Color(230, 138, 0));
} else if (tableModel.getStatus(row,col) == 18) {
l.setBackground(new Color(204, 122, 0));
//=====================empty===================
} else if(col>1){
l.setBackground(new Color(102, 255, 51));
}
return l;
}
}
As of this version of the software I'm trying to update the table from the TablePanel class. but I've tried it in all 3 of these classes.
Here is a video of it's behavior. I hope I've explained the problem enough and you know the solution?
答案 0 :(得分:2)
DefaultTableCellRenderer.getTableCellRendererComponent
将参数视为索引。您将继续执行以使用这些索引来检索模型中的值。您需要先使用JTable.convertRowIndexToModel
和JTable.convertColumnIndexToModel
转换这些索引。然后使用转换后的索引检索模型中的值。
答案 1 :(得分:2)
看起来你没有打电话给super.setValueAt()
。这是一个有效的例子:
public class BookingColorChange {
private static final class AbstractActionExtension extends AbstractAction {
private final JTable table;
private final BookingState newState;
private AbstractActionExtension(String name, JTable table, BookingState newState) {
super(name);
this.table = table;
this.newState = newState;
}
@Override
public void actionPerformed(ActionEvent e) {
int[] selectedColumns = table.getSelectedColumns();
for (int column : selectedColumns) {
int[] selectedRows = table.getSelectedRows();
for (int row : selectedRows) {
if (table.isCellSelected(row, column))
table.setValueAt(newState, row, column);
}
}
table.clearSelection();
}
}
enum BookingState {
FREE {
@Override
Color getColor() {
return Color.GREEN;
}
},
RESERVED {
@Override
Color getColor() {
return Color.ORANGE;
}
},
BOOCKED {
@Override
Color getColor() {
return Color.RED;
}
};
abstract Color getColor();
}
class Boocking {
private BookingState bookingState = BookingState.FREE;
private final Date date;
private final int roomNumber;
public Boocking(Date date, int roomNumber) {
super();
this.date = date;
this.roomNumber = roomNumber;
}
public BookingState getBookingState() {
return bookingState;
}
public void setBookingState(BookingState bookingState) {
this.bookingState = bookingState;
}
public Date getDate() {
return date;
}
public int getRoomNumber() {
return roomNumber;
}
}
public static void main(String[] args) {
final TableModel tableModel = new DefaultTableModel(30, 15) {
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.");
Calendar c = Calendar.getInstance();
@Override
public String getColumnName(int column) {
c.setTime(new Date());
c.add(Calendar.DATE, column);
return sdf.format(c.getTime());
}
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
@Override
public Class<?> getColumnClass(int column) {
return BookingState.class;
}
@Override
public Object getValueAt(int row, int column) {
Object valueAt = super.getValueAt(row, column);
if (null == valueAt) {
int roomNumber = row + 1;
c.setTime(new Date());
c.add(Calendar.DATE, column);
Object dbEntry = fetchEntryFromDataBase(roomNumber, new java.sql.Date(c.getTime().getTime()));
valueAt = translateDbValueToBookingState(dbEntry);
super.setValueAt(valueAt, row, column);
}
return null == valueAt ? BookingState.FREE : valueAt;
}
private BookingState translateDbValueToBookingState(Object dbEntry) {
return null;
}
private Object fetchEntryFromDataBase(int roomNumber, java.sql.Date date) {
// TODO Auto-generated method stub
return null;
}
@Override
public void setValueAt(Object value, int row, int column) {
super.setValueAt(value, row, column);
// update your database here
}
};
TableCellRenderer renderer = new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
Component rendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
row, column);
Color color = ((BookingState) value).getColor();
if (isSelected)
color = color.darker();
rendererComponent.setBackground(color);
((JComponent) rendererComponent).setToolTipText(
"Room " + (row + 1) + " " + table.getModel().getColumnName(column) + " " + value);
return rendererComponent;
}
};
JComboBox<BookingState> comboBox = new JComboBox<>(BookingState.values());
TableCellEditor cellEditor = new DefaultCellEditor(comboBox);
JTable jTable = new JTable(tableModel);
jTable.setPreferredScrollableViewportSize(new Dimension(800, 400));
jTable.setDefaultRenderer(BookingState.class, renderer);
jTable.setDefaultEditor(BookingState.class, cellEditor);
jTable.getColumnModel().setColumnSelectionAllowed(true);
jTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
JPanel buttons = new JPanel(new GridLayout(1, 0));
buttons.add(new JButton(new AbstractActionExtension("reserve", jTable, BookingState.RESERVED)));
buttons.add(new JButton(new AbstractActionExtension("boock", jTable, BookingState.BOOCKED)));
buttons.add(new JButton(new AbstractActionExtension("cancel", jTable, BookingState.FREE)));
JPanel jPanel = new JPanel(new BorderLayout());
jPanel.add(new JScrollPane(jTable));
jPanel.add(buttons, BorderLayout.NORTH);
JOptionPane.showMessageDialog(null, jPanel);
}
}
答案 2 :(得分:2)
this.add(table.getTableHeader(), BorderLayout.NORTH);
this.setAllColoumnsRenderer();
this.add(table,BorderLayout.CENTER);
首先,通常不会如何在面板上显示表格。通常会将表添加到JScrollPane,因此基本代码为:
JScrollPane scrollPane = new JScrollPane( table );
this.add(scrollPane, BorderLayout.CENTER);
表格标题和表格会自动添加到滚动窗格中。
添加到它工作正常。它是检索不起作用的数据。
public void addRoom(String roomname,int roomId){
this.remove(table);
((CustomTableModel) model).addRow(getRoomObjectArray(roomname,roomId));
table = new JTable(model);
((CustomTableModel) model).fireTableRowsInserted(0, ((CustomTableModel)model).getRowCount());
this.add(table);
this.revalidate();
this.repaint();
}
每次创建新表或为表设置新模型时,都会创建一个新的TableColumnModel
。结果是您丢失了已添加到表中的所有自定义渲染器/编辑器。
首先,永远不需要重新创建表格。相反,您只需使用表格的setModel(...)
方法即可。这样做,您永远不必担心从框架中删除/添加组件。
然而,这仍然无法解决问题。几个解决方案:
table.setAutoCreateColumnsFromModel(false)
。这将阻止在重置表模型时重新创建TableColumnModel。不要创建渲染器的多个实例:
for(int i=0; i<368;i++){
table.getColumnModel().getColumn(i).setCellRenderer(new CustomRenderer());
}
无需创建368个渲染器实例。所有列都可以共享渲染器。
此外,您无需为每列单独分配渲染器。您可以使用表的setDefaultRenderer(...)方法来设置渲染器。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(“dd-MM-yyyy”);
就像上面的注释一样,这段代码在循环中执行。可以再次共享Formatter。继续创建可以重用的对象。在循环外创建Formatter,这样你就只有一个实例。