Я сейчас на распутье.У меня проблема с окраской в ячейках TableView<Person>.
У меня есть 3 столбца: firstName, lastName, and the Days Column
(что на самом деле 60 столбцов, представляющих следующие 60 дней с сегодняшнего дня).Каждый Person
будет чем-то заниматься в эти дни под названием «events
» (максимум 1 событие в день с startDate
и endDate
).Поэтому каждый человек может иметь до 60 событий, когда я читаю их из файла XML.Вот иллюстрация, чтобы проиллюстрировать то, что я имею в виду.
Планировщик
Это класс Person
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import stack.Event;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
public class Person{
private StringProperty name;
private StringProperty last;
private String group;
private ArrayList<Event> events;
static ArrayList<String> strDays = new ArrayList<String>();
public ArrayList<Event> getEvents() {
return events;
}
public void setEvents(ArrayList<Event> events) {
this.events = new ArrayList<>(events);
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);;
}
public StringProperty nameProperty(){
return name;
}
public String getLast() {
return last.get();
}
public void setLast(String last) {
this.last.set(last);
}
public StringProperty lastProperty(){
return last;
}
public String getGroups() {
return group;
}
public void setGroups(String group) {
this.group = group;
}
public Person(String name, String last, String group, ArrayList<Event> events){
this.name = new SimpleStringProperty(name);
this.last = new SimpleStringProperty(last);
this.group = group;
this.events = new ArrayList<Event>(events);
}
public static void print(){
Date current = new Date(); //current first date
SimpleDateFormat ft = new SimpleDateFormat("yyyy\n MM/dd\n E"); //format wanted
ArrayList<Date> dates = new ArrayList<Date>();
Calendar cal = Calendar.getInstance();
cal.setTime(current);
cal.add(Calendar.DATE, 60); //setting the tableView end date
Date startDate = current;
Date endDate = cal.getTime();
Calendar c1 = DateToCalendar(startDate);
Calendar c2 = DateToCalendar(endDate);
//this generates all the dates between the start date and end date
while (!areEqualDate(c1, c2)){
ft.format(c1.getTime());
dates.add(c1.getTime());
c1.add(Calendar.DAY_OF_YEAR,1);
}
//this formats the dates
for (int i = 0; i < dates.size(); i++){
strDays.add(i, ft.format(dates.get(i)));
}
}
private static boolean areEqualDate(Calendar c1, Calendar c2) {
if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR))
return false;
if (c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH))
return false;
if (c1.get(Calendar.DAY_OF_YEAR) != c2.get(Calendar.DAY_OF_YEAR))
return false;
return true;
}
private static Calendar DateToCalendar(Date startDate) {
Calendar cal = Calendar.getInstance();
cal.setTime(startDate);
return cal;
}
}
Класс события
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
public class Event {
private String event;
private String startDate;
private String endDate;
public String getStartDate() {
return startDate;
}
public void setStartDate(String startDate) {
this.startDate = startDate;
}
public String getEndDate() {
return endDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
public Event(){
this.event= "";
this.startDate = "";
this.endDate = "";
}
public Event(String event, String startDate, String endDate){
this.event = event;
this.startDate = startDate;
this.endDate = endDate;
}
public String getEvent() {
return event;
}
public void setEvent(String event) {
this.event = event;
}
}
Мой класс sample.fxml, имя пакета моего проекта: стек
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Text?>
<?import javafx.scene.control.ChoiceBox?>
<?import java.lang.String?>
<?import javafx.collections.FXCollections?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.cell.*?>
<?import javafx.collections.*?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.SeparatorMenuItem?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.control.ScrollBar?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.CheckBox?>
<BorderPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml"
fx:controller="stack.Controller" fx:id="container">
<center>
<GridPane alignment="CENTER">
<padding>
<Insets top="40" left="20" bottom="20" right="20"></Insets>
</padding>
<?language javascript?>
<Label fx:id="title" text="Scheduler" alignment="CENTER" GridPane.columnIndex="0" GridPane.rowIndex="0"></Label>
<TableView fx:id="table" GridPane.columnIndex="0" GridPane.rowIndex="2" GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS" editable="true">
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
<columns>
<TableColumn fx:id="firstColumn" text="First Name" minWidth="100" maxWidth="100">
<cellValueFactory>
<PropertyValueFactory property="name"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="secondColumn" text="Last Name" minWidth="100" maxWidth="120">
<cellValueFactory>
<PropertyValueFactory property="last" />
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
<fx:script>
table.getSelectionModel().setCellSelectionEnabled(true);
table.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);
</fx:script>
</GridPane>
</center>
</BorderPane>
Основной класс
import javax.print.DocFlavor.URL;
import javafx.application.*;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.MenuItem;
import javafx.scene.image.Image;
public class main extends Application {
public Scene theme;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
try {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Stack");
Scene scene = new Scene(root, 800, 650);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
}
Мой код неправильный, ноЯ понимаю, почему он делает то, что делает.это то, что у меня есть в настоящее время в моем классе контроллеров
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.util.Callback;
public class Controller implements Initializable {
public TableView<Person> table = new TableView<>();
public TableColumn<Person, String> firstColumn, secondColumn, days;
public TableColumn[] tablecols;
//public TableColumn<Person, Event> days;
int count = 0;
//TempTestClass test = new TempTestClass();
private String current = "";
ArrayList<String> dayArray = new ArrayList<String>();
@Override
public void initialize(URL location, ResourceBundle resources) {
Person.print();
dayArray = new ArrayList<String>(Person.strDays);
tablecols = new TableColumn[dayArray.size()];
System.out.println("tablecols size: " + tablecols.length);
String start = "";
//in each day for the next 60 days
for (int i = 0; i < tablecols.length; i++){
days = new TableColumn<>(dayArray.get(i));
days.setText(dayArray.get(i));
days.setMinWidth(55);
table.getColumns().add(days);
current = dayArray.get(i);
//days.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getEvents().toString()));
//days.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getEvents().get(0).getEvent()));
for (Person p:getPerson()){
if (p.getEvents().size() != 0){
for (int j = 0; j < p.getEvents().size(); j++){
start = p.getEvents().get(j).getStartDate();
String sub = start.substring(0, 5);
// I think we're good here, it gets all the valid days that there's at least one event on
if (current.contains(sub)){
System.out.println(sub);
specific();
}
}
} } }
/*These two do not work here*/
//specific();
//days.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getEvents().get(0).getEvent().toString()));
table.setItems(getPerson());
table.setEditable(true);
table.setStyle("-fx-selection-bar: grey;"); //default cell color
}
/*******************************************************************************************************************************************************************************************************/
/*******************************************************************************************************************************************************************************************************/
public void specific(){ //loops through each column?
days.setCellFactory(new Callback<TableColumn<Person, String>,
TableCell<Person, String>>(){
@Override
public TableCell<Person, String> call(
TableColumn<Person, String> param){
return new TableCell<Person, String>(){
@Override
protected void updateItem(String item, boolean empty){
super.updateItem(item, empty);
if (empty){ //item is null, meaning there's nothing there?
setText(null);
setGraphic(null);
} else {
int currentIndex = indexProperty()
.getValue() < 0 ? 0
: indexProperty().getValue();
ArrayList<Event> type = param //basically person.getEvents()
.getTableView().getItems()
.get(currentIndex).getEvents();
Person person = getTableView().getItems().get(currentIndex);
for (int i = 0; i < type.size(); i++){
String task = type.get(i).getEvent();
/*String day = type.get(i).getStartDate();
String sub = day.substring(0, 5);*/
if (type.get(1).getEvent().equals("International Travel")){
setStyle("-fx-background-color: orange");
setText(task);
}
if (type.get(i).getEvent().equals("PTO")){
setStyle("-fx-background-color: green");
setText(task);
}
else{
setStyle(""); //invisible column but still "filled in"
setText(task);
}
}
}
};
};
}
});
}
public ObservableList<Person> getPerson(){
ObservableList<Person> person = FXCollections.observableArrayList();
ArrayList<Event> eventArray = new ArrayList<Event>();
eventArray.add(new Event("International Travel", "09/22/2018", "09/22/2018"));
eventArray.add(new Event("International Travel", "09/30/2018", "09/30/2018"));
eventArray.add(new Event("PTO", "10/02/2018", "10/02/2018"));
ArrayList<Event> diffArray = new ArrayList<Event>();
diffArray.add(new Event("Personal", "09/22/2018", "09/22/2018"));
diffArray.add(new Event("PTO", "09/30/2018", "09/30/2018"));
diffArray.add(new Event("PTO", "10/02/2018", "10/02/2018"));
person.add(new Person("John", "Smith", "GroupA", eventArray));
person.add(new Person("Karen", "O", "GroupA", eventArray));
person.add(new Person("Jane", "Doe", "GroupB", diffArray));
person.add(new Person("Mike", "Johnson", "GroupA", eventArray));
person.add(new Person("Dukes", "Clan", "GroupB", diffArray));
return person;
}
}
Так что в основном то, что происходит с приведенным выше полным кодом Compilable , - это если Dukes имеет события 09/22, 09/30,и 10/02, которые event
Personal только 22-го числа, и PTO в другие дни 30-го и 2-го.09/22 day column
будет синим, потому что cellFactory будет смотреть на события, которые есть у Герцогов (которых 3) в этой клетке, каждой клетки, принадлежащей Герцогам, и затем будет видеть, что "О, она делаетв массиве событий есть событие PTO, поэтому давайте сделаем всю ячейку синей ".Дневные столбцы важны для меня, и я подумал о том, чтобы поставить что-то вроде (If PTO && PTO.startDay.equals(dayColumn.getText))
, но это будет некрасиво и все равно не будет работать точно.Я не знаю, как быть гибким с этим.Я могу только жестко закодировать его, чтобы он выглядел как то, что я хочу, но это плохая логика, мой код - плохая логика, поэтому я спрашиваю, является ли Hashmap подходом перед тем, как пройти этот маршрут, или есть простая реализацияили что-то я пропускаю?
Нужен ли мне один или два HashMap?потому что я думаю, что должен быть способ нанести на карту человека, и день через событие.
Примерно так Макет
Я искал другие ссылки и думаю, что это можно сделать, но я просто хотел узнать, нужен ли хэш-файлчтобы выполнить то, что я хочу, а также о том, что я делаю неправильно.
Спасибо.