Java。如何在JTable中绘制特定的单元格? [英] Java. How to paint a specific cell in a JTable?

查看:116
本文介绍了Java。如何在JTable中绘制特定的单元格?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,我处于这种情况下。我的班级中有渲染器,但不知道如何使用它来使特定单元格的背景变成红色。这是一个房间出租应用,我将Jtable用作日历,因此我希望将油漆单元出租为红色。因此,它应该以某种方式采用特定的列和行并使该单元格变为红色。我的渲染器如下图所示,但是正如我所说,自从Java新手以来,我就不知道如何使用它。真正的问题是如何传递该列和行,我对此有疑问。单元格渲染可以与其他代码一起使用,但这并不是我需要的。

Ok I'm in this situation... I have Renderer in my class but have no idea how to use it to make certain cell's background red. It's a room renting app and I have Jtable as calendar so I want paint cells which are rent red. So It should somehow take specific column and row and make that cell red. My renderer down bellow but as I said no Idea how to use it since Im new to java. Real question how do I pass that column and row, I have problem with that. Cell rendered worked with some other code but that wasnt what I need.

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,它保存所占用房间的行索引和列索引以及房间号日期,保留时间。所以现在在查看示例时,我有点困惑如何使用我的数组设置颜色。我希望我不会精神崩溃

Alright oh wow I might have some trouble figuring this out. But maybe somehow. You said you dont know how my code looks, well I have some basic renderer. One thing to have in mind I have 2 dimensional array ReservedOne which holds row index and column index of taken room also room number date, time until which its reserved. So now Im a bit confused when looking at your example how to use my array to set colors. I hope I wont have mental breakdown

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

Your TableModel should be modeling this data, this is very important, as it allows the rest of the API to revolve around it


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

Real question how do I pass that column and row, I have problem with that. Cell rendered worked with some other code but that wasnt what I need.

这就是为什么 TableModel 包装数据,因为表API将传递信息到 TableCellRenderer ,但它还将传递单元格值!

This is why it's important to have the TableModel wrap the data, as the table API will pass the row and column information to the TableCellRenderer, but it will also pass the cell value!

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

}

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

This means we can now setup the cell renderer to display the information we need

公共静态类RoomTableCellRenderer扩展DefaultTableCellRenderer {

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

}

别忘了,如果您想要表格使用您的渲染器,您需要注册...

Don't forget, if you want the table to use your renderer, you need to register it...

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



已更新...



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

Updated...

Based on the available data been stored in 2D String array (you really don't like me).

这是一个有点脏。实际上,应该将数据设置在可以传递给 TableModel 的地方,并让它处理细节。您还将要特别注意如何更新数组,因为在强制您刷新表之前,更新不会在表中反映出来。

This is a little dirty. In reality, the data should be setup in such away as it could be passed to the TableModel and let it take care of the details. You're also going to have be careful in how you update the array, as updates won't be reflected by the table until you can force it to refresh ... and that won't be pretty.

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 并不是您真正应该做的,但是要对其进行重大的结构调整就可以了

Basically, this allows you to pass the booking information to the TableCellRenderer, as I've stated, this is NOT how you really should be doing this, but it would require a significant restructure of your code to make it work properly.

现在,我创建一个 TableModel ,它基本上需要一个年月值,并返回一个<$每个单元格的c $ c> LocalDate (如果单元格不在月份范围内,则为 null

Now, I create a TableModel which basically takes a year and month value and returns a LocalDate for each cell (or null if the cell is out of the month range)

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

This means that the TableCellRenderer is been passed either a null value of LocalDate value, with this information, you then need to search your array for any possible bookings for the specified date.

这将达到惊人的规模,这就是为什么我避免这样做的原因并一直试图让您更改数据的管理方式,但这就是

This will scale horribly, which is why I've avoided doing and kept trying to get you to change how you manage your data, but here it is

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

And finally a really rough example...

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

This example doesn't really care for all the information you'll be managing, it will only care about the month and day information

< a href = https://i.stack.imgur.com/Bmk5Z.png rel = nofollow noreferrer>

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

}

这篇关于Java。如何在JTable中绘制特定的单元格?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆