简体   繁体   English

强制JTable上的更新不起作用

[英]Forcing update on JTable not working

I have a JTable on which I show some info and color backgrounds accordingly. 我有一个JTable,可以在上面显示一些信息和相应的颜色背景。 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) 我已经在tableModel内部,持有表本身的JPanel类中甚至在tablerenderer内部尝试了这些方法,但是似乎没有任何效果(表没有改变)

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: 因此,我决定将整个项目上传到github,但是您可以在这里的以下类中找到错误:

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: 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: 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. 从该软件的该版本开始,我正尝试从TablePanel类更新表。 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? 我希望我已经解释了足够的问题,您知道解决方案吗?

DefaultTableCellRenderer.getTableCellRendererComponent takes as parameters view indexes. DefaultTableCellRenderer.getTableCellRendererComponent以视图索引为参数。 You proceed in the implementation to use these indexes to retrieve values in the model. 您可以继续实施以使用这些索引来检索模型中的值。 You need to convert those indexes using JTable.convertRowIndexToModel and JTable.convertColumnIndexToModel first. 您需要先使用JTable.convertRowIndexToModelJTable.convertColumnIndexToModel转换这些索引。 Then use the converted indexes to retrieve the values in the model. 然后使用转换后的索引来检索模型中的值。

looks like you're not calling super.setValueAt() . 看起来您没有调用super.setValueAt() Here is a working example: 这是一个工作示例:

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);
    }

}
    this.add(table.getTableHeader(), BorderLayout.NORTH);
    this.setAllColoumnsRenderer();
    this.add(table,BorderLayout.CENTER);

First of all that is not how you would normally display a table on a panel. 首先,这不是您通常在面板上显示表格的方式。 Typically a table is added to a JScrollPane so the basic code would be: 通常,将表添加到JScrollPane,因此基本代码为:

JScrollPane scrollPane = new JScrollPane( table );
this.add(scrollPane, BorderLayout.CENTER);

The table header and table are automatically added to the scrollpane. 表标题和表将自动添加到滚动窗格中。

adding to it works fine. 添加到它工作正常。 it's the retrieving of the data that doesn't work. 这是无法使用的数据检索。

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();
}

Every time you create a new table or set a new model to the table a new TableColumnModel is created. 每次创建新表或在表中设置新模型时,都会创建一个新TableColumnModel The result of this is that you lose all the custom renderers/editors that have been added to the table. 这样的结果是您将丢失所有已添加到表中的自定义渲染器/编辑器。

Firstly, there is never any need to recreate the table. 首先,永远不需要重新创建表。 Instead you can just use the setModel(...) method of the table. 相反,您可以只使用表的setModel(...)方法。 Doing this you never need to worry about removing/adding components from the frame. 这样做,您无需担心从框架中删除/添加组件。

However this still won't solve the problem. 但是,这仍然无法解决问题。 A couple of solutions: 几个解决方案:

  1. add back in the custom renderers/editor after resetting the model. 重置模型后,重新添加到自定义渲染器/编辑器中。
  2. don't create a new model. 不要创建新模型。 Instead you can remove all the rows from the model and then use the addRow(...) method to reset the rows in the model 相反,您可以从模型中删除所有行,然后使用addRow(...)方法重置模型中的行。
  3. After you initially create the table the first time you can use: table.setAutoCreateColumnsFromModel(false) . 初次创建表后,可以使用: table.setAutoCreateColumnsFromModel(false) This will prevent the TableColumnModel from being recreated when you reset the model of the table. 这将防止在重置表的模型时重新创建TableColumnModel。

Don't create multiple instances of the renderer: 不要创建渲染器的多个实例:

for(int i=0; i<368;i++){
    table.getColumnModel().getColumn(i).setCellRenderer(new CustomRenderer());
}

There is no need to create 368 instances of you renderer. 无需创建368个渲染器实例。 A renderer can be shared by all the columns. 渲染器可以被所有列共享。

Also, you don't need to assign the renderer individually to each column. 另外,您无需将渲染器单独分配给每一列。 You can just use the setDefaultRenderer(...) method of the table to set the renderer. 您可以只使用表的setDefaultRenderer(...)方法来设置渲染器。

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern(“ dd-MM-yyyy”);

Just like the above comment, this code is executed inside a loop. 就像上面的注释一样,此代码在循环内执行。 Again a Formatter can be shared. 同样,可以共享格式化程序。 Do keep creating objects that can be reused. 务必创建可重复使用的对象。 Create the Formatter outside the loop so you only have a single instance. 在循环外创建格式化程序,这样您只有一个实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM