I have a TableView with a TableColumn called "descriptionCol". To do text wrapping I used this cell factory:
descriptionCol.setCellValueFactory((new PropertyValueFactory<Task, String>("description")));
descriptionCol.setCellFactory(new Callback<TableColumn<Task, String>, TableCell<Task, String>>() {
@Override
public TableCell<Task, String> call(TableColumn<Task, String> param) {
final TableCell<Task, String> cell = new TableCell<Task, String>() {
private Text text;
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!isEmpty()) {
text = new Text(item.toString());
text.setWrappingWidth(descriptionCol.getWidth() * 2); // Setting the wrapping width to the Text
setGraphic(text);
}
}
};
return cell;
}
});
which works for wrapping the text in the column but as a side-effect the text isn't styled like the rest of the text in the program.
descriptionCol is defined in fxml as:
<TableColumn fx:id="descriptionCol" prefWidth="75.0" text="Description" />
and is in the <columns> tag of the TableView.
The styled text should be
* {
-fx-text-fill: -fx-txt;
-fx-font-size: 12px;
/* Everything in regular CSS format is only there for compatibility reasons */
color: -fx-txt;
font-size: 12px;
}
where -fx-txt is in .root as "#FFFFFF"
I've tried doing text.setStyle()
in the cell factory, creating a CSS rule as .text {}
and inserting the above CSS into the rule in my stylesheet, setting an id to the text object and creating an #id {}
rule in the stylesheet, and applying the css to the .table.column {}
rule in the stylesheet as well. So far none of these solutions have worked to style the object and I'm all out of ideas now. Also confused why the * {}
rule above isn't just being automatically applied to the Text object in the table column but I think that's something to ask in a separate question.
If anymore of the code is needed to get a proper gauge on what's going on please let me know and I can provide.
MRE:
- Using VS Code with JavaFX 13 and Java 11
Main.java
package com.example;
import java.io.IOException;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application
{
protected static Scene mainScene;
protected static ObservableList<Task> list = FXCollections.observableArrayList();
@Override
public void start(Stage primStage) throws IOException
{
primStage.setTitle("Example");
mainScene = new Scene(loadFXML("Table"), 640, 480);
mainScene.getStylesheets().add(getClass().getResource("Main.css").toExternalForm());
primStage.setScene(mainScene);
primStage.setMaximized(true);
primStage.show();
}
static void setRoot(String fxml) throws IOException {
mainScene.setRoot(loadFXML(fxml));
}
private static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource(fxml + ".fxml"));
return fxmlLoader.load();
}
public static void main(String[] args) {
launch();
}
}
Controller.java
package com.example;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import java.net.URL;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.BorderPane;
import javafx.scene.text.Text;
import javafx.fxml.Initializable;
import javafx.util.Callback;
import javafx.scene.control.TableCell;
public class Controller extends Main implements Initializable
{
@FXML private BorderPane bPane;
@FXML private TableView<Task> table;
@FXML private TableColumn<Task, String> descriptionCol;
@Override
public void initialize(URL url, ResourceBundle resources)
{
// Sample data
list.add(new Task(100.0, 300.0, MouseButton.PRIMARY));
list.get(0).setName("Click Corner");
list.get(0).setDescription("Clicks to top left corner of the screen");
list.add(new Task("A"));
list.get(1).setName("Type a");
list.get(1).setDescription("Types the letter 'a' once");
// Adds data to table
table.getItems().setAll(list);
descriptionCol.setCellValueFactory((new PropertyValueFactory<Task, String>("description")));
descriptionCol.setCellFactory(new Callback<TableColumn<Task, String>, TableCell<Task, String>>() {
@Override
public TableCell<Task, String> call(TableColumn<Task, String> param) {
final TableCell<Task, String> cell = new TableCell<Task, String>() {
private Text text;
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!isEmpty()) {
text = new Text(item.toString());
text.setWrappingWidth(descriptionCol.getWidth() * 2); // Setting the wrapping width to the Text
setGraphic(text);
}
}
};
return cell;
}
});
}
}
Task.java
package com.example;
import javafx.scene.input.MouseButton;
public class Task
{
private double x, y;
private MouseButton button;
private String description, name, keyCode;
public Task(double xPos, double yPos, MouseButton inButton)
{
this.x = xPos;
this.y = yPos;
this.button = inButton;
this.description = null;
this.name = null;
}
public Task(String code)
{
this.x = 0;
this.y = 0;
this.button = MouseButton.NONE;
this.description = null;
this.name = null;
this.keyCode = code;
}
public void setName(String s)
{
this.name = s;
}
public void setDescription(String s)
{
this.description = s;
}
public String getDescription()
{
return this.description;
}
}
Table.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane fx:id="bPane" prefHeight="1080.0" prefWidth="1920.0" fx:controller="com.example.Controller" xmlns="http://javafx.com/javafx/13" xmlns:fx="http://javafx.com/fxml/1">
<center>
<TableView fx:id="table" prefHeight="352.0" prefWidth="543.0">
<columns>
<TableColumn fx:id="descriptionCol" prefWidth="75.0" text="Description" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</center>
</BorderPane>
Main.css
.root {
-fx-bgc: #121212; /* Dark gray recommended dark theme background color - Material Design */
-fx-bgc-alt: #242424;
-fx-pc: #7C4DFF; /* Deep Purple 50 A200 - Material Design */
-fx-sc: #448AFF; /* Blue 50 A200 - Material Design */
-fx-sc-uf: #588be0;
-fx-txt: #FFFFFF;
}
* {
-fx-background-color: -fx-bgc;
-fx-text-fill: -fx-txt;
-fx-font-size: 12px;
/* Everything in regular CSS format is only there for compatibility reasons */
background-color: -fx-bgc;
color: -fx-txt;
font-size: 12px;
}
.table-row-cell:focused, .table-row-cell:focused:even,
.table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell:filled:even:focused:selected {
-fx-background-color: -fx-pc, -fx-pc, -fx-pc;
-fx-background-insets: 0, 1, 2;
background-color: -fx-pc, -fx-pc, -fx-pc;
}
.table-row-cell:focused:odd,
.table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell:filled:odd:focused:selected {
-fx-background-color: -fx-sc, -fx-sc, -fx-sc;
-fx-background-insets: 0, 1, 2;
background-color: -fx-sc, -fx-sc, -fx-sc;
}
.table-column {
-fx-alignment: CENTER;
}
.table-row-cell {
-fx-table-cell-border-color: -fx-txt;
}
.table-view .column-header-background, .table-view .column-header-background .filler, .table-view .corner {
-fx-background-color: -fx-bgc;
background-color: -fx-bgc;
}
.table-row-cell:filled:even .table-column:filled,
.table-row-cell:filled:even .table-column,
.table-row-cell:even .table-column:filled {
-fx-background-color: -fx-bgc;
-fx-selection-bar: -fx-pc;
-fx-selection-bar-non-focused: -fx-pc;
background-color: -fx-bgc;
}
.table-row-cell:filled:odd .table-column:filled,
.table-row-cell:filled:odd .table-column,
.table-row-cell:odd .table-column:filled {
-fx-background-color: -fx-bgc-alt;
-fx-selection-bar: -fx-sc;
-fx-selection-bar-non-focused: -fx-sc;
background-color: -fx-bgc-alt;
}
File structure and how I created the MRE:
- In VSCode open command palette and create a new JavaFX project provided by Maven.
- Only thing I changed in the prompts was making the artifact id be "example" instead of "demo" but I don't think that should matter.
- Under src/main/java/com/example/ include Controller.java, Main.java, and Task.java provided above
- Under src/main/java/ add
requires transitive javafx.graphics;
to file module-info.java- I did this under
requires javafx.fxml;
as line 4.
- I did this under
- Under src/main/resources/com/example/ include Table.fxml and Main.css also provided above.
- I left in all of the table CSS rules that I did so that you can see exactly what I see
- I did not change anything in the auto-generated pom.xml and I removed all other .java and .fxml files that were made on creation.