Java的。如何在JTable中绘制特定单元格?

时间:2017-04-11 14:53:09

标签: java swing colors jtable tablecellrenderer

好的我在这种情况下......我的课堂上有渲染器,但不知道如何使用它来使某些单元格的背景变红。它是一个房间租赁应用程序,我有Jtable作为日历,所以我想要租红色的油漆单元格。所以它应该以某种方式采取特定的列和行,并使该单元格变红。我的渲染器下降了,但我说不知道如何使用它,因为我是java的新手。真正的问题我如何传递该列和行,我有问题。呈现的单元格与其他一些代码一起工作,但这不是我需要的。

ublic class TableColour extends javax.swing.table.DefaultTableCellRenderer {
@Override
public java.awt.Component getTableCellRendererComponent(javax.swing.JTable table, java.lang.Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    java.awt.Component cellComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    cellComponent.setBackground(java.awt.Color.RED);
    return cellComponent;
}

}

2 个答案:

答案 0 :(得分:1)

  

好吧哦哇我可能会遇到一些麻烦。但也许不知何故。你说你不知道我的代码看起来如何,我有一些基本的渲染器。有一点要记住我有2维数组ReservedOne,它保存所有房间的行索引和列索引,房间号码日期,其预留的时间。所以现在我在看你的例子如何使用我的数组设置颜色时有点困惑。我希望我不会精神崩溃

您的TableModel应该对这些数据建模,这非常重要,因为它允许API的其余部分围绕它旋转

  

真正的问题我如何传递该列和行,我有问题。呈现的单元格与其他一些代码一起工作,但这不是我需要的。

这就是让TableModel包装数据非常重要的原因,因为表格API会将rowcolumn信息传递给TableCellRenderer ,但它也会传递单元格值!

public class RoomTableModel extends AbstractTableModel {

    private Room[][] reservations;

    public RoomTableModel(Room[][] reservations) {
        this.reservations = reservations;
    }

    @Override
    public int getRowCount() {
        return reservations.length;
    }

    @Override
    public int getColumnCount() {
        return reservations[0].length;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        return reservations[rowIndex][columnIndex];
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return Room.class;
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        if (aValue instanceof Room) {
            Room room = (Room) aValue;
            reservations[rowIndex][columnIndex] = room;
            fireTableCellUpdated(rowIndex, columnIndex);
        }
    }

}

这意味着我们现在可以设置单元格渲染器以显示我们需要的信息

public static class RoomTableCellRenderer extends DefaultTableCellRenderer {

    private static Color BOOKED_COLOR = Color.RED;

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        if (value instanceof Room && value != null) {
            if (isSelected) {
                setBackground(table.getSelectionBackground());
                setForeground(table.getSelectionForeground());
            } else {
                setBackground(table.getBackground());
                setForeground(table.getForeground());
            }
            // Update the details based on the room properties
        } else { //if (value == null) {
            setBackground(BOOKED_COLOR);
            setText(null);
        }
        return this;
    }

}

不要忘记,如果您希望表格使用您的渲染器,您需要注册它...

table.setDefaultRenderer(Room.class, new RoomTableCellRenderer());

更新...

根据可用数据存储在2D String数组中(你真的不喜欢我)。

这有点脏。实际上,数据应该设置在可以传递给TableModel的位置,并让它处理细节。您还应该小心更新阵列的方式,因为更新不会被表反映出来,直到您可以强制它更新...并且这不会很漂亮。

public class LocalDateTableCellRenderer extends DefaultTableCellRenderer {

    protected static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd");
    private String[][] bookings;

    public LocalDateTableCellRenderer(String[][] bookings) {
        this.bookings = bookings;
    }


    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
        setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
        if (value instanceof LocalDate) {
            LocalDate date = (LocalDate) value;
            if (hasBookingFor(date)) {
                setForeground(Color.WHITE);
                setBackground(Color.RED);
            }
            setText(formatter.format(date));
        } else {
            setText(null);
        }
        return this;
    }

    protected boolean hasBookingFor(LocalDate date) {
        for (String[] data : bookings) {
            int day = Integer.parseInt(data[2]);
            int month = Integer.parseInt(data[3]);
            int year = 2017; // Because :P

            LocalDate booking = LocalDate.of(year, month, day);
            if (booking.isEqual(date)) {
                return true;
            }
        }
        return false;
    }

}

基本上,这允许您将预订信息传递给TableCellRenderer,正如我所说,这不是您应该如何做到这一点,但它需要重新调整您的代码使它正常工作。

现在,我创建一个TableModel,它基本上需要一年和一个月的值,并为每个单元格返回LocalDate(如果单元格超出月份范围,则返回null)< / p>

public class CalendarModel extends AbstractTableModel {

    public static String[] COLUMN_NAMES = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

    private int rows = 0;

    private LocalDate startOfCalendar;
    private LocalDate firstDayOfMonth;
    private LocalDate lastDayOfMonth;

    public CalendarModel(int year, Month month) {
        firstDayOfMonth = LocalDate.of(year, month, 1);

        startOfCalendar = firstDayOfMonth.minusDays(firstDayOfMonth.getDayOfWeek().getValue());
        lastDayOfMonth = firstDayOfMonth.with(TemporalAdjusters.lastDayOfMonth());

        System.out.println(startOfCalendar.getDayOfWeek());
        System.out.println(firstDayOfMonth);
        System.out.println(lastDayOfMonth);

        Duration between = Duration.between(startOfCalendar.atStartOfDay(), lastDayOfMonth.atStartOfDay());
        long days = between.toDays();
        rows = (int) Math.round(days / 7d) + 1;
    }

    @Override
    public int getRowCount() {
        return rows;
    }

    @Override
    public int getColumnCount() {
        return 7;
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return LocalDate.class;
    }

    @Override
    public String getColumnName(int column) {
        return COLUMN_NAMES[column];
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {

        LocalDate date = null;

        if (startOfCalendar != null) {
            int day = (rowIndex * 7) + columnIndex;
            date = startOfCalendar.plusDays(day);

            if (date.isBefore(firstDayOfMonth) || date.isAfter(lastDayOfMonth)) {
                date = null;
            }
        }

        return date;

    }

}

这意味着TableCellRenderer已传递null值为LocalDate的值,有了这些信息,您需要在数组中搜索指定日期的任何可能预订

这将会出现可怕的扩展,这就是为什么我一直避免这样做,并一直试图让你改变管理数据的方式,但这里是

最后一个非常粗略的例子......

这个例子并不真正关心你所管理的所有信息,它只关心月和日信息

Example

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.time.Duration;
import java.time.LocalDate;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableModel;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                String[][] bookings = new String[7][6];
                bookings[0][2] = "5";
                bookings[0][3] = "4";
                bookings[1][2] = "10";
                bookings[1][3] = "4";
                bookings[2][2] = "15";
                bookings[2][3] = "4";
                bookings[3][2] = "20";
                bookings[3][3] = "4";
                bookings[4][2] = "25";
                bookings[4][3] = "4";
                bookings[5][2] = "30";
                bookings[5][3] = "4";
                bookings[6][2] = "5";
                bookings[6][3] = "5";

                TableModel model = new CalendarModel(2017, Month.APRIL);
                JTable table = new JTable(model);
                table.setDefaultRenderer(LocalDate.class, new LocalDateTableCellRenderer(bookings));

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new JScrollPane(table));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}

答案 1 :(得分:0)

您必须为JTable的每一列设置单元格渲染器。 我希望这个例子可以帮到你:

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

public class JTableTest
{

  public static void main( String[] args )
  {
    SwingUtilities.invokeLater( new Runnable()
    {
      @Override
      public void run()
      {
        buildUI();
      }
    } );
  }

  public static void buildUI()
  {
    final int w = 500;
    final int h = 200;
    Object colNames[] =
    {
      "COL1", "COL2", "COL3"
    };
    Object[][] data =
    {
    };
    DefaultTableModel dtm = new DefaultTableModel( data, colNames );
    dtm.addRow( new Object[]
    {
      "a", "b", "c"
    } );
    dtm.addRow( new Object[]
    {
      "d", "e", "f"
    } );
    dtm.addRow( new Object[]
    {
      "g", "h", "i"
    } );
    dtm.addRow( new Object[]
    {
      "l", "m", "n"
    } );
    final JTable t = new JTable( dtm );
    final TableColour tce = new TableColour();
    t.getColumnModel().getColumn( 0 ).setCellRenderer( tce );
    t.getColumnModel().getColumn( 1 ).setCellRenderer( tce );
    t.getColumnModel().getColumn( 2 ).setCellRenderer( tce );
    final JFrame f = new JFrame();
    f.setBounds( 0, 0, w, h );
    JScrollPane sp = new JScrollPane( t );
    f.getContentPane().add( sp );
    f.setVisible( true );

  }
}

class TableColour
    extends javax.swing.table.DefaultTableCellRenderer
{

  @Override
  public java.awt.Component getTableCellRendererComponent( javax.swing.JTable table, java.lang.Object value, boolean isSelected, boolean hasFocus, int row, int column )
  {
    java.awt.Component cellComponent = super.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column );
    cellComponent.setBackground( java.awt.Color.RED );
    return cellComponent;
  }

}