After many hours of reading and trying I have been struggling with populating editable TextField containers within a TableView.
I already managed to display data from an ObservableList of a custom object to my TableView instance.
I already tried this command:
spalteTag.setCellFactory(TextFieldTableCell.forTableColumn(spalteTag));
But this gives an error whereas this type of code
spalteIstErledigt.setCellFactory(CheckBoxTableCell.forTableColumn(spalteIstErledigt));
works properly.
package sample;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.converter.NumberStringConverter;
import tabellen.MysqlController;
import tabellen.TabelleKabelzug;
public class mainController {
ObservableList<TabelleKabelzug> oListeKabelzug = FXCollections.observableArrayList();
#FXML
private TableView tableViewKabelzug = new TableView();
#FXML
private TableColumn<TabelleKabelzug, Integer> spalteId = new TableColumn();
#FXML
private TableColumn<TabelleKabelzug, Boolean> spalteIstErledigt = new TableColumn();
#FXML
private TableColumn<TabelleKabelzug, String> spalteTag = new TableColumn();
public void initialize() {
initialisiereKabelzugliste();
tableViewKabelzug.setItems(oListeKabelzug);
}
public void initialisiereKabelzugliste() {
MysqlController controller = new MysqlController();
controller.mitMysqlVerbinden();
oListeKabelzug.setAll(controller.kabelzuglisteLaden());
spalteIstErledigt.setCellFactory(CheckBoxTableCell.forTableColumn(spalteIstErledigt));
spalteTag.setCellFactory(TextFieldTableCell.forTableColumn(spalteTag));
tableViewKabelzug.setItems(oListeKabelzug);
}
}
Example of my TableColumn "spalteTag" within my .fxml-File:
<TableColumn fx:id="spalteTag" text="BMK">
<cellValueFactory>
<PropertyValueFactory property="tag" />
</cellValueFactory>
<cellFactory>
??? <-- Any code in here possible?
</cellFactory>
</TableColumn>
Here is a sample of what it looks like at the moment (without any errors of course):
TableView with populated data and Checkboxes
So my 3 questions now are:
First how can I add TextFields in every TableView cell that is dedicated to a String value?
Second how can I make these TextFields editable for every TableView cell?
Third and is there any setup possible for this in my .fxml file? (this would be the most convenient solution to me)
Greetings from Germany :)
You don't have to pass parameter to forTableColumn function.
Try this
spalteTag.setCellFactory(TextFieldTableCell.forTableColumn());
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last year.
Improve this question
I will be very grateful for your help, I am trying to create JavaFX applications, I want to start creating something on the canvas panel, the code is compiling but no effects, it seems to me that the canvas panel view is not refreshed, maybe some spec will advise what I forgot, I throw in the whole class, below the code the window structure from the scene builder and the project structure.
[![package com.example.rpgfxmaven;
import javafx.animation.AnimationTimer;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.AnchorPane;
import javafx.scene.media.MediaPlayer;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.IOException;
public class GameControler{
final int oryginalnyRozmiarLudzika = 16; // 16x16 tile
final int skala = 3;
final int rozmiarLudzika = skala * oryginalnyRozmiarLudzika;
final int dlugoscPlanszy = 20;
final int szerokoscPlanszy = 15;
final int dlugoscEkranu = rozmiarLudzika*dlugoscPlanszy;
final int szerokoscEkranu = rozmiarLudzika*szerokoscPlanszy;
#FXML
private Canvas canvaspane = new Canvas(dlugoscEkranu, szerokoscEkranu);
GraphicsContext content;
public static MediaPlayer mediaPlayer;
public void start(Stage primaryStage) throws IOException {
FXMLLoader loader = new FXMLLoader(this.getClass().getResource("maingame-window.fxml"));
AnchorPane anchorPane= loader.load();
anchorPane.setPrefSize(dlugoscEkranu+100, szerokoscEkranu+75);
Scene scene = new Scene(anchorPane);
primaryStage.setScene(scene);
primaryStage.show();
content = canvaspane.getGraphicsContext2D();
startGame();
}
public void startGame()
{
Timeline timeline = new Timeline(new KeyFrame(Duration.millis(10), e ->run(content)));
timeline.setCycleCount(Timeline.INDEFINITE);
}
public void run(GraphicsContext content) {
content.setFill(Color.BLUE);
content.fillRect(100, 100, rozmiarLudzika,rozmiarLudzika);
}
}
This is wrong:
#FXML
private Canvas canvaspane = new Canvas(dlugoscEkranu, szerokoscEkranu);
You should never set an #FXML injected field to a new value.
The fxml loader will already have created an instance of the #FXML field and linked that into the object tree returned by the loader.
If you assign the field to a new value, the new value will not be in the loaded object tree added to the scene graph, so it will never be seen. Only the empty canvas created by the loader will be seen.
You almost definitely have other issues with your application outside of this, but I can't really outline them in detail here.
In a simple drag and drop example program where strings can be dragged from a list cell to a text field, everything works fine, except that after a drop, the mouse does not behave normally: for example, I have to click twice on the window close button for the window to close.
However, in the following cases, everything works fine:
Using a label instead of a text field (but the problem remains with a text area)
Dropping a string into the text field from another application
Dragging the string from the list cell onto another application
Clicking anywhere in the window also 'frees' the close button - even outside the list or the text field.
Edited: Below is a minimal working example (class DnD in package dnd). Note in particular the drag and drop handlers used on the field and on the list cell. To reproduce the problem: run the program, drag Banana from the list to the text field and then try to close the window. In my case I have to click twice.
package dnd;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Dnd extends Application {
#Override
public void start(Stage stage) {
stage.setScene(new Scene(new DndPanel(), 200, 300));
stage.setTitle("Drag and drop");
stage.setResizable(false);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
public static class DndPanel extends VBox {
public DndPanel() {
super(10);
TextField field = new TextField();
ListView<String> list = new ListView<>();
list.setCellFactory(Dnd.DnDCell::new);
list.getItems().addAll("Apple", "Pear", "Banana", "Grapes", "Peach", "Pineapple");
setPadding(new Insets(10));
getChildren().addAll(field, list);
field.setOnDragOver(ev -> {
if (ev.getDragboard().hasString()) {
ev.acceptTransferModes(TransferMode.COPY);
}
ev.consume();
});
field.setOnDragDropped(ev -> {
field.setText(ev.getDragboard().getString());
ev.setDropCompleted(true);
ev.consume();
});
}
}
public static class DnDCell extends TextFieldListCell<String> {
public DnDCell(ListView<String> listView) {
setOnDragDetected(ev -> {
Dragboard dragboard = startDragAndDrop(TransferMode.COPY);
ClipboardContent cc = new ClipboardContent();
cc.putString(listView.getItems().get(getIndex()));
dragboard.setContent(cc);
ev.consume();
});
}
}
}
Tested on JavaFX 11.0.2 from Gluon on Ubuntu Linux 18.04 with additional
JVM runtime option -Djdk.gtk.version=2.
What I have so far:
When I press for example the C key button, this happens:
First item starts with C is selected.
The selectOptionOnKey (see below) function selected the option that starts with letter C.
The problem:
The combo box stores more option that can be displayed at once. So when the option which is selected is not in the displayed area I want the combo box to scroll down/jump to that option but I don't know how to do that.
Selected an option by pressing a letter key - option is not in the displayed area. - This will happen with the current code.
Selected an option by pressing a letter key - option is not in the displayed area. - This is what I want to happen!
Sample code:
Main:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root, 850.0, 650.0);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller:
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.SingleSelectionModel;
import javafx.scene.input.KeyCode;
public class SampleController implements Initializable {
#FXML private ComboBox<String> cb;
//Entered random options
private final ObservableList<String> options = FXCollections.observableArrayList(
"Aab",
"Aer",
"Aeq",
"Arx",
"Byad",
"Csca",
"Csee",
"Cfefe",
"Cead",
"Defea",
"Dqeqe",
"Fefaf",
"Gert",
"Wqad",
"Xsad",
"Zzz"
);
#Override
public void initialize(URL location, ResourceBundle resources) {
cb.getItems().addAll(options);
selectOptionOnKey();
}
/* When you press a letter key
* this method will search for an option(item) that starts with the input letter key
* and it selects the first occurrence in combo box
*/
public void selectOptionOnKey() {
cb.setOnKeyPressed(e -> {
KeyCode keyCode = e.getCode();
if (keyCode.isLetterKey()) {
char key = keyCode.getName().charAt(0);
SingleSelectionModel<String> cbSelectionModel = cb.getSelectionModel();
cbSelectionModel.select(0);
for (int i = 0; i < options.size(); i++) {
if(cbSelectionModel.getSelectedItem().charAt(0) == key) {
// option which starts with the input letter found -> select it
cbSelectionModel.select(i);
/* Before exiting the function it would be nice if after the selection,
the combo box would auto slide/jump to the option which is selected.
I don't know how to do that. */
return;
}
else
cbSelectionModel.selectNext();
}
}
});
}
}
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="SampleController">
<children>
<ComboBox fx:id="cb" layoutX="300.0" layoutY="300.0" prefHeight="25.0" prefWidth="173.0" />
</children>
</AnchorPane>
Any help is much appreciated.
As general behaviour, selection in a virtual control does not scroll the selected index/item into the visible region. Slightly astonished that the list in a comboBox' dropdown is no exception to that rule - would have expected at the one that's selected on opening to be visible.
The way out is to scroll the newly selected item in code. This involves:
get hold of the comboBox' skin
get the listView by skin.getPopupContent(): while that method is public, its return type is an implementation detail ..
call list.scrollTo(index)
A code snippet, could be called whenever the selection changed, f.i. in your key handler:
cbSelectionModel.select(i);
ComboBoxListViewSkin<?> skin = (ComboBoxListViewSkin<?>) cb.getSkin();
ListView<?> list = (ListView<?>) skin.getPopupContent();
list.scrollTo(i);
How to bind in JavaFx a textField with others textFields. For Example
textFieldTotal.textProperty.bind(Bindings.multiply(textFieldAmount.textProperty,
textFieldPrice.textProperty));
You question is pretty vague, but I'm going to take a guess. Basically, you need to create some additional Property and Binding objects.
First, create properties for your two TextField nodes. Then, you'll bind them using a StringConverter to convert the text entered into doubles.
Finally, create a "total" property that multiplies the two fields together and displays them in a Label.
Here's a very simple application to test out:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;
import javafx.util.converter.DoubleStringConverter;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
// Quantity
HBox hBoxQuantity = new HBox(5);
hBoxQuantity.setAlignment(Pos.CENTER);
TextField txtQuantity = new TextField();
hBoxQuantity.getChildren().addAll(
new Label("Quantity:"),
txtQuantity
);
// Price
HBox hBoxPrice = new HBox(5);
hBoxPrice.setAlignment(Pos.CENTER);
TextField txtPrice = new TextField();
hBoxPrice.getChildren().addAll(
new Label("Price:"),
txtPrice
);
// Total
HBox hBoxTotal = new HBox(5);
hBoxTotal.setAlignment(Pos.CENTER);
Label lblTotal = new Label();
hBoxTotal.getChildren().addAll(
new Label("Total: $"),
lblTotal
);
// Properties used for bindings
DoubleProperty price = new SimpleDoubleProperty();
DoubleProperty quantity = new SimpleDoubleProperty();
DoubleProperty total = new SimpleDoubleProperty();
// Bind the total to price x quantity
total.bind(price.multiply(quantity));
// Setup the converters to get the input from the textfields
StringConverter<? extends Number> converter = new DoubleStringConverter();
// Bind the text field entries to their properties
Bindings.bindBidirectional(txtPrice.textProperty(), price, (StringConverter<Number>) converter);
Bindings.bindBidirectional(txtQuantity.textProperty(), quantity, (StringConverter<Number>) converter);
// Bind the total label
lblTotal.textProperty().bind(total.asString());
// Add all nodes to stage
root.getChildren().addAll(hBoxPrice, hBoxQuantity, hBoxTotal);
// Show the stage
primaryStage.setWidth(300);
primaryStage.setHeight(300);
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
}
The Result:
Is this what you had in mind?
Note: This obviously does not include any error checking or restrictions on input, so you'll receive an error message if entering a non-numeric String in either TextField.
Now, I've looked around for a while, but I haven't found anything that helps me. I'm trying to create a chat-based game, which utilizes JavaFX-FXML and relies on a ScrollPane.
I'm trying to create JLabels and add them to the ScrollPane dynamically.
With my own research I found that you can't set multiple children for a ScrollPane; you have to use the setContent method and have a pane to add the children inside of that, so that's what I did but I still get an error when adding the labels. It's inside the IDE and tells me I have to use a Node but I don't know what a node is.
Here's my controller:
public class Controller() {
import javax.swing.*;
import javafx.fxml.FXML;
import javafx.scene.input.*;
import javafx.scene.layout.Pane;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import static jdk.nashorn.internal.objects.NativeError.printStackTrace;
private String msg;
private char[] msgA;
#FXML
private Label opt1;
#FXML
private Label opt2;
#FXML
private Label opt3;
#FXML
private TextField msgBox;
#FXML
private AnchorPane gameUI;
#FXML
private AnchorPane mainMenu;
#FXML public ScrollPane labelPane;
private boolean optionSelected = false;
private void startup(){
System.out.println("startup called! Getting player's name now..");
String mcName=JOptionPane.showInputDialog(null,"Please enter your name");
System.out.println(mcName+" was inputted, let's hope it's an appropriate name! Haha!");
JLabel label = new JLabel();
label.setName("evieHi");
label.setText("Hi "+mcName+"! How are you doing?");
labelPane.setContent(p);
opt1.setText("I'm good, how are you?");
opt2.setText("Not so well until you texted. ;D");
opt3.setText("I'm sorry, who is this?");
Pane p = new Pane();
p.getChildren().add(label);
}
}
I do realize some of the imports and variables are redundant. They're not relevant to my question so I left the methods using them out of my code I included.
Thanks in advance and I'm sorry you had to read my messy code.
Attempting to create a Swing UI component doesn't bode well with JavaFX...
I fixed it with the help of #James_D and #fabian pointing out what I'm to dumb to realize..
private void startup(){
System.out.println("startup called! Getting player's name now..");
mcName=JOptionPane.showInputDialog(null,"Please enter your name");
System.out.println(mcName+" was inputted,let's hope it's an appropriate name! Haha!");
Label label = new Label();
label.setText("Hi "+mcName+"! How are you doing?");
p.getChildren().add(label);
labelPane.setContent(p);
}