I have this whole mess of Controls and Transitions in the Scene, and whenever an error or message is made, I call FormBuilder.say(String x).
The sample included doesn't error as much, because it's empty. But when all the stuff are active, the pop up from FormBuilder.say(String x) comes out as a mess.
If I wait long enough, attempt to interact, or if I minimize then restore the Stage, it loads properly. But many times, it's just blank.
My laptop runs Ubuntu 15.10, with approx 2GB RAM. No Video Card.
Included is a screen cap of the messy picture.
Included is the code that's affected during the bug. I've striped out some of the less suspected parts. (EDITED)
package solo;
import javafx.animation.Animation;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
import javafx.util.Duration;
public class FormBuilder extends Application{
Stage ps;
public FormBuilder(){
}
public void begin(String[] args){
launch(args);
}
public void start(Stage primaryStage) {
ps = primaryStage;
ps.setTitle("E-VIL v0.0");
ps.setScene(new Scene(scene(), 800, 600));
ps.show();
}
public void say(String things){
Stage stage = new Stage(StageStyle.UTILITY);
stage.initOwner(ps);
Text text = new Text(things);
Button btn = new Button("Okay");
btn.setOnAction(e -> {stage.close();});
VBox pane = new VBox(text,btn);
pane.setAlignment(Pos.TOP_CENTER);
text.setLayoutY(12);
pane.autosize();
stage.setScene(new Scene(pane));
stage.sizeToScene();
stage.setOnShown(e -> {stage.requestFocus();});
stage.showAndWait();
}
public Pane scene(){
Pane pn = new Pane();
Button btn = new Button("Say Something");
btn.setOnAction(e->{FormBuilder.this.say("Something");});
btn.setLayoutX(0);
btn.setLayoutY(10);
pn.getChildren().add(btn);
pn.sceneProperty().addListener(new ChangeListener<Scene>(){
#Override
public void changed(ObservableValue<? extends Scene> arg0, Scene arg1, Scene arg2) {
System.out.println("new Scene");
if(arg2 != null)
arg2.windowProperty().addListener(new ChangeListener<Window>(){
#Override
public void changed(ObservableValue<? extends Window> observable, Window oldValue,
Window newValue) {
System.out.println("new window");
if(newValue != null){
Rectangle rect = new Rectangle(0,30,300,300);
rect.setFill(Color.RED);
pn.getChildren().add(rect);
Rectangle box = new Rectangle(30,60,50,50);
TranslateTransition tt = new TranslateTransition(Duration.seconds(1), box);
tt.setByX(160);
tt.setByY(160);
tt.setAutoReverse(true);
tt.setCycleCount(Animation.INDEFINITE);
pn.getChildren().add(box);
tt.play();
}
}
});
}
});
return pn;
}
}
package solo;
public class Main {
public static void main(String args[]){
FormBuilder fb = new FormBuilder();
fb.begin(args);
}
}
Related
I try to use vlcj-javafx-demo to develop a video player, and I put the progress bar(Slider) on the StackPane over the video layer. In the beginning, it looks work well, but when I set maximum or full screen the app, it looks some components UI did not update correctly. How can I correct it?
Thanks a lot!
normally:
[1]: https://i.stack.imgur.com/bbE51.png
normally:
[2]: https://i.stack.imgur.com/Plsb1.png
the red color is the sence background color.
the code :
package my.javafx.myplayer;
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Slider;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
import uk.co.caprica.vlcj.factory.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.base.MediaPlayer;
import uk.co.caprica.vlcj.player.base.MediaPlayerEventAdapter;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import java.util.ArrayList;
import java.util.List;
import static uk.co.caprica.vlcj.javafx.videosurface.ImageViewVideoSurfaceFactory.videoSurfaceForImageView;
/**
*
*/
public class VlcjJavaFxApplication extends Application {
private final MediaPlayerFactory mediaPlayerFactory;
private final EmbeddedMediaPlayer embeddedMediaPlayer;
private ImageView videoImageView;
Slider progress=new Slider();
public VlcjJavaFxApplication() {
this.mediaPlayerFactory = new MediaPlayerFactory();
this.embeddedMediaPlayer = mediaPlayerFactory.mediaPlayers().newEmbeddedMediaPlayer();
this.embeddedMediaPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() {
#Override
public void mediaPlayerReady(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer) {
Platform.runLater(()->{
progress.setValue(0);
progress.setMax(embeddedMediaPlayer.media().info().duration());
progress.setMin(0);
});
}
#Override
public void playing(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer) {
}
#Override
public void paused(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer) {
}
#Override
public void stopped(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer) {
}
#Override
public void timeChanged(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer, long newTime) {
Platform.runLater(()->{
progress.setValue(newTime);
});
}
});
}
#Override
public void init() {
this.videoImageView = new ImageView();
this.videoImageView.setPreserveRatio(true);
embeddedMediaPlayer.videoSurface().set(videoSurfaceForImageView(this.videoImageView));
}
#Override
public final void start(Stage primaryStage) throws Exception {
List<String> params = new ArrayList<String>();
params.add("/Users/baixq/Downloads/妙味课堂xhtml+css2/妙味课堂-XHTMLCSS2整站视频教程-4.avi");
if (params.size() != 1) {
System.out.println("Specify a single MRL");
System.exit(-1);
}
StackPane root=new StackPane();
//BorderPane root = new BorderPane();
root.setStyle("-fx-background-color: black;");
videoImageView.fitWidthProperty().bind(root.widthProperty());
videoImageView.fitHeightProperty().bind(root.heightProperty());
root.widthProperty().addListener((observableValue, oldValue, newValue) -> {
// If you need to know about resizes
});
root.heightProperty().addListener((observableValue, oldValue, newValue) -> {
// If you need to know about resizes
});
Scene scene = new Scene(root, 1200, 675, Color.RED);
primaryStage.setTitle("vlcj JavaFX");
primaryStage.setScene(scene);
AnchorPane contrlBox=new AnchorPane();//操作面板上的控制模块
contrlBox.prefWidthProperty().bind(root.widthProperty());
contrlBox.prefHeightProperty().bind(root.heightProperty().multiply(0.1));
BorderPane controlBar=new BorderPane();
controlBar.setStyle("-fx-background-color: #130c0e;");
controlBar.prefWidthProperty().bind(root.widthProperty());
controlBar.prefHeightProperty().bind(root.heightProperty().multiply(0.1));
controlBar.setCenter(progress);
Button fullScreen=new Button("全屏");
controlBar.setRight(fullScreen);
contrlBox.getChildren().add(controlBar);
contrlBox.setBottomAnchor(controlBar, 0.0);
root.getChildren().addAll(videoImageView,contrlBox);
primaryStage.show();
embeddedMediaPlayer.media().play(params.get(0));
fullScreen.setOnAction(event->{
primaryStage.setFullScreen(true);
});
root.setOnMouseEntered(event->{
Platform.runLater(()->{
FadeTransition ft = new FadeTransition(Duration.millis(500), contrlBox);
ft.setFromValue(0.0);
ft.setToValue(1);
//ft.setCycleCount(Timeline.INDEFINITE);
ft.setAutoReverse(false);
ft.play();
contrlBox.setVisible(true);
});
});
root.setOnMouseExited(event->{
Platform.runLater(()->{
FadeTransition ft = new FadeTransition(Duration.millis(500), contrlBox);
ft.setFromValue(1);
ft.setToValue(0.0);
ft.setAutoReverse(false);
ft.play();
contrlBox.setVisible(false);
});
});
//embeddedMediaPlayer.controls().setPosition(0.4f);
}
#Override
public final void stop() {
embeddedMediaPlayer.controls().stop();
embeddedMediaPlayer.release();
mediaPlayerFactory.release();
}
public static void main(String[] args) {
launch(args);
}
}
You appear to be using a Linux OS, try passing one or more of these system properties when you start your JVM:
-Dprism.dirtyopts=false
-Dprism.forceUploadingPainter=true
This is mentioned under "Linux notes" here: https://github.com/caprica/vlcj-javafx-demo/tree/vlcj-5.x
I have seen similar painting glitches on Linux before and in all cases using these properties, at least for me, clears the issue with only a small hit to performance - even when doing something like a full-screen grid of nine concurrent media players, where each one had an animating video controls overlay.
Is there any way to manage the z-index ordering of multiple stages (independent to each other). Something like, say there are three Stages A, B & C. StageA should stay always at back. StageB should be in middle and StageC should be always on top. Just a special note that these three stages have no relation to each other (like owner)
Below is a quick demo of what I am expecting. I need to access any stage (for dragging or modifying) but z-order need to be maintained. Any ideas or help is highly appreciated.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.HashMap;
import java.util.Map;
public class StagesZOrdering_Demo extends Application {
private Map<String, Stage> stages = new HashMap<>();
#Override
public void start(Stage stage) throws Exception {
Button button1 = new Button("Back");
button1.setOnAction(e -> openStage("Back"));
Button button2 = new Button("Middle");
button2.setOnAction(e -> openStage("Middle"));
Button button3 = new Button("Front");
button3.setOnAction(e -> openStage("Front"));
VBox root = new VBox(button1, button2, button3);
root.setAlignment(Pos.CENTER);
root.setSpacing(10);
Scene sc = new Scene(root, 200, 200);
stage.setScene(sc);
stage.show();
}
private void openStage(String title) {
if (stages.get(title) != null) {
stages.get(title).requestFocus();
} else {
Stage stg = new Stage();
stg.setTitle(title);
stg.setScene(new Scene(new StackPane(), 300, 300, Color.GRAY));
stg.show();
stg.setOnHidden(e -> stages.remove(title));
stages.put(title, stg);
}
}
public static void main(String... a) {
Application.launch(a);
}
}
The following mcve demonstrates re-ordering of back-to-front stages, once a ROOT MOUSE_EXITED_TARGET event is fired from one of them.
It is a simple yet limited solution:
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventType;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class StagesZOrdering_Demo extends Application {
public enum STAGES {BACK, MIDDLE, FRONT;}
private final EnumMap<STAGES, Stage> stages = new EnumMap<>(STAGES.class);
#Override
public void start(Stage stage) throws Exception {
VBox root = new VBox();
for(STAGES s : STAGES.values()){
Button button = new Button(s.name());
button.setOnAction(e -> openStage(s));
root.getChildren().add(button);
}
root.setAlignment(Pos.CENTER);
root.setSpacing(10);
Scene sc = new Scene(root, 200, 200);
stage.setScene(sc);
stage.show();
}
private void openStage(STAGES s) {
if (stages.get(s) == null) {
Stage stg = new Stage();
stg.setTitle(s.name());
stg.addEventHandler(EventType.ROOT, e->reOrder(e));
stg.setScene(new Scene(new StackPane(), 300, 100, Color.GRAY));
stg.show();
stg.setOnHidden(e -> stages.remove(s));
stages.put(s, stg);
}
}
private void reOrder(Event e){
if(! e.getEventType().getName().equals("MOUSE_EXITED_TARGET"))
return;
for(STAGES s : STAGES.values()){
Stage stage = stages.get(s);
if(stage != null) {
stage.requestFocus();
}
}
}
public static void main(String... a) {
Application.launch(a);
}
}
I am trying to run this application in which I used event-handling and it won't compile and won't show anything. I am currently using NetBeans 8.1. What is that I did wrong. Also it is not showing any errors.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class event extends Application {
public void start(Stage primaryStage)
{
HBox pane = new HBox();
pane.setAlignment(Pos.CENTER);
Button btOk = new Button("OK");
Button btCancel = new Button("Cancel");
OkHandlerClass handler1 = new OkHandlerClass();
btOk.setOnAction(handler1);
CancelHandlerClass handler2 = new CancelHandlerClass();
pane.getChildren().addAll(btOk, btCancel);
Scene scene = new Scene(pane);
primaryStage.setTitle("Handle the fucking event");
primaryStage.setScene(scene);
primaryStage.show();
}
class OkHandlerClass implements EventHandler<ActionEvent>{
public void handle(ActionEvent e) {
System.out.println("OK button clicked");
}
}
class CancelHandlerClass implements EventHandler<ActionEvent>{
public void handle(ActionEvent event) {
System.out.println("Cancel button clicked");
}
}
public static void main(String[] args) {
launch(args);
}
}
I'm trying to create image gallery and use some image animations. Problem is with ImageView. I would like to play() RotateTransition from some method and call this method any time but it's not working at all. There should be some issue with threads but even if it is called from new thread nothing is happening. Is there any solution how to work with ImageView and Transitions generally?
public class ImageGallery extends ImageView{
RotateTransition rt;
public ImageGallery() {
setImage(new Image("/img/01.jpg"));
setPreserveRatio(true);
rt = new RotateTransition(Duration.millis(800), this);
rt.setByAngle(90);
//this works but not what I need
//fitWidthProperty().addListener(e -> rt.play());
}
public void rotateRight(){
rt.play(); //nothing
//run later is not working too
//Platform.runLater(new ViewTransition(this));
}
}
Thanks
As per user comments in the question, adding a MCVE
Main.java
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
ImageGallery gallery = new ImageGallery();
VBox box= new VBox(gallery);
box.setAlignment(Pos.CENTER);
Scene scene = new Scene(box, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
gallery.rotateRight();
}
public static void main(String[] args){
launch(args);
}
}
ImageGallery.java
import javafx.animation.RotateTransition;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.util.Duration;
public class ImageGallery extends ImageView{
RotateTransition rt;
public ImageGallery() {
setImage(new Image("http://jaxenter.com/wp-content/uploads/2013/03/javafx.1.png"));
setPreserveRatio(true);
rt = new RotateTransition(Duration.millis(800), this);
rt.setByAngle(90);
}
public void rotateRight(){
rt.play();
}
}
I'm working with RichTextFx's CodeArea to highlight custom mini language code.
Now while executing this code I want to show a small arrow in front of current executed line. I know the specific line number but can't get anything to happen with the line number label.
Since github project claims showing line numbers or breakpoint toggles as a feature this can't be very difficult. But can't get anything to work...
Thanks in advance
To show any graphic in front of the line, you need to set the "paragraph graphic factory" of the CodeArea. This graphic factory is just a function int -> Node: given the line number, it returns a Node that will be displayed in front of the line.
Here is a graphic factory that produces a green triangle pointing at the line. It will only be shown when the line is equal to the given integer property shownLine.
class ArrowFactory implements IntFunction<Node> {
private final ObservableValue<Integer> shownLine;
ArrowFactory(ObservableValue<Integer> shownLine) {
this.shownLine = shownLine;
}
#Override
public Node apply(int lineNumber) {
Polygon triangle = new Polygon(0.0, 0.0, 10.0, 5.0, 0.0, 10.0);
triangle.setFill(Color.GREEN);
ObservableValue<Boolean> visible = Val.map(
shownLine,
sl -> sl == lineNumber);
triangle.visibleProperty().bind(visible.conditionOnShowing(triangle));
return triangle;
}
}
Each graphic (i.e. little green triangle) you create will be observing the given shownLine property to decide whether it should be visible. As lines, and therefore line graphics, come and go, it is important to remove the listener of shownLine when the graphic is no longer used. visible.conditionOnShowing(triangle) is a new property that will stop observing the visible property (and automatically also the shownLine property, thanks to ReactFX's lazy binding semantics) and reset to constant false whenever the triangle is not part of a showing window. So we don't cause memory or CPU leaks due to uncleaned listeners.
Here is a complete runnable demo that uses this ArrowFactory combined with the LineNumberFactory provided by RichTextFX to show both line numbers and a little triangle. This demo uses the CodeArea's current line as the shownLine property. You will want to substitute it for a property that contains the current line of execution.
import java.util.function.IntFunction;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.stage.Stage;
import org.fxmisc.richtext.CodeArea;
import org.fxmisc.richtext.LineNumberFactory;
import org.reactfx.value.Val;
public class CodeAreaWithLineIndicator extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
CodeArea codeArea = new CodeArea();
IntFunction<Node> numberFactory = LineNumberFactory.get(codeArea);
IntFunction<Node> arrowFactory = new ArrowFactory(codeArea.currentParagraphProperty());
IntFunction<Node> graphicFactory = line -> {
HBox hbox = new HBox(
numberFactory.apply(line),
arrowFactory.apply(line));
hbox.setAlignment(Pos.CENTER_LEFT);
return hbox;
};
codeArea.setParagraphGraphicFactory(graphicFactory);
primaryStage.setScene(new Scene(new StackPane(codeArea), 600, 400));
primaryStage.show();
}
}
class ArrowFactory implements IntFunction<Node> {
private final ObservableValue<Integer> shownLine;
ArrowFactory(ObservableValue<Integer> shownLine) {
this.shownLine = shownLine;
}
#Override
public Node apply(int lineNumber) {
Polygon triangle = new Polygon(0.0, 0.0, 10.0, 5.0, 0.0, 10.0);
triangle.setFill(Color.GREEN);
ObservableValue<Boolean> visible = Val.map(
shownLine,
sl -> sl == lineNumber);
triangle.visibleProperty().bind(visible.conditionOnShowing(triangle));
return triangle;
}
}
And this is the result:
Working example
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.stage.Stage;
import org.fxmisc.richtext.CodeArea;
import org.fxmisc.richtext.LineNumberFactory;
import org.reactfx.value.Val;
import java.util.function.IntFunction;
public class CodeAreaWithLineIndicator extends Application {
CodeArea codeArea;
TextField textField;
public static final IntegerProperty lineValue = new SimpleIntegerProperty(-1) ;
/* public final int getValue() {
return value.get();
}*/
/* public final void setValue(int value) {
this.value.set(value);
}*/
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
codeArea = new CodeArea();
codeArea.replaceText(0,0,"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
codeArea.setPrefHeight(400);
IntFunction<Node> numberFactory = LineNumberFactory.get(codeArea);
IntFunction<Node> arrowFactory = new ManualArrowFactory(lineValue);
IntFunction<Node> graphicFactory = line -> {
HBox hbox = new HBox(
numberFactory.apply(line),
arrowFactory.apply(line));
hbox.setAlignment(Pos.CENTER_LEFT);
return hbox;
};
codeArea.setParagraphGraphicFactory(graphicFactory);
VBox vbox = new VBox();
textField = new TextField();
textField.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
try {
lineValue.setValue(Integer.parseInt(textField.getText()));
} catch (NumberFormatException e) {
}
}
});
Button button = new Button("MoveIt");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
try {
lineValue.setValue(Integer.parseInt(textField.getText()));
} catch (NumberFormatException e) {
}
}
});
vbox.getChildren().addAll(textField, button, codeArea);
Scene scene = new Scene(vbox, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
class ManualArrowFactory implements IntFunction<Node> {
private final IntegerProperty shownLine;
public ManualArrowFactory(IntegerProperty shownLine) {
this.shownLine = shownLine;
}
#Override
public Node apply(int lineNumber) {
Polygon triangle = new Polygon(0.0, 0.0, 10.0, 5.0, 0.0, 10.0);
triangle.setFill(Color.GREEN);
ObservableValue<Boolean> visible = Val.map(shownLine, sl -> sl.intValue()-1 == lineNumber);
triangle.visibleProperty().bind(
Val.flatMap(triangle.sceneProperty(), scene -> {
return scene != null ? visible : Val.constant(false);
}));
return triangle;
}
}
}
For multiline implementation:
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import org.fxmisc.richtext.CodeArea;
import org.fxmisc.richtext.LineNumberFactory;
import org.reactfx.value.Val;
import java.util.function.IntFunction;
public class CodeAreaWithLineIndicator extends Application {
CodeArea codeArea;
TextField textField;
public static final IntegerProperty lineValue = new SimpleIntegerProperty(-1) ;
public static final ObservableList<Integer> olistValue = FXCollections.observableArrayList();
public static final ListProperty<Integer> listValue = new SimpleListProperty<Integer>(olistValue);
/* public final int getValue() {
return value.get();
}*/
/* public final void setValue(int value) {
this.value.set(value);
}*/
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
codeArea = new CodeArea();
codeArea.replaceText(0,0,"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
codeArea.setPrefHeight(400);
IntFunction<Node> numberFactory = LineNumberFactory.get(codeArea);
IntFunction<Node> arrowFactory = new MultiBreakPointFactory(listValue);
IntFunction<Node> graphicFactory = line -> {
HBox hbox = new HBox(
numberFactory.apply(line),
arrowFactory.apply(line));
hbox.setAlignment(Pos.CENTER_LEFT);
return hbox;
};
codeArea.setParagraphGraphicFactory(graphicFactory);
VBox vbox = new VBox();
textField = new TextField();
textField.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
int newValue = Integer.parseInt(textField.getText());
olistValue.add(newValue);
}
});
Button button = new Button("Clear");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
olistValue.clear();
}
});
vbox.getChildren().addAll(textField, button, codeArea);
Scene scene = new Scene(vbox, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
class MultiBreakPointFactory implements IntFunction<Node> {
private final ListProperty<Integer> shownLines;
public MultiBreakPointFactory(ListProperty<Integer> shownLine) {
this.shownLines = shownLine;
}
#Override
public Node apply(int lineIndex) {
StackPane stackPane = new StackPane();
Circle circle = new Circle(10.0, 10.0, 6.0, Color.RED);
Rectangle rectangle = new Rectangle(20,20);
rectangle.setFill(Color.TRANSPARENT);
rectangle.setCursor(Cursor.HAND);
rectangle.setOnMouseClicked(me->{
if (!olistValue.contains(lineIndex+1)){
olistValue.add(lineIndex+1);
}
});
stackPane.getChildren().addAll(rectangle, circle);
circle.setOnMouseClicked(me->{
int index = olistValue.indexOf(lineIndex+1);
if (index>-1)
olistValue.remove(index);
});
circle.setCursor(Cursor.HAND);
ObservableValue<Boolean> visible = Val.map(shownLines, sl -> sl.contains(lineIndex+1));
circle.visibleProperty().bind(
Val.flatMap(circle.sceneProperty(), scene -> {
return scene != null ? visible : Val.constant(false);
}));
return stackPane;
}
}
}
Enter a number to textfield and click enter. Now only changing oListValue will show breakpoint lines on the codearea.