I'd like to create two buttons in the bottom of the window, one on the far left and the other one on the right. I'm using BorderPane and AnchorPane. When running only one button is displayed, because I call the method BorderPane.setBottom()two times, the first call is executed, the second one is not atleast not in a way I'd like it to. Is there a way to do this using BorderPane? I've only seen help for other versions.
BorderPane root = new BorderPane();
AddArea addArea = new AddArea();
DeleteArea deleteArea = new DeleteArea();
root.setBottom(deleteArea.getPane());
root.setBottom(addArea.getPane());
public class AddArea {
private final AnchorPane anchorPane = new AnchorPane();
private final Button addButton = new Button("Add");
public AddArea() {
AnchorPane.setBottomAnchor(addButton, 10.0);
AnchorPane.setLeftAnchor(addButton, 10.0);
anchorPane.getChildren().addAll(addButton);
}
public Node getPane() {
return anchorPane;
}
}
public class DeleteArea {
private final AnchorPane anchorPane = new AnchorPane();
private final Button deleteButton = new Button("Delete");
public DeleteArea() {
AnchorPane.setBottomAnchor(deleteButton, 10.0);
AnchorPane.setRightAnchor(deleteButton, 10.0);
anchorPane.getChildren().addAll(deleteButton);
}
public Node getPane() {
return anchorPane;
}
}
Thank you in advance!
Related
I am trying to implement a full press-drag-release gesture with JavaFX. I want to drag a rectangle from one VBox to another. On the MOUSE_DRAG_RELEASED event that happens on the target VBox, I'm trying to add the dragged rectangle as a child of the target VBox.
The problem is that when I release the mouse on the target VBox, the rectangle does not get into the expected position inside the VBox, but is always offset to the right by a fixed distance.
public class DragFromOneVBoxToAnother extends Application {
private Disk sourceDisk = new Disk();
private VBox targetVBox = new VBox();
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
// Build the UI
GridPane root = getUI();
// Add the event handlers
this.addEventHandlers();
Scene scene = new Scene(root, 800, 600);
stage.setScene(scene);
stage.show();
}
private GridPane getUI() {
GridPane pane = new GridPane();
VBox sourceVBox = new VBox();
sourceDisk.setWidth(90);
sourceDisk.setHeight(20);
sourceVBox.setStyle(" -fx-border-color:red; -fx-border-width: 1; -fx-border-style: solid;");
targetVBox.setStyle(" -fx-border-color:green; -fx-border-width: 1; -fx-border-style: solid;");
sourceVBox.getChildren().add(sourceDisk);
targetVBox.getChildren().add(new Rectangle(200, 20));
pane.setHgap(200);
pane.addColumn(0, sourceVBox);
pane.addColumn(1, targetVBox);
pane.setPadding(new Insets(200, 100, 200, 100));
return pane;
}
private void addEventHandlers() {
sourceDisk.setOnMouseEntered(event -> sourceDisk.setCursor(Cursor.HAND));
sourceDisk.setOnMousePressed(event -> {
sourceDisk.setOrgSceneX(event.getSceneX());
sourceDisk.setOrgSceneY(event.getSceneY());
sourceDisk.setOrgTranslateX(sourceDisk.getTranslateX());
sourceDisk.setOrgTranslateY(sourceDisk.getTranslateY());
sourceDisk.setMouseTransparent(true);
sourceDisk.setCursor(Cursor.CLOSED_HAND);
});
sourceDisk.setOnDragDetected(event -> sourceDisk.startFullDrag());
sourceDisk.setOnMouseDragged(event -> {
double offsetX = event.getSceneX() - sourceDisk.getOrgSceneX();
double offsetY = event.getSceneY() - sourceDisk.getOrgSceneY();
double newTranslateX = sourceDisk.getOrgTranslateX() + offsetX;
double newTranslateY = sourceDisk.getOrgTranslateY() + offsetY;
sourceDisk.setTranslateX(newTranslateX);
sourceDisk.setTranslateY(newTranslateY);
});
sourceDisk.setOnMouseReleased(event -> {
sourceDisk.setMouseTransparent(false);
sourceDisk.setCursor(Cursor.DEFAULT);
});
targetVBox.setOnMouseDragReleased(event ->
targetVBox.getChildren().add(sourceDisk));
}
private class Disk extends Rectangle {
private double orgSceneX;
private double orgSceneY;
private double orgTranslateX;
private double orgTranslateY;
// below, the getters and setters for all the instance variables
// were removed for brevity
}
I have found that, even though the visual representation of the dragged rectangle seems to be offset when it's dropped, a child appears to actually be added to the target VBox (this can be seen because the border of the VBox expands after the MOUSE_DRAG_RELEASED event).
What could be the issue?
During the mouse drag gesture you modify the translateX/translateY properties of the node. This results in the dragged node being offset from the position where the new parent places it by this transformation. You need to reset those values to properly add the node to the bottom of the VBox:
targetVBox.setOnMouseDragReleased(event -> {
targetVBox.getChildren().add(sourceDisk);
// reset translate values
sourceDisk.setTranslateX(0);
sourceDisk.setTranslateY(0);
});
I'm making the application with JavaFX and Scene Builder. I have a fullscreen video before my appliaction start. SO it is a kind of intro for my appliaction.
A video has the same background as my main stage.
The problem is I have flickering effect at the very beginning when I launch the appliaction. Buttons and text from main window appear during like half of a second and then my video start.
How can I remove or hide that effect?
Please, check this link for more clear understanding of my problem
Video
Main Class:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("fxml/card.fxml"));
Parent root = (Parent) loader.load();
Scene scene = new Scene(root, 1600, 600);
primaryStage.setScene(scene);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setMaximized(true);
primaryStage.setResizable(true);
primaryStage.getIcons().add(new Image("logo-icon.png"));
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Controller where I place All buttons and text. I also have a video here:
public class Controller implements Initializable {
#FXML private AnchorPane mainAnchor, anchorRow, randomCard, randomCardBack, previewCard, bolt1;
#FXML private StackPane hBoxCat0;
#FXML private Button btnPalette, btnFont, btnQuestCards, btnNonQuestCards;
#FXML private ToggleButton btnPref1, btnPref2, btnPref3, btnPref4, btnPref5, btnPref6, btnPref7, btnPref8;
#FXML private Label lb_randomCard, lb_randomCardBack, answerID, lb_previewCard, category1, category2, category3, category4, category5, category6, category7, category8;
#FXML private ToggleGroup group;
#FXML private JFXColorPicker colorPickerCategory;
#FXML private Rectangle rectRandom, rectRandomBack;
#FXML private MediaView media;
private MediaPlayer mp;
private static final String MEDIA_URL = "intro.mp4";
#FXML
public void initialize(URL location, ResourceBundle resources) {
mp = new MediaPlayer(new Media(this.getClass().getResource(MEDIA_URL).toExternalForm()));
media.setMediaPlayer(mp);
media.setSmooth(true);
mp.setAutoPlay(true);
Timeline tm = new Timeline(new KeyFrame(Duration.millis(3000), new KeyValue(media.opacityProperty(), 0.0)));
tm.setDelay(Duration.millis(5500));
tm.play();
addQuestionsToArrayCat1();
addAnswersToArrayCat1();
addSentencesToArray();
matchSentences();
}
}
I'm trying to make TreeView with CheckBoxTreeItems. When I collapse/expand a CheckBoxTreeItems the image I set up does not display correctly. I googled but I couldn't find correct answer. On Stack Overflow, I found a similar problem, but I didn't get a valid answer.
E.g
JavaFX CheckBoxTreeItem graphic disappear when siblings collapse
JavaFX CheckBoxTreeItem: Graphic disappears if graph is extended
Any ideas?
public class ClientApplication extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage stage) {
ImageView folderIcon = new ImageView();
Image folderImage = new Image("image/folder.png");
folderIcon.setImage(folderImage);
folderIcon.setFitWidth(16);
folderIcon.setFitHeight(16);
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("folder", folderIcon);
rootItem.setExpanded(true);
for (int i = 0; i < 4; i++) {
CheckBoxTreeItem<String> checkBoxTreeItem = new CheckBoxTreeItem<String>("Sample" + (i + 1), folderIcon);
rootItem.getChildren().add(checkBoxTreeItem);
}
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
tree.setRoot(rootItem);
tree.setShowRoot(true);
StackPane root = new StackPane();
root.getChildren().add(tree);
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
}
enter image description here
I tried to use the ideas provided by #Jai,But when I click the expand/collapse icon, there is still a problem.Attachment is a screenshot.Thanks in advance.
enter image description here
ImageView is a JavaFX control. This means that each instance represents a unique control you see on your screen. You should never use the same instance for multiple locations in your GUI.
On the other hand, Image represents an image (i.e. an array of pixel data), so it is reusable.
This should work:
#Override
public void start(final Stage stage) {
final Image folderImage = new Image("image/folder.png");
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("folder", createImageView(folderImage));
rootItem.setExpanded(true);
for (int i = 0; i < 4; i++) {
CheckBoxTreeItem<String> checkBoxTreeItem = new CheckBoxTreeItem<String>("Sample" + (i + 1), createImageView(folderImage));
rootItem.getChildren().add(checkBoxTreeItem);
}
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
tree.setRoot(rootItem);
tree.setShowRoot(true);
StackPane root = new StackPane();
root.getChildren().add(tree);
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
private ImageView createImageView(Image folderImage) {
ImageView folderIcon = new ImageView();
folderIcon.setImage(folderImage);
folderIcon.setFitWidth(16);
folderIcon.setFitHeight(16);
return folderIcon;
}
I am trying to capture key press events (page up and down) but there are no key events received at all. Here is the relevant code:
Constructor:
private MainLayout() {
imageView = new ImageView();
root = new StackPane();
root.getChildren().add(imageView);
root.setFocusTraversable(true); //no effect
//root.requestFocus(); //also no effect
registerEvents();
}
Both lines regarding the focus don't have an effect. The stack pane is directly added to scene.
There are no other nodes than Scene->StackPane->ImageView.
I am able to capture key events on the scene, but i need them captured in the stack pane
Here is registerEvents(), all other events are captured fine!:
private void registerEvents() {
OnScroll onScroll = new OnScroll();
root.setOnScroll(onScroll);
OnResize onResize = new OnResize();
root.heightProperty().addListener(onResize);
root.widthProperty().addListener(onResize);
OnMouseDown onMouseDown = new OnMouseDown();
root.setOnMousePressed(onMouseDown);
root.setOnMouseReleased((event) -> fitImage());
root.setOnDragOver((event) -> dragOver(event));
root.setOnDragDropped((event) -> dropFile(event));
root.setOnKeyPressed((event) -> {
LOG.debug("Key captured.");
if(event.getCode() == KeyCode.PAGE_UP){
imageView.setImage(ip.prev());
event.consume();
} else if(event.getCode() == KeyCode.PAGE_DOWN){
imageView.setImage(ip.next());
event.consume();
}
if(event.isConsumed()){
fitImage();
}
});
I don't see the log out put and a break point is also not caught. So how to catch and handle key events correctly?
Meanwhile i found the solution thanks to this answer. The trick is to setFocusTraversable(true) on ImageView (child of stack pane). Here is the working code:
#Inject
private MainLayout(ImageProvider ip) {
this.ip = ip;
imageView = new ImageView();
imageView.setFocusTraversable(true);
imageView.requestFocus();
root = new StackPane();
root.getChildren().add(imageView);
registerEvents();
}
I don't know if this answer will satisfy you, but I would move handling events from this class to the class where you initialize your scene, and attach the events to the scene itself (since StackPane is, in a way, the scene). I'm guessing that, since the constructor in your code is private, you are instantiating the class via public static method from another class.
public class MainClass extends Application {
private Scene scene = new Scene(MainLayout.getMainLayout());
#Override
public void start(Stage primaryStage) throws Exception {
registerEvents();
primaryStage.setScene(scene);
primaryStage.show();
}
private void registerEvents() {
OnScroll onScroll = new OnScroll();
scene.setOnScroll(onScroll);
OnResize onResize = new OnResize();
scene.heightProperty().addListener(onResize);
scene.widthProperty().addListener(onResize);
OnMouseDown onMouseDown = new OnMouseDown();
scene.setOnMousePressed(onMouseDown);
scene.setOnMouseReleased((event) -> fitImage());
scene.setOnDragOver((event) -> dragOver(event));
scene.setOnDragDropped((event) -> dropFile(event));
scene.setOnKeyPressed((event) -> {
LOG.debug("Key captured.");
if (event.getCode() == KeyCode.PAGE_UP) {
imageView.setImage(ip.prev());
event.consume();
} else if (event.getCode() == KeyCode.PAGE_DOWN) {
imageView.setImage(ip.next());
event.consume();
}
if (event.isConsumed()) {
fitImage();
}
});
}
}
Alternatively, if you want to keep the code for handling events in the MainLayout class, consider making registerEvents a public (or package local, depending on your design) method accepting Scene as a param.
I have a question. How can i pass the same reference of one ObservableList between two classes? I need to add an Element from my SimultanTestController to the List in FXMLDocumentController.
My Code (FXMLDocumentController):
public class FXMLDocumentController implements Initializable {
Stage primaryStage = new Stage();
Stage options = new Stage();
Stage selectTest = new Stage();
ObservableList<DefaultTestInterface> items = FXCollections.observableArrayList();
public ObservableList<DefaultTestInterface> getList() {
return items;
}
#FXML
private ListView ItemList;
#FXML
public Button btn_globalOptions;
#FXML
private Button btn_add;
#FXML
private Button btn_delete;
#FXML
private Button btn_moveUP;
#FXML
private Button btn_moveDOWN;
public void getPrimaryStage(Stage stage){
this.primaryStage=stage;
}
My Code (SimultanTestController):
public class SimultanTestController implements Initializable {
ObservableList<DefaultTestInterface> items = (new FXMLDocumentController()).getList();
#FXML
Button btn_ok;
public void addTest(ActionEvent event){
for( int x = 0 ; x < items.size() ; x++ ) { // start from index 0
System.out.println("Item" +items.get(x));
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
btn_ok.setOnAction(this::addTest);
}
}
So you see, i have one Method: getList
and this method is called in SimultanTestController and i try to parse the value of getList to the ObservableList in SimultanTestController.
After that, i want to to add an element to the ObservableList in FXMLDocumentController from SimultanTestController. But i dont get the same list in both classes ...
Thank you for help!
I load my FXML-Files in this class:
First i create all new stages for my FXML-Files and have 3 ObservableList with the FXML-File-Names, the window-titel and all the stages. Then i load all stages with my for-loop. (By the way, is this a good solution?)
My window opening way: Main-->SelectTest-->SimultanTest
public class SelectTestController implements Initializable {
ObservableList<String> items =FXCollections.observableArrayList();
Stage primaryStage = new Stage();
Stage simultan = new Stage();
Stage audioLoop = new Stage();
Stage cpu = new Stage();
Stage driversCD = new Stage();
Stage driversHD = new Stage();
Stage driversFD = new Stage();
Stage externalProgramm = new Stage();
Stage graphics = new Stage();
Stage interactive = new Stage();
Stage mainboard = new Stage();
Stage memorySPD = new Stage();
Stage memory = new Stage();
Stage network = new Stage();
Stage ports = new Stage();
Stage reboot = new Stage();
Stage signal = new Stage();
Stage userMessage = new Stage();
#FXML
private ListView lv_selectTest;
#FXML
private Button btn_choose;
#FXML
private Label test;
public void getPrimaryStage(Stage stage){
this.primaryStage=stage;
}
ObservableList<Stage> stages =FXCollections.observableArrayList();
ObservableList<String> fxml =FXCollections.observableArrayList();
ObservableList<String> stageTitel =FXCollections.observableArrayList();
public void initWindows(){
try {
for(int i=0;i<=stages.size();i++){
Window parent = primaryStage;
Parent root = FXMLLoader.load(getClass().getResource(fxml.get(i)));
Scene scene = new Scene(root);
stages.get(i).initOwner(parent);
stages.get(i).initModality(Modality.APPLICATION_MODAL);
stages.get(i).setTitle(stageTitel.get(i));
stages.get(i).setScene(scene);
stages.get(i).setResizable(false);
stages.get(i).setAlwaysOnTop(true);
}
}catch (IOException|IllegalStateException ex) {
System.out.println(ex);
}
}
I tried to get the controller of the FXML-Loader and this works. I get the value from JavaFX-Start methode and parse it to FXMLDocumentController. Now i have a var with the controller instance in my FXMLDocumentConroller. But i am not able to get the value in SimultanTest ot add something to the ObservableList items. I tired per new Instance() and setter+getter... I dont know why i dont get it...
It would be very nice if someone could give me an example based of my code ... You see i worked for my solution but im not getting further...
i found an own solution for my Problem. I dont get the Controller of FXMLMain, but i solved it with an Singelton Class which stores the ObservableList items.
Now i can set Items from every class and can show them in ListView in FXMLDocumentController. If some one have the same Problem, connect me for a solution.
Thanks for help # James_D