Forcing update on JTable not working

时间:2017-06-15 10:34:13

标签: java swing jtable tablecellrenderer

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?

3 个答案:

答案 0 :(得分:2)

DefaultTableCellRenderer.getTableCellRendererComponent将参数视为索引。您将继续执行以使用这些索引来检索模型中的值。您需要先使用JTable.convertRowIndexToModelJTable.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(...)方法即可。这样做,您永远不必担心从框架中删除/添加组件。

然而,这仍然无法解决问题。几个解决方案:

    重置模型后,
  1. 在自定义渲染器/编辑器中重新添加。
  2. 不要创建新模型。相反,您可以从模型中删除所有行,然后使用addRow(...)方法重置模型中的行
  3. 首次创建表格后,您可以首次使用:table.setAutoCreateColumnsFromModel(false)。这将阻止在重置表模型时重新创建TableColumnModel。
  4. 不要创建渲染器的多个实例:

    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,这样你就只有一个实例。