How to know caret coordinates (not position) in JavaFX? - java

I would like to draw autocomplete-like drop-down box near caret in JavaFX controls like TextField and TextArea.
Is it possible to know double numeric coordinates of the caret in node coordinate system?

You can use the inputMethodRequests property to retrieve the position. You can specify a index relative to the start of the selection to get the screen coordinates for the char.
private static ContextMenu createMenu(String... text) {
ContextMenu menu = new ContextMenu();
EventHandler<ActionEvent> handler = evt -> {
TextInputControl control = (TextInputControl) menu.getUserData();
String t = ((MenuItem) evt.getSource()).getText();
control.replaceSelection(t);
};
for (String s : text) {
MenuItem item = new MenuItem(s);
item.setOnAction(handler);
menu.getItems().add(item);
}
return menu;
}
#Override
public void start(Stage primaryStage) {
ContextMenu menu = createMenu("Hello World", "42", "foo", "bar");
TextArea textArea = new TextArea();
TextField textField = new TextField();
VBox root = new VBox(textArea, textField);
root.setPadding(new Insets(10));
EventHandler<KeyEvent> handler = evt -> {
if (evt.isControlDown() && evt.getCode() == KeyCode.SPACE) {
evt.consume();
TextInputControl control = (TextInputControl) evt.getSource();
Point2D pos = control.getInputMethodRequests().getTextLocation(0);
menu.setUserData(control);
menu.show(control, pos.getX(), pos.getY());
menu.requestFocus();
}
};
textArea.addEventFilter(KeyEvent.KEY_PRESSED, handler);
textField.addEventFilter(KeyEvent.KEY_PRESSED, handler);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

Related

Not able to click on Button JavaFX

I am creating a simple JavaFX based game and when I add a Button to my Pane and try to perform some action on it by clicking the mouse button while hovering over the button nothing happens - as if it is disabled but still visible.
private class Game extends Parent {
public Game() {
private Button newGameButton;
private Scene secondScene;
private Stage secondStage;
private Pane pane;
VBox menu = new VBox(15);
VBox highScore = new VBox(15);
menu.setTranslateX(280);
menu.setTranslateY(250);
highScore.setTranslateX(100);
highScore.setTranslateY(200);
try {
onLoad();
} catch (IOException e) {
e.printStackTrace();
}
newGameButton = new MenuButtonView("New Game");
newGameButton.setOnMouseClicked(event -> {
pane = new Pane();
secondScene = new Scene(pane, 800, 600);
secondStage = new Stage();
secondStage.setScene(secondScene);
secondStage.show();
scoreAndCrackView();
mickeyView();
});
public void mickeyView(){
private Button leftDownRedButton;
leftDownRedButton = new Button();
rightDownRedButton.setTranslateX(640);
rightDownRedButton.setTranslateY(560);
pane.getChildren().add(rightDownRedButton);
leftDownRedButton.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
System.out.println("Clicked");
}
});
public void scoreAndCrackView()
{
vertBox = new VBox();
vertBox.setPrefSize(800, 100); // this one was causing issue, previously: vertBox.setPrefSize(800, 600)
vertBox.getChildren().addAll(scoreLabel,crackLabel);
pane.getChildren().add(vertBox);
}
}
UPDATE
Btw I found the cause of the error - as you guys suggested something was covering my buttons and more precisely the VBox in another method which was set to the whole screen. After changing the values and minimizing prefWidth and prefHeight I can click on the buttons. Lesson for the future to set the Box only for the required area.

Background color transition on a JavaFX 8 Node/Region/Pane

Is it possible to do a simple background "flash" effect with a gradual fade on an arbitrary Node/Region/Pane?
I just want to show a subtle/brief red/white "flash" effect on a VBox (containing a label) to draw attention to it when the label's value changes.
Edit: All examples of this nature I've found so far seem to use a "Shape" (which is a Node), but of course a VBox or a Pane aren't a Shape - so that doesn't help me too much. Calling getShape() on the VBox just returns a null, so that's no help (I guess layout code hasn't been executed yet).
Edit 2:
This ALMOST works, but this dang effect seems to be completely overwriting (I think) everything in the VBox, including the text Label.
ColorInput effect = new ColorInput(0, 0, 900, 25, Paint.valueOf("#FFDDDD"));
Timeline flash = new Timeline(
new KeyFrame(Duration.seconds(0.4), new KeyValue(effect.paintProperty(), Paint.valueOf("#EED9D9"))),
new KeyFrame(Duration.seconds(0.8), new KeyValue(effect.paintProperty(), Paint.valueOf("#E0DDDD"))),
new KeyFrame(Duration.seconds(1.0), new KeyValue(effect.paintProperty(), Paint.valueOf("#DDDDDD"))));
vbox.setEffect(effect);
flash.setOnFinished(e -> vbox.setEffect(null));
flash.play();
Best way would be to provide a custom animation, like this (elaborating on fabian's answer):
#Override
public void start(Stage primaryStage) {
Label label = new Label("Bla bla bla bla");
Button btn = new Button("flash");
VBox box = new VBox(10, label, btn);
box.setPadding(new Insets(10));
btn.setOnAction((ActionEvent event) -> {
//**************************
//this animation changes the background color
//of the VBox from red with opacity=1
//to red with opacity=0
//**************************
final Animation animation = new Transition() {
{
setCycleDuration(Duration.millis(1000));
setInterpolator(Interpolator.EASE_OUT);
}
#Override
protected void interpolate(double frac) {
Color vColor = new Color(1, 0, 0, 1 - frac);
box.setBackground(new Background(new BackgroundFill(vColor, CornerRadii.EMPTY, Insets.EMPTY)));
}
};
animation.play();
});
Scene scene = new Scene(box, 100, 100);
primaryStage.setScene(scene);
primaryStage.show();
}
You could animate a effect, e.g. DropShadow:
#Override
public void start(Stage primaryStage) {
Label label = new Label("Bla bla bla bla");
DropShadow shadow = new DropShadow();
shadow.setColor(Color.RED);
shadow.setSpread(0.75);
Timeline shadowAnimation = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(shadow.radiusProperty(), 0d)),
new KeyFrame(Duration.seconds(0.15), new KeyValue(shadow.radiusProperty(), 20d)));
shadowAnimation.setAutoReverse(true);
shadowAnimation.setCycleCount(2);
Button btn = new Button("flash");
btn.setOnAction((ActionEvent event) -> {
Node target = label;
target.setEffect(shadow);
shadowAnimation.setOnFinished(evt -> target.setEffect(null));
shadowAnimation.play();
});
VBox box = new VBox(10, label, btn);
box.setPadding(new Insets(10));
Scene scene = new Scene(box, 100, 100);
primaryStage.setScene(scene);
primaryStage.show();
}
You can create a fake shape and use the FillTransition Interpolator to apply the shape's fill to the control background.
public static void AnimateBackgroundColor(Control control, Color fromColor,Color toColor,int duration)
{
Rectangle rect = new Rectangle();
rect.setFill(fromColor);
FillTransition tr = new FillTransition();
tr.setShape(rect);
tr.setDuration(Duration.millis(duration));
tr.setFromValue(fromColor);
tr.setToValue(toColor);
tr.setInterpolator(new Interpolator() {
#Override
protected double curve(double t) {
control.setBackground(new Background(new BackgroundFill(rect.getFill(), CornerRadii.EMPTY, Insets.EMPTY)));
return t;
}
});
tr.play();
}

Bind the result of list.contains() method

I want to bind text field to indicate whether list of integer contain 1.
i have a button that insert 1 to the list and I want the text field will update but this doesn't happens. why and how can i repair it?
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
final List<Integer> list = new ArrayList<Integer>();
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
list.add(1);
}
});
TextField txt = new TextField();
txt.textProperty().bind(new SimpleStringProperty(String.valueOf(list.contains(1))));
VBox root = new VBox();
root.getChildren().addAll(btn,txt);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
Try creating a BooleanBinding:
#Override
public void start( final Stage primaryStage )
{
primaryStage.setTitle( "Hello World!" );
final List<Integer> list = new ArrayList<>();
// we need an ObservableList, duh, to observe!
final ObservableList<Integer> oblist = FXCollections.observableArrayList( list );
Button btn = new Button();
btn.setText( "Say 'Hello World'" );
btn.setOnAction( new EventHandler<ActionEvent>()
{
#Override
public void handle( ActionEvent event )
{
oblist.add( 1 );
}
} );
BooleanBinding bb = Bindings.createBooleanBinding( () -> oblist.contains( 1 ), oblist );
TextField txt = new TextField();
txt.textProperty().bind( bb.asString() );
VBox root = new VBox();
root.getChildren().addAll( btn, txt );
final Scene scene = new Scene( root, 400, 300 );
primaryStage.setScene( scene );
primaryStage.show();
}
I still doesn't understand what problem with my code, can you explain
me please?
Let's break down the code: new SimpleStringProperty(String.valueOf(list.contains(1)));
-> initially list.contains(1) = false
-> String.valueOf(false) = "false"
-> new SimpleStringProperty("false") will create new instance of StringProperty with initial value "false", and this instance is bound to textProperty of textField. That is it, since we are initiating with the String value "false", no further observation for list and its content where it contains 1 or not. Hence we need an observable list here.
Thus the textfield's text will change in sync if the bound StringProperty is changed. Rewriting as,
StringProperty sp = new SimpleStringProperty(String.valueOf(list.contains(1)));
txt.textProperty().bind(sp);
sp.set("newVal"); // at this point textfield's text will be updated with
// "newVal", but it has nothing about list and its content.

Custom palette in the ColorPicker

I would like to change the color palette. The colors are by default have a transparency of 30%.
Is it possible to replace the color palette?
Based on this solution, you can replace the color palette once you get the rectangles and their colors.
For instance, you can make brighter all the palette:
#Override
public void start(Stage primaryStage) {
ColorPicker picker = new ColorPicker();
StackPane root = new StackPane(picker);
Scene scene = new Scene(root, 500, 400);
primaryStage.setScene(scene);
primaryStage.show();
picker.showingProperty().addListener((obs,b,b1)->{
if(b1){
PopupWindow popupWindow = getPopupWindow();
Node popup = popupWindow.getScene().getRoot().getChildrenUnmodifiable().get(0);
popup.lookupAll(".color-rect").stream()
.forEach(rect->{
Color c = (Color)((Rectangle)rect).getFill();
// Replace with your custom color
((Rectangle)rect).setFill(c.brighter());
});
}
});
}
private PopupWindow getPopupWindow() {
#SuppressWarnings("deprecation")
final Iterator<Window> windows = Window.impl_getWindows();
while (windows.hasNext()) {
final Window window = windows.next();
if (window instanceof PopupWindow) {
return (PopupWindow)window;
}
}
return null;
}

Resize JavaFX tab when double click

I have this simple example with JavaFX tabs:
public class test extends Application
{
private BorderPane root;
// Navigation Utilization
private ActionTabs actiontabs;
#Override
public void start(Stage primaryStage)
{
// Set Main Window Label
primaryStage.setTitle("Desktop Client");
Image iv = new Image(getClass().getResource("/images/internet-icon.png").toExternalForm());
primaryStage.getIcons().add(iv);
root = new BorderPane();
root.setLeft(getLeftHBox(primaryStage, root));
Scene scene = new Scene(root, 1000, 1000, Color.WHITESMOKE); // Set main Stage color
primaryStage.setScene(scene);
Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
// Set Stage boundaries to visible bounds of the main screen
primaryStage.setX(primaryScreenBounds.getMinX());
primaryStage.setY(primaryScreenBounds.getMinY());
primaryStage.setWidth(primaryScreenBounds.getWidth()); // Maximum width of the display
primaryStage.setHeight(primaryScreenBounds.getHeight()); // Maximum height of the display
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
private HBox getLeftHBox(Stage primaryStage, BorderPane root)
{
HBox hbox = new HBox();
TabPane tabPane = new TabPane();
BorderPane mainPane = new BorderPane();
tabPane.setStyle("-fx-font-size: 12pt;"); // Set global size for the font
// Create Tabs
Tab tabA = new Tab();
tabA.setText("Main Component");
tabA.setStyle("-fx-font-size: 12pt;"); // Set size of the tab name
tabA.setClosable(false);
// Add something in Tab
StackPane tabA_stack = new StackPane();
tabA_stack.setAlignment(Pos.CENTER);
tabA_stack.getChildren().add(new Label("Label#Tab A"));
tabA.setContent(tabA_stack);
tabPane.getTabs().add(tabA);
Tab tabB = new Tab();
tabB.setText("Second Component");
tabB.setStyle("-fx-font-size: 12pt;"); // Set size of the tab name
tabB.setClosable(false);
// Add something in Tab
StackPane tabB_stack = new StackPane();
tabB_stack.setAlignment(Pos.CENTER);
tabB_stack.getChildren().add(new Label("Label#Tab B"));
tabB.setContent(tabB_stack);
tabPane.getTabs().add(tabB);
Tab tabC = new Tab();
tabC.setText("Last Component");
tabC.setStyle("-fx-font-size: 12pt;"); // Set size of the tab name
tabC.setClosable(false); // da se mahne opciqta da se zatvarq tab
// Add something in Tab
StackPane tabC_vBox = new StackPane();
tabC_vBox.setAlignment(Pos.CENTER);
tabC_vBox.getChildren().add(new Label("Label#Tab C"));
tabC.setContent(tabC_vBox);
tabPane.getTabs().add(tabC);
mainPane.setCenter(tabPane);
mainPane.setPrefSize(300, 500);
//mainPane.setLayoutX(5); // Horizontal Position
mainPane.setLayoutY(32); // Vertical Position
hbox.getChildren().addAll(mainPane);
return hbox;
}
}
I want when I double click on a tab name to maximize the size of the body of the tab and make it the same width and height as the size of the application. Similar for example to Eclipse IDE tabs. Is this possible with JavaFX?
EDIT
This is the code that I have tested.
public BorderPane initNavigation(Stage primaryStage)
{
VBox stackedTitledPanes = createStackedTitledPanes();
ScrollPane scroll = makeScrollable(stackedTitledPanes);
final TabPane tabPane = new TabPane();
final BorderPane mainPane = new BorderPane();
final Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
tabPane.setStyle("-fx-font-size: 12pt;"); // Set global size for the font
// Create Tabs
Tab tabA = new Tab();
tabPane.setOnMouseClicked(new EventHandler<MouseEvent>()
{
private double sizeX, sizeY;
private boolean first = true;
#Override
public void handle(MouseEvent me)
{
if (first)
{
sizeX = mainPane.getWidth();
sizeY = mainPane.getHeight();
first = false;
}
if (me.getButton().equals(MouseButton.PRIMARY) && me.getClickCount() % 2 == 0)
{
if (sizeX != mainPane.getWidth() || sizeY != mainPane.getHeight())
{
mainPane.setPrefSize(sizeX, sizeY);
}
else
{
mainPane.setPrefSize(primaryScreenBounds.getWidth(), primaryScreenBounds.getHeight());
//mainPane.toFront();
}
}
}
});
tabA.setText("Main Component");
tabA.setContextMenu(makeTabContextMenu(tabA, tabPane)); // Set right mouse click menu
// Add something in Tab
StackPane tabA_stack = new StackPane();
tabA_stack.setAlignment(Pos.CENTER);
tabA_stack.getChildren().add(scroll);
tabA.setContent(tabA_stack);
tabPane.getTabs().add(tabA);
Tab tabB = new Tab();
tabB.setText("Second Component");
tabB.setContextMenu(makeTabContextMenu(tabB, tabPane)); // Set right mouse click menu
// Add something in Tab
StackPane tabB_stack = new StackPane();
tabB_stack.setAlignment(Pos.CENTER);
tabB_stack.getChildren().add(new Label("Label#Tab B"));
tabB.setContent(tabB_stack);
tabPane.getTabs().add(tabB);
Tab tabC = new Tab();
tabC.setText("Last Component");
tabC.setContextMenu(makeTabContextMenu(tabC, tabPane)); // Set right mouse click menu
// Add something in Tab
StackPane tabC_vBox = new StackPane();
tabC_vBox.setAlignment(Pos.CENTER);
tabC_vBox.getChildren().add(new Label("Label#Tab C"));
tabC.setContent(tabC_vBox);
tabPane.getTabs().add(tabC);
mainPane.setCenter(tabPane);
mainPane.setPrefSize(300, 500);
//mainPane.setLayoutX(5); // Horizontal Position
mainPane.setLayoutY(32); // Vertical Position
scroll.setPrefSize(395, 580);
scroll.setLayoutX(5);
scroll.setLayoutY(32);
return mainPane;
}
The problem is how I can cover the stage with the tab code when I double click on the tab name?
You required to add few lines to your code, here is a sample for you,
.....
Tab tabA = new Tab();
Label tabALabel = new Label("Main Component");
tabA.setGraphic(tabALabel);
tabALabel.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
if (mouseEvent.getClickCount() == 2) {
mainPane.setPrefSize(500, 500); //Your required size
}
}
}
});
....
Try this, and tell if there's any difficulty.
You could create another BorderPane which contains your root = new BorderPane();
in Center, and replace it with the Tabpanel on doubleclick.
Resulting in:
rootRoot = new BorderPane();
BorderPane root = new BorderPane();
root.setLeft(getLeftHBox(primaryStage, root));
rootRoot.setCenter(root);
Scene scene = new Scene(rootRoot, 1000, 1000, Color.WHITESMOKE); // Set main Stage color
with "rootRoot" being the new root (great Name, i know ^^), and
Label tabALabel=new Label("Label#Tab A");
tabALabel.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
if (mouseEvent.getClickCount() == 2) {
//mainPane.setPrefSize(500, 500); //Your required size
rootRoot.setCenter(mainPane);
}
}
}
});
for maximizing.

Categories

Resources