繁体   English   中英

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

[英]Java. How to paint a specific cell in a JTable?

好的,我处于这种情况下...我的班级中有渲染器,但不知道如何使用它来使特定单元格的背景变为红色。 这是一个房间出租应用程序,我将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;
}

}

好吧,哇,我可能很难解决这个问题。 但是也许以某种方式。 您说您不知道我的代码看起来如何,我有一些基本的渲染器。 要记住的一件事是,我有一个二维数组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);
        }
    }

}

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

公共静态类RoomTableCellRenderer扩展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

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传递LocalDate值的null值,并使用此信息,然后您需要在数组中搜索指定日期的任何可能的预订。

这将令人难以置信地扩展,这就是为什么我避免这样做并一直试图让您更改数据管理方式的原因,但这就是为什么

最后是一个非常粗糙的例子...

该示例并不真正关心您将要管理的所有信息,而仅关心月和日信息

例

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

}

您必须为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;
  }

}

暂无
暂无

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

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