I have these two MouseEvents, and I want them "centralized" because I have other nodes that will do the same thing. I know that this can be done if you create multiple MouseEvents, but I reckon that there must be a shorter way.
public class scMain implements Initializable {
#FXML
private Button btnView, btnView2;
#FXML
private HBox hboxView, hboxView2;
public void translateTransition(Node node) {
TranslateTransition translate = new TranslateTransition();
translate.setNode(node);
// ...animation stuff
translate.play();
}
public void fadeOffTransition(Node node) {
FadeTransition fade = new FadeTransition();
fade.setNode(node);
// ...animation stuff
fade.play();
}
public void fadeInTransition(Node node) {
FadeTransition fade = new FadeTransition();
fade.setNode(node);
// ...animation stuff
fade.play();
}
#FXML
void btnMouseEnter(MouseEvent event) {
fadeOffTransition(btnView);
hboxView.setVisible(true);
translateTransition(hboxView);
}
#FXML
void btnMouseExit(MouseEvent event) {
fadeInTransition(btnView);
hboxView.setVisible(false);
}}
What I tried but obviously didn't work :
#FXML
void btnMouseEnter(MouseEvent event, Node first, Node second) {
fadeOffTransition(first);
second.setVisible(true);
translateTransition(second);
}
#FXML
void btnMouseExit(MouseEvent event, Node first, Node second) {
fadeInTransition(first);
second.setVisible(false);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
btnMouseEnter(event, btnView2, hboxView2); //error cannot find symbol
btnMouseExit(event, btnView2, hboxView2); //error cannot find symbol
}
Any suggestions would be appreciated.
Register the event handler in the intialize() method, instead of in the FXML. Remove the onMouseEnter and onMouseExit attributes from the FXML file, and modify the controller as follows:
void btnMouseEnter(Node first, Node second) {
fadeOffTransition(first);
second.setVisible(true);
translateTransition(second);
}
void btnMouseExit(Node first, Node second) {
fadeInTransition(first);
second.setVisible(false);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
btnView2.setOnMouseEnter(e -> btnMouseEnter(btnView2, hboxView2));
btnView2.setOnMouseExit(e -> btnMouseExit(btnView2, hboxView2));
}
You can also make the obvious reductions in code, e.g.:
private void registerMouseHandlers(Button button, Node target) {
button.setOnMouseEnter(e -> btnMouseEnter(button, target));
button.setOnMouseExit(e -> btnMouseExit(button, target));
}
#Override
public void initialize(URL location, ResourceBundle resources) {
registerMouseHandlers(btnView, hboxView);
registerMouseHandlers(btnView2, hboxView2);
}
And if you have a fairly large number of these, it might also be more efficient (in terms of lines of code) to do
#Override
public void initialize(URL location, ResourceBundle resources) {
List<Button> buttons = List.of(btnView, btnView2);
List<Node> targets = List.of(hboxView, hboxView2);
for (int i = 0 ; i < buttons.size() ; i++) {
registerMouseHandlers(buttons.get(i), targets.get(i));
}
}
You could also consider creating a custom component encapsulating your button and hbox, which simply implements the event handlers for a single button-hbox pair, and then including them in the FXML using fx:include.
Related
I am trying to make the radio button selection choose which of the encryption methods is used by the program
#FXML
public void atbashChooser(ActionEvent event) {
}
#FXML
public void caesarChooser(ActionEvent evnt) {
}
#FXML
public void encryptShit(ActionEvent event) {
if (atbashButton.isSelected()){
encryptField.setText(new AtbashCipher().encrypt(messageField.getText()));
}
else if (caesarButton.isSelected()){
encryptField.setText(new CaesarCipher().encrypt(messageField.getText()));
}
}
#FXML
public void decryptShit(ActionEvent event) {
if (atbashButton.isSelected()){
decryptField.setText(new AtbashCipher().decrypt(messageField.getText()));
}
else if (caesarButton.isSelected()){
decryptField.setText(new CaesarCipher().decrypt(messageField.getText()));
}
}
This does obviously not work, but is there a way to do this in a somewhat easy way? I can share the FXML code as well if this is necessary.
I'm using a JFXDrawer, SalesDrawer containing a VBox and 2 JFXButtons inside it. The contents of the JFXDrawer have a separate controller, SalesDrawerController.java. The controller file, SalesController.java that contains the JFXDrawer consists of 2 anchor panes that I want to set visible on click of the buttons in the JFXDrawer. Till now I was using a set of static boolean variables and making sure on click of a button in the JFXDrawer one of the variables is set to true. Then in the SalesController.java, I used a TimerTask object to check which of these variables were true and set the needed anchor pane to visible. Is there a better way of doing this?
SalesDrawerController.java
public class SalesDrawerController implements Initializable {
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
private void button1Hit(MouseEvent event) {
SalesController.SD[0]=true;
}
#FXML
private void button2Hit(MouseEvent event) {
SalesController.SD[1]=true;
}
}
SalesController.java
public class SalesController implements Initializable {
public static boolean SD[]= {false,false};
static boolean tock=true;
#FXML
private AnchorPane eq_newpane;
#FXML
private AnchorPane eq_delpane;
#FXML
private JFXHamburger SalesHam;
#FXML
private JFXDrawer SalesDraw;
public void initialize(URL url, ResourceBundle rb) {
eq_newpane.setVisible(true);
eq_delpane.setVisible(false);
eq_newpane.setDisable(false);
eq_delpane.setDisable(true);
VBox box = FXMLLoader.load(getClass().getResource("/fxml/SalesDrawer.fxml"));
SalesDraw.setSidePane(box);
HamburgerBackArrowBasicTransition transition = new HamburgerBackArrowBasicTransition(SalesHam);
transition.setRate(-1);
SalesHam.addEventHandler(MouseEvent.MOUSE_PRESSED,(e)->{
transition.setRate(transition.getRate()*-1);
transition.play();
if(SalesDraw.isShown()){
SalesDraw.close();
SalesDraw.toBack();
}
else{
SalesDraw.toFront();
SalesDraw.open();
}
});
threadtock();
}
public void threadtock() {
final java.util.Timer timer = new java.util.Timer();
final TimerTask delayedThreadStartTask;
delayedThreadStartTask = new TimerTask() {
public void run() {
try
{
if(tock){
if(SD[0])
{
eq_newpane.setVisible(true);
eq_delpane.setVisible(false);
eq_newpane.setDisable(false);
eq_delpane.setDisable(true);
}
else if(SD[1]){
eq_delpane.setVisible(true);
eq_newpane.setVisible(false);
eq_newpane.setDisable(true);
eq_delpane.setDisable(false);
}
if(tock)
{
threadtock();
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
};
timer.schedule(delayedThreadStartTask, 500);
};
}
Use synchronization mechanisms so you do not inherit deadlocks in your code from 2 or more threads attempting to operate on the same variable at once.
Figuring out how to properly synchronize your threads can be a pain, and it is very hard to explain, let alone debug. So, my best advice is to use google for "Java Concurrency" and "Java Thread Synchronization".
Otherwise, you should start a thread/threads from your main application to preform your intended operations
I want to make a custom cell in the ListView. Excuse my bad English!
I want to display the picture, name and status in the ListView.
For this I use a different Fxml that contains Hbox .
public class Controller {
CollectionContactForListCollection contactForList = new CollectionContactForListCollection();
#FXML
private ListView<Contact> listContact ;
#FXML
HBox hbox;
#FXML
ImageView avatar;
#FXML
Label labelName;
#FXML
Label lblStatus;
#FXML
Label lblSense;
#FXML
private void initialize(){
contactForList.fieldData();
// listContact.setItems((ObservableList) contactForList.getContactList());
listContact.setCellFactory(new Callback<ListView<Contact>, ListCell<Contact>>() {
#Override
public ListCell<Contact> call(ListView<Contact> param) {
ListCell<Contact> listCell = new ListCell<Contact>() {
#Override
protected void updateItem(Contact item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
//This method does not work download
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/view/boxInContact.fxml"));
fxmlLoader.setController(this);
labelName.setText(item.getName());
lblSense.setText(item.getSense());
lblStatus.setText(item.getStatus());
avatar.setImage(item.getImage());
}
}
};
return listCell;
}
});
listContact.setItems((ObservableList) contactForList.getContactList());
}
As a general, rule, you should use a different controller class for each FXML file. With the code you have, all cells are using the same controller instance, so there is only one reference to each control, even though there are many labelNames, etc (one for each cell).
So define a controller for the FXML defined for the list cell, and define the methods you need to update the controls:
public class ContactCellController {
#FXML
private Label labelName ;
#FXML
private Label labelStatus ;
#FXML
private Label labelSense ;
#FXML
private ImageView avatar ;
public void setName(String name) {
labelName.setText(name);
}
public void setStatus(String status) {
labelStatus.setText(status);
}
public void setSense(String sense) {
labelSense.setText(sense);
}
public void setAvatarImage(Image image) {
avatar.setImage(image);
}
}
Update the FXML file to use a controller attribute with fx:controller="my.package.ContactCellController", and then your cell implementation can look like
listContact.setCellFactory(lv -> new ListCell<Contact>() {
private Node graphic ;
private ContactCellController controller ;
{
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/boxInContact.fxml"));
graphic = loader.load();
controller = loader.getController();
} catch (IOException exc) {
throw new RuntimeException(exc);
}
}
#Override
protected void updateItem(Contact contact, boolean empty) {
super.updateItem(contact, empty);
if (empty) {
setGraphic(null);
} else {
controller.setName(contact.getName());
controller.setStatus(contact.getStatus());
controller.setSense(contact.getSense());
controller.setAvatarImage(contact.getImage());
setGraphic(graphic);
}
}
});
I have an application in JavaFX FXML by using Model View Controller. I want to move some sliders with keyboard. To do this in the main class I put a KeyEvent to hear what happens on the keyboard. In the controller class FXMLDocumentController where are FXML variables. These variables are passed to a third class. Where there sliders are changed when you click any.
The problem is that when I pass the variables of the sliders in the third class are perfectly stored but when you run the code to modify sliders coming past the main class when clicked are FXML variables are null.
Here you have the code:
Main class:
public class OpenPilot extends Application {
Movements Movements = new Movements();
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent Key) {
Movements.GetKeys(Key);
}
});
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Controller:
public class FXMLDocumentController implements Initializable {
Movements Movements = new Movements();
#FXML public Slider SpeedSlider;
#FXML public Slider TurnsSlider;
#Override
public void initialize(URL url, ResourceBundle rb) {
//Send GUI Information
Movements.GetSliders(SpeedSlider, TurnsSlider);
}
}
Movements:
public class Movements {
//Define Data Variables
public double SpeedValue;
public double TurnsValue;
//Define GUI Variables
private Slider SpeedSlider;
private Slider TurnsSlider;
public void GetSliders(Slider SpeedSlider, Slider TurnsSlider) {
this.SpeedSlider = SpeedSlider;
this.TurnsSlider = TurnsSlider;
}
//Get Sliders
public void GetKeys(KeyEvent Key) {
System.out.println(Key.getCode());
System.out.println(SpeedSlider);
Platform.runLater(new Runnable() {
#Override public void run() {
TurnsSlider.setValue(10);
}
});
}
}
You use 2 different instances of the Movements class (Movements Movements = new Movements(); in OpenPilot and FXMLDocumentController). Since you don't use static fields / methods, you won't get any data from one instance to the other. You have to get the Movements object from the controller:
Controller:
public class FXMLDocumentController implements Initializable {
Movements movements = new Movements();
public Movements getMovements() {
return movements;
}
#FXML public Slider SpeedSlider;
#FXML public Slider TurnsSlider;
#Override
public void initialize(URL url, ResourceBundle rb) {
//Send GUI Information
movements.GetSliders(SpeedSlider, TurnsSlider);
}
}
Use a instance of the FXMLLoader instead of the static method to get the Movements field from the controller:
Main class:
public class OpenPilot extends Application {
Movements movements;
#Override
public void start(Stage stage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader();
// use non-static load method here
Parent root = fxmlLoader.load(getClass().getResource("FXMLDocument.fxml").openStream());
// get movements from via controller
FXMLDocumentController controller = fxmlLoader.<FXMLDocumentController>getController();
movements = controller.getMovements();
Scene scene = new Scene(root);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent Key) {
movements.GetKeys(Key);
}
});
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
I have a BorderPane, onto which I placed a MenuBar. At the center of the BorderPane I display differnt AnchorPanes depending on the MenuItem selected. So far so good.
Now, how do I make sure that the Menus change behavior in response to the item selected in the child AnchorPane? So for example if the user selects "Edit", there will be a different action depending on whether the item currently higlighted is a user account, a file etc.
So far I made something along these lines:
The BorderPane controller:
public class MenuTest implements Initializable{
#FXML
private BorderPane borderPaneMain;
#FXML
private AnchorPane anchorPaneMain;
#FXML
private Menu menuEdit;
#FXML
private MenuItem itemEdit;
static String menuMode;
static String entityName;
public MenuTest(){
menuMode ="";
entityName = "";
}
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
AnchorPane anchor;
try {
anchor = (AnchorPane) new FXMLLoader().load(getClass().getResource("views/MainView.fxml"));
borderPaneMain.setCenter(anchor);
} catch (IOException e) {
e.printStackTrace();
}
}
protected static void setMenuMode(String menuMd, String entityNm){
entityName = entityNm;
menuMode = menuMd;
}
#FXML
private void onEditClick(){
if(entityName.equals(AnchorTest.FILE)){
//Launches correct edit view
new FXMLLoader().load(getClass().getResource("views/EditFile.fxml"));
//Passes the name of the entity so that the controller can retrieve its data
FileEditController.setFile(entityName);
}else if(entityName.equals(AnchorTest.PERSON)){
new FXMLLoader().load(getClass().getResource("views/EditPerson.fxml"));
PersonEditController.setFile(entityName);
}
}
}
The child AnchorPane controller:
public class AnchorTest implements Initializable{
public static final String PERSON = "PERSON";
public static final String FILE = "FILE";
ObservableList<String> peopleList;
ObservableList<String> fileList;
#FXML
private ListView<String> listPeople;
#FXML
private ListView<String> listFiles;
#Override
public void initialize(URL location, ResourceBundle resources) {
peopleList = FXCollections.observableArrayList("Frank","Matin","Anne");
fileList = FXCollections.observableArrayList("hello.txt","holiday.jpg","cv.doc");
listPeople.setItems(peopleList);
listFiles.setItems(fileList);
}
#FXML
private void personSelected(){
MenuTest.setMenuMode(this.PERSON, listPeople.getSelectionModel().getSelectedItem());
}
#FXML
private void fileSelected(){
MenuTest.setMenuMode(this.FILE, listFiles.getSelectionModel().getSelectedItem());
}
}
However I'm not sure that it's the best solution, especially considering the if/elseif statement will need to be altered whenever I add a new element type and its corresponding edit options. So is there any way that I can do this better?
I think if your application has only a few (2-4) different types of "things" that are represented by a AnchorPane, then your approach is totally fine. An alternative to your approach is the state pattern. In that case, your currently selected "item type" would be your state.