2017-06-15 107 views
0

我有一个JTable,我可以在其上显示一些信息和颜色背景。然而,每当数据发生变化时,我都会遇到问题,表格不会更新它的颜色。展望槽SO我发现了几个问题,他说这些例子应该工作:强制更新JTable不起作用

table.revalidate(); 

((CustomTableModel)table.getModel()).fireTableDataChanged(); 

table.repaint(); 

tableModel.fireTableCellUpdated(row, col); 

我已经试过这些方法在桌子里面eModel,在JPanel类中持有表格本身,甚至在tablerenderer内部,但似乎没有任何工作(表格不会改变一点)

我检查了更新表格时收到的数据是否变化,但表格本身不更新。它只有当我重新启动应用程序。

我试图做一个Minimal, Complete, and Verifiable example只是通过复制的代码,但我可以使它以同样的方式,它已成为办法漫长而复杂的人了解工作之前...

为此我决定要上传整个project to 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:

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; 

    } 
} 

由于这个版本我想从TablePanel类更新表的软件。但我已经在所有这三个类中尝试过了。

这是一个video它的行为。我希望我已经解释了这个问题,你知道解决方案吗?

+0

你应该为每个GUI组件创建一个单独的MouseAdapter实例,而不是为所有人创建一个... –

回答

2

DefaultTableCellRenderer.getTableCellRendererComponent作为参数视图索引。您继续执行以使用这些索引来检索模型中的值。您需要首先使用JTable.convertRowIndexToModelJTable.convertColumnIndexToModel来转换这些索引。然后使用转换后的索引检索模型中的值。

+0

等一等你能解释一下好吗? – BRHSM

+0

@BRHSM屏幕上显示的是视图。存储在内存中的是模型。视图和模型之间有一个映射。例如。当你对行进行排序,重新排列柱子等等,这些都不是在模型中完成的,而是在视图中完成的。视图映射到模型。例如,模型包含{5,4,3,2,1},您按升序排序,视图将包含{1,2,3,4,5},但模型保持不变。该视图将具有行1映射到模型中的行5,视图中的行2到模型中的行4等等。这就是为什么你需要将索引从视图转换为模型或反之亦然。 –

+0

我已经尝试在使用这些值之前将'convertRowIndexToModel'&'convertColumnIndexToModel'添加到GetStatus()方法中,但它使我在使用它们的行上出现'ArrayIndexOutOfBoundsException'(在CustomTableModel中的第35行) – BRHSM

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

} 
+0

你的意思是在这里更新你的文件? – BRHSM

+0

@BRHSM什么都你作为持久性的后端使用,我没有深入分析你的代码... –

+0

所以这是像添加的东西呢? – BRHSM

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。

不要创建渲染器的多个实例:

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

没有必要创建368个实例你渲染器。渲染器可以被所有列共享。

此外,您不需要将渲染器单独分配给每列。您可以使用表的setDefaultRenderer(...)方法来设置渲染器。

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

就像上面的注释一样,这段代码在一个循环内执行。格式化程序可以再次共享。请继续创建可重用的对象。在循环外部创建格式化程序,以便只有一个实例。

+0

我尝试添加了setDefaultRenderer但现在有没有颜色在所有... – BRHSM

+0

我会尽力找到所有的地方我创建循环内的对象并摆脱它们 – BRHSM

+0

嗯,你做错了什么。您是否指定了渲染器应该用于的正确“类”?为什么你甚至在你的代码中有'Booking'类。所有的数据都应该存储在TableModel中。如果您对表格中的数据进行更改,则更新后端数据库。 – camickr