How to set minimum diameter to jfxtras circularpane. For example take a look at following code,
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import jfxtras.scene.layout.*;
/**
* AssistiveBall
*/
public class AssistiveBall extends Application
{
#Override
public void start(Stage pStage) throws Exception
{
StackPane root = new StackPane();
CircularPane pane = new CircularPane();
Scene scene = new Scene(root, 800, 600);
Button btn = new Button("Center");
Button[] buttons = new Button[13];
for (int i = 0; i < buttons.length; i++)
{
buttons[i] = new Button("" + i);
}
pane.getChildren().addAll(buttons);
btn.setOnAction(e -> {
if(pane.isVisible())
{
pane.setVisible(false);
}
else
{
pane.setVisible(true);
}
});
root.getChildren().add(pane);
root.getChildren().add(btn);
pStage.setScene(scene);
pStage.setTitle("Assistive Ball");
pStage.show();
}
public static void main( String[] args )
{
AssistiveBall.launch(args);
}
}
Here here code if fine, but if i use just 3 buttons it starts appear one on another, So how to set minimum diameter or there is any another way to do this ?
Thanks.
Version 11-r3-SNAPSHOT has changed certain methods like computeChainDiameter and determineBeadDiameter to protected, so you can override them and tune the output.
Related
I can listen for scroll events:
tableView.addEventFilter(javafx.scene.input.ScrollEvent.SCROLL,
new EventHandler<javafx.scene.input.ScrollEvent>() {
#Override
public void handle(final javafx.scene.input.ScrollEvent scrollEvent) {
System.out.println("Scrolled.");
}
});
But How can I be notified if the bottom/ top of the table is reached?
A simple way of doing this is to retrieve the ScrollBar using a lookup:
ScrollBar tvScrollBar = (ScrollBar) tableView.lookup(".scroll-bar:vertical");
You can then add a listener to check if it's reached the bottom (the valueProperty of the ScrollBar is represented by the percentage it's been scrolled, so 0.0 is the top and 1.0 is the bottom):
tvScrollBar.valueProperty().addListener((observable, oldValue, newValue) -> {
if ((Double) newValue == 1.0) {
System.out.println("Bottom!");
}
});
Below is a simple MCVE that demonstrates how to put it all together:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ScrollBarNotify extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Simple interface
VBox root = new VBox(5);
root.setPadding(new Insets(10));
root.setAlignment(Pos.CENTER);
// Simple TableView to demonstrate
TableView<String> tableView = new TableView<>();
TableColumn<String, String> column = new TableColumn<>("Text");
column.setCellValueFactory(f -> new SimpleStringProperty(f.getValue()));
tableView.getColumns().add(column);
// Add some sample items to our TableView
for (int i = 0; i < 100; i++) {
tableView.getItems().add("Item #" + i);
}
// Now, let's add a listener to the TableView's scrollbar. We can only access the ScrollBar after the Scene is
// rendered, so we need to do schedule this to run later.
Platform.runLater(() -> {
ScrollBar tvScrollBar = (ScrollBar) tableView.lookup(".scroll-bar:vertical");
tvScrollBar.valueProperty().addListener((observable, oldValue, newValue) -> {
if ((Double) newValue == 1.0) {
System.out.println("Bottom!");
}
});
});
// Finally, add the TableViewto our layout
root.getChildren().add(tableView);
// Show the Stage
primaryStage.setWidth(300);
primaryStage.setHeight(300);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
If you're using Java 10+ you can subclass TableViewSkin and get access to the VirtualFlow. The latter class has the position property which you can use to know if the top or bottom has been reached.
Here's an example using custom events:
MyEvent.java
import javafx.event.Event;
import javafx.event.EventType;
public class MyEvent extends Event {
public static final EventType<MyEvent> ANY = new EventType<>(Event.ANY, "MY_EVENT");
public static final EventType<MyEvent> TOP_REACHED = new EventType<>(ANY, "TOP_REACHED");
public static final EventType<MyEvent> BOTTOM_REACHED = new EventType<>(ANY, "BOTTOM_REACHED");
public MyEvent(EventType<? extends MyEvent> eventType) {
super(eventType);
}
}
MyTableViewSkin.java
import javafx.scene.control.TableView;
import javafx.scene.control.skin.TableViewSkin;
public class MyTableViewSkin<T> extends TableViewSkin<T> {
public MyTableViewSkin(TableView<T> control) {
super(control);
getVirtualFlow().positionProperty().addListener((obs, oldVal, newVal) -> {
if (newVal.doubleValue() == 0.0) {
control.fireEvent(new MyEvent(MyEvent.TOP_REACHED));
} else if (newVal.doubleValue() == 1.0) {
control.fireEvent(new MyEvent(MyEvent.BOTTOM_REACHED));
}
});
}
}
App.java
import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void start(Stage primaryStage) {
var table = new TableView<Integer>();
for (int i = 0; i < 250; i++) {
table.getItems().add(i);
}
var column = new TableColumn<Integer, Number>("Value");
column.setCellValueFactory(features -> new SimpleIntegerProperty(features.getValue()));
table.getColumns().add(column);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.setSkin(new MyTableViewSkin<>(table));
table.addEventHandler(MyEvent.ANY, event -> System.out.printf("%s%n", event.getEventType()));
primaryStage.setScene(new Scene(table, 500, 300));
primaryStage.setTitle("Example");
primaryStage.show();
}
}
In this example I manually call table.setSkin. Another option is to subclass TableView and override createDefaultSkin which returns the skin you want to use.
tableView.addEventFilter(javafx.scene.input.ScrollEvent.SCROLL,
new EventHandler<javafx.scene.input.ScrollEvent>() {
#Override
public void handle(final javafx.scene.input.ScrollEvent scrollEvent) {
Object virtualFlow = ((javafx.scene.control.SkinBase<?>) tableView.getSkin()).getChildren().get(1);
double position = -1;
try {
position = (double) virtualFlow.getClass().getMethod("getPosition").invoke(virtualFlow);
} catch (Exception ignored) { }
if(position == 0.0) {
System.out.println("scrolled to top!");
}
else if(position == 1.0) {
System.out.println("scrolled to bottom!");
}
}
});
I am trying to make a game in which I have an obstacle with the Class Rectangle, and have it slide left and right. However, although it seems like it should work, the Rectangle that I named obstacle1 does not move whatsoever.
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class SemiCircleMan extends Application {
public Pane pane = new Pane();
public AnimationTimer animate;
public double obstacle1Position = 0;
public int obstacle1Direction = 1;
public void start(Stage primaryStage) {
Scene scene = new Scene(pane, 800, 600);
Rectangle obstacle1 = new Rectangle(100, 125, 25, 25);
pane.getChildren().add(obstacle1);
obstacle1Position += 3 * obstacle1Position;
animate = new AnimationTimer() {
#Override
public void handle(long now) {
if (obstacle1.getX() <= 500) {
obstacle1.setTranslateX(obstacle1Position); //attempt to only make it go right
}
};
animate.start();
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I excluded the other code that I am sure does not affect this, as the other code only deals with moving other things. Again, with this code my obstacle1 stays still. Does anyone know how to make it slide?
Your code has (at least) two problems.
obstacle1Position is always zero.
You assume that the x-value will change if you set translateX. This is not true. The x-value belongs to the geometry and translateX modifies only its transform.
A sample app that shows how to move a Rectangle using AnimationTimer. One of the things you did not do in your code is get the Rectangle's current location and move from there.
In your case
rectangle.setTranslateX(rectangle.getTranslateX() + direction * speed);
Equivalent code in the sample app
rectangle.setX(rectangle.getX() + direction * speed);
Full Code:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication235 extends Application
{
double speed = 3;
double direction = 1;
#Override
public void start(Stage primaryStage)
{
Rectangle rectangle = new Rectangle(100, 125, 25, 25);
AnimationTimer animationTimer = new AnimationTimer()
{
#Override
public void handle(long now)
{
rectangle.setX(rectangle.getX() + direction * speed);
}
};
animationTimer.start();
Pane root = new Pane(rectangle);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
Instead of giving a fixed value as a target is there any way to continuously change the keyvalues's target value while the animation is running.
To achieve this goal I have bound the target value with a node's width property which changes continuously.But bind is not working at all when the animation starts the target value doesn't update and stuck.
This is the code for the animation
public void setGlowAnimation(){
System.out.println("WIDTH "+width.getValue());
KeyValue value = new KeyValue(glowshape.centerXProperty(),width.getValue(),Interpolator.EASE_OUT);
KeyFrame keyframe1 = new KeyFrame(Duration.millis(2000),value);
glow_timeline = new Timeline();
glow_timeline.setCycleCount(Timeline.INDEFINITE);
glow_timeline.setAutoReverse(true);
glow_timeline.getKeyFrames().add(keyframe1);
}
public void init(){
indetermination();
setStartAnimation();
createEllipse();
width = new SimpleDoubleProperty();
width.bind(this.widthProperty());
setGlowAnimation();
}
I don't think you can modify a Timeline while it is active like that. Consider using a Transition instead:
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.Transition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class AdaptiveAnimation extends Application {
#Override
public void start(Stage primaryStage) {
Circle circle = new Circle(0, 100, 25, Color.CORNFLOWERBLUE);
Pane pane = new Pane(circle);
Interpolator interp = Interpolator.EASE_BOTH ;
Transition transition = new Transition() {
{
setCycleDuration(Duration.millis(2000));
}
#Override
protected void interpolate(double frac) {
double x = interp.interpolate(0, pane.getWidth(), frac);
circle.setCenterX(x);
}
};
transition.setCycleCount(Animation.INDEFINITE);
transition.setAutoReverse(true);
Scene scene = new Scene(pane, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
transition.play();
}
public static void main(String[] args) {
launch(args);
}
}
This is a little jumpy while you're resizing the window, but it provides the basic idea.
I have two different StackPanes with HBoxes I want to change the image of a label in the second StackPane with a Label(MouseListener) in the first StackPane I think the problem is that the Label doesn't gets repainted or reloaded
First StackPane:
Label label= new Label("",new ImageView(ClearSpace));
label.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent event) -> {
HotBar hb = new HotBar();
if(hb.getX1() == 0){
hb.setImageX1(5);
}
event.consume();
});
Second StackPane(HotBar):
public Label x1;
Image image= new Image(getClass().getResourceAsStream("/resources/images/Test.png"));
...
Label x1 = new Label("",new ImageView(image));
...
public void setImage(int i){
if(i == 5){
x1.setGraphic(new ImageView(image2));
}
}
I think these are the importantst parts of hte code
setImage() is definetly working if you use it below Label x1 = ... it works
In your EventHandler you create a new instance of HotBar on which you do changes, but this instance is not linked to the scene.
Instead you should pass the instance of HotBar into the other class and use that in your event handler.
package helloworld;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
/**
* Created by matt on 3/22/16.
*/
public class SwapLabel extends Application {
int i = 0;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Pane root = new Pane();
Image img1 = new Image("http://www.logotemplater.com/freelogostemplates/voope-free-logo-template.png", true);
Image img2 = new Image("http://www.logotemplater.com/freelogostemplates/zoozz-vector-logo-template-sample.png", true);
Label l = new Label("", new ImageView(img1));
l.addEventHandler(MouseEvent.MOUSE_CLICKED, e->{
i = (i+1)%2;
if(i==0){
l.setGraphic(new ImageView(img1));
}else{
l.setGraphic(new ImageView(img2));
}
});
root.getChildren().add(l);
primaryStage.setScene(new Scene(root, 200, 200));
primaryStage.show();
}
}
This appears to be what you are trying to do, but this works. So most likely something else is happening.
i want to add and edit directly an element to a listview :
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javafx_test;
import java.util.Observable;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.StringConverter;
/**
*
* #author karim
*/
public class Javafx_test extends Application {
#Override
public void start(Stage primaryStage) {
ObservableList<String> items = FXCollections.observableArrayList("test1", "test2");
ListView<String> list = new ListView<>(items);
list.setEditable(true);
list.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
#Override
public ListCell<String> call(ListView<String> param) {
return new TextFieldListCell<>(new StringConverter<String>() {
#Override
public String toString(String object) {
return object;
}
#Override
public String fromString(String string) {
return string;
}
});
}
});
Button btn = new Button();
btn.setText("Add String");
btn.setOnAction((ActionEvent event) -> {
String c = new String("test");
list.getItems().add(list.getItems().size(), c);
list.scrollTo(c);
list.edit(list.getItems().size() - 1);
});
VBox root = new VBox(list, btn);
Scene scene = new Scene(root);
primaryStage.setTitle("test!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Everything seems correct but that not working, it like its try to modify the first item not the newly added item in the last index, i don't know why
That's a bug.
There seems to be some truly horrible interplay between focus and editing. The basic problem seems to be that when a list cell loses focus, it cancels any editing. I think that by clicking on the button, you cause the focus to shift to that button, and then on the next rendering pulse the list cell sees it has lost focus and cancels editing. I can't quite explain why the first item in the list appears to go to an editing state, but I suspect it is due to some further interaction with the list's focusModel, which manages focus of individual items.
For a truly ugly hack, use an AnimationTimer to delay the call to ListView.edit(...) by an additional rendering frame. (In case you're not familiar with it, an AnimationTimer defines a handle(...) method that is invoked once on each rendering pulse; here I just count one frame and then call edit, and stop the timer.)
btn.setOnAction((ActionEvent event) -> {
String c = "test"+(list.getItems().size()+1);
list.getItems().add(list.getItems().size(), c);
list.scrollTo(list.getItems().size() - 1);
// list.edit(list.getItems().size() - 1);
new AnimationTimer() {
int frameCount = 0 ;
#Override
public void handle(long now) {
frameCount++ ;
if (frameCount > 1) {
list.edit(list.getItems().size() - 1);
stop();
}
}
}.start();
});
Calling scrollTo(...) with an index instead of an item seems more robust too (especially as you have items in there that are equal to each other :).)
Maybe someone else can come up with something a bit cleaner that this...
The issue seems to be the Cells not being updated before calling edit. Since updating the cells is done during layout, calling layout before starting the edit should fix the issue:
Example:
#Override
public void start(Stage primaryStage) {
ListView<String> listView = new ListView<>();
listView.setEditable(true);
listView.setCellFactory(TextFieldListCell.forListView());
Button editButton = new Button("Add & Edit");
editButton.setOnAction((ActionEvent event) -> {
listView.getItems().add("");
listView.scrollTo(listView.getItems().size() - 1);
listView.layout();
listView.edit(listView.getItems().size() - 1);
});
Scene scene = new Scene(new VBox(listView, editButton));
primaryStage.setScene(scene);
primaryStage.show();
}
What James_D already mentioned: It seems that the index for the edit method is calculated wrong. In the following example it should not grab the correct index, but it does.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ListEdit extends Application {
int i = 3;
#Override
public void start(Stage primaryStage) {
ObservableList<String> items = FXCollections.observableArrayList("test1", "test2");
ListView<String> list = new ListView<>(items);
list.setCellFactory(TextFieldListCell.forListView());
list.setEditable(true);
Button btn = new Button();
btn.setText("Add String");
btn.setOnAction((ActionEvent event) -> {
list.getItems().add(i - 1, "test" + i);
list.edit(i - 2);
i++;
});
VBox root = new VBox(list, btn);
Scene scene = new Scene(root);
primaryStage.setTitle("test!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}