I have this very simple example of GridPane.
GridPane playerGrid = new GridPane();
Text title = new Text("Top Scorers in English Premier League");
title.setFont(Font.font("Arial", FontWeight.BOLD, 20));
playerGrid.add(title, 0,0,4,1);
How I can select the text with the mouse and copy it when the program is running?
Text nodes in JavaFX are not selectable.
If you want to have text selectable, use a selection aware control.
The fact that the text is eventually placed in a GridPane is irrelevant to this question.
For example, use a read only TextField:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class SelectableTextSample extends Application {
#Override public void start(final Stage stage) throws Exception {
stage.setScene(
new Scene(
new SelectableText(
"Top Scorers in English Premier League"
)
)
);
stage.show();
}
class SelectableText extends TextField {
SelectableText(String text) {
super(text);
setEditable(false);
setPrefColumnCount(20);
}
}
public static void main(String[] args) {
Application.launch(args);
}
}
Alternate solution
You could use a WebView if you wish. For some situations that may be a better solution, but for others it may not.
Related
I am making a login GUI and after I enter the username, I want to hit ENTER key and it will select the password text field. How can I achieve this?
My attempt:
#FXML
void userNameKeyPressed(KeyEvent event) {
if(event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB) {
passWord.requestFocus();
}
}
I think you'll need to compile a more complete example. Eg maybe a simple fxml and where it goes wrong. Here is an example that works, and it uses most of the ingredients you are.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import javafx.scene.input.KeyEvent;
public class TextFields extends Application{
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("text field");
TextField a = new TextField();
TextField b = new TextField();
a.setOnKeyPressed( evt ->{
System.out.println(KeyCode.ENTER + ", " + evt.getCode());
if(evt.getCode().equals(KeyCode.ENTER)){
System.out.println("entered");
b.requestFocus();
}
});
BorderPane root = new BorderPane();
root.setLeft(a);
root.setRight(b);
primaryStage.setScene(new Scene(root, 300, 100));
primaryStage.show();
}
}
This code creates a frame with 2 text fields, if you press enter in the left one, you will move to the right one.
I'm creating a simple lottery game where I can chose numbers from 1 to 42. I would like to mark the chosen number with a red "X" (instead of using an effect) but the user should still see the chosen number beneath the "X". When the user clicks the marked number again, the "X" should disappear.
The GUI looks like this:
enter image description here
How can I display a second text on a button in the way that the first text is still visible?
Thanks for your help
kind regards
Joel
You can set the Graphic of a button to a StackPane and then add an element to the StackPane. Since the children of a StackPane are all displayed on top of each other, this yields the effect that you want. My example just shows the concept, I would probably write a new class that extends Button in your use scenario :)
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
public class NewFXMain extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Pane pane = new Pane();
StackPane buttonPane = new StackPane();
Label label = new Label("42");
buttonPane.getChildren().add(label);
Button button = new Button();
button.setGraphic(buttonPane);
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if(buttonPane.getChildren().size() == 1){
Label labelX = new Label("X");
labelX.setStyle("-fx-text-fill: red;");
buttonPane.getChildren().add(labelX);
}
else
buttonPane.getChildren().remove(1);
}
});
pane.getChildren().addAll(button);
primaryStage.setScene(new Scene(pane, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I have a very large StackPane(3000x2000) inside of a ScrollPane. The idea is to use it like a large "drawing board", in which users can create nodes and drag them around, for creating Mindmaps and such. The problem is drag and drop: It works fine if the scrollPane is in its "start position", so that both Hvalue and Vvalue are 0. But once you scrolled a bit, the values that DragEvent.getX() and .getY() return are relative to the visible part of the pane, not to its entire size. That means you cannot drag and drop something properly. I created a test class to illustrate the problem without any obsolete code:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class DragTestClass extends Application{
public static void problem(Circle circle, ScrollPane scrollPane, StackPane pane, DataFormat dataFormat){
circle.setOnDragDetected(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
Dragboard db = circle.startDragAndDrop(TransferMode.ANY);
ClipboardContent content = new ClipboardContent();
content.put(dataFormat,0); // normally, ID of node
db.setContent(content);
event.consume();
}
});
scrollPane.setOnDragDropped(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
Dragboard db = event.getDragboard();
if(db.hasContent(dataFormat) && db.getContent(dataFormat) instanceof Integer){
int index = (Integer) db.getContent(dataFormat);
Circle node = (Circle) pane.getChildren().get(index);
node.setManaged(false);
// this is the problematic part
node.setTranslateX(event.getX() - node.getCenterX());
node.setTranslateY(event.getY() - node.getCenterY());
event.setDropCompleted(true);
event.consume();
}
}
});
scrollPane.setOnDragOver(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
event.acceptTransferModes(TransferMode.ANY);
event.consume();
}
});
}
#Override
public void start(Stage primaryStage) throws Exception {
ScrollPane scrollPane = new ScrollPane();
StackPane pane = new StackPane();
DataFormat dataFormat = new DataFormat("DragDropFormat");
int width = 1000;
int height = 1000;
pane.setMinHeight(height);
pane.setMaxHeight(height);
pane.setMinWidth(width);
pane.setMaxWidth(width);
Circle circle = new Circle(50,50,20); // normally a StackPane
circle.setManaged(false);
pane.getChildren().add(circle);
pane.setAlignment(Pos.TOP_LEFT);
scrollPane.setContent(pane);
problem(circle, scrollPane, pane, dataFormat);
Scene scene = new Scene(scrollPane, 400, 400);
primaryStage.setTitle("Problem");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
My idea was to add something to the translation of the nodes, like scrollPane.getHvalue() * width, but that doesn't seem to be working. Maybe I just googled the wrong keywords, but I haven't found anything helpful, so I'm sorry if the question was answered elsewhere. Thanks in advance for your help!
I figured it out! Setting the EventHandler on the StackPane (the content of the ScrollPane, instead of the ScrollPane itself) did the trick. Apparently, the coordinates that event.getX() returns are relative to the node that has the EventHandler. In this example:
pane.setOnDragDropped...
In HTMLEditor of JavaFX: the preview color is so small.
I want to show bigger like picture below:
How i can do.
Thanks
The style of the HTMLEditor is customized via CSS.
.html-editor-foreground {
-fx-color-rect-width: 16;
-fx-color-rect-height: 16;
-fx-graphic: null;
}
Here we style the foreground color picker picked color indicator as a (relatively) large rectangle (with a pink color chosen for the sample):
Sample Code
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.web.HTMLEditor;
import javafx.stage.Stage;
public class EditorSample extends Application {
#Override
public void start(Stage stage) throws Exception {
HTMLEditor editor = new HTMLEditor();
Scene scene = new Scene(editor);
scene.getStylesheets().add(
this.getClass().getResource(
"html-editor-large-color-rect.css"
).toExternalForm()
);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I am using JavaFX SplitPanes on my application and I need to change the divider positions when the height and width changes, because I want to keep the divider positions fixed. My code is as follows:
scene.widthProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observableValue, Number oldSceneWidth, Number newSceneWidth) {
GUIController.resetMainSplitPane();
}
});
scene.heightProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observableValue, Number oldSceneHeight, Number newSceneHeight) {
GUIController.resetMusicSplitPane();
}
});
and the resetSplitPane methods:
public static void resetMusicSplitPane() {
musicSplitPane.setDividerPosition(0, 0.7);
Util.err("height changed");
}
I do get the message 'height changed' however the divider positions have not been changed at all. I think this has something to do with JavaFX performing gui changes which override my changes. In other words; I change the divider position but JavaFX changes it back because its performing layout changes responding to the resizing of the window.
Normally, divider automatically adjusts itself whenever the scene is resized (i.e. the size of both sides of the divider increases/decreases). The only reason I can think of, on why, you are trying to set divider position, is not to increase or decrease the height/width of one side of the Divider. This can be achieved by using
SplitPane.setResizableWithParent(paneToBeFixed, Boolean.FALSE);
A small example to show how it works, (example given by Sergey in here)
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class TestObjectArray extends Application {
#Override
public void start(Stage stage) {
final SplitPane root = new SplitPane();
final Pane paneFixed = new StackPane();
paneFixed.getChildren().add(new Text("Fixed"));
SplitPane.setResizableWithParent(paneFixed, Boolean.FALSE);
Pane paneFree = new StackPane();
paneFree.getChildren().add(new Text("Free"));
root.getItems().addAll(paneFixed, paneFree);
Scene scene = new Scene(root, 300, 200);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}