I am a newbie in Javafx and I am trying to fix a cropping over an image. I found an interesting solution for cropping with rubber band and now I try to modified this in my scenario.
I have two controllers. One controller has the crop button (CropController) and another controller which contain an image as ImageController.
CropController:
public class CropController {
#FXML
private void initialize() {}
#FXML
private void handleCrop(){
}
}
ImageController:
public class ImageController {
#FXML
private ImageView MainImage;
#FXML
private void initialize() {
modelSharedOne.imageProperty()
.addListener((obs, oldImage,newImage)-> MainImage.setImage(newImage));
}
#FXML
private void handleMousePresses(){}
#FXML
private void handleMouseDragged(){}
#FXML
private void handleMouseReleased(){}
}
Based on the rubber band solution I need to group those three mouse handlers. I do not know what could be the best solution for this. I have tried many solutions like creating a model between these two controllers but I have not managed to solve this solution.
Anyone knows how can I solve this?
My current solution
CropController:
public class ToolboxController {
#FXML
private void initialize() {
}
#FXML
private void handleCrop(){
SharedModelTwo.callHandlerInWorkstation();
}
}
SharedModelTwo:
public class CropImageModel {
ImageController imageController;
public void callHandlerInImage(){
imageController = new ImageController();
imageController.handleCrop();
}
}
ImageController:
public class ImageController {
#FXML
private ImageView MainImage;
#FXML
private void initialize() {
modelSharedOne.imageProperty()
.addListener((obs, oldImage,newImage)-> MainImage.setImage(newImage));
}
public void handleCrop() {
Image image = getImage();
ImageView imageView = new ImageView(image);
rect = new Rectangle( 0,0,0,0);
rect.setStroke(Color.BLUE);
rect.setStrokeWidth(1);
rect.setStrokeLineCap(StrokeLineCap.ROUND);
rect.setFill(Color.LIGHTBLUE.deriveColor(0, 1.2, 1, 0.6));
Group imageLayer = new Group();
imageLayer.getChildren().add(imageView);
rubberBandSelection = new RubberBandSelection(imageLayer);
}
}
And rubberBandSelection is a class as it was in the linked. when I run that it does not hit when mouse pressed on image.
Related
So I'm trying to fill my Rectangle with Color Picker, but it doesn't cooperate.
I do it like this:
#FXML
private ColorPicker colorPicker = new ColorPicker(Color.BLACK);
#FXML
public void changeColor()
{
myRect.setFill(colorPicker.getValue());
System.out.println("color = " + colorPicker.getValue());
}
I binded this function to the ColorPicker in SceneBuilder, but when I choose a color, my rectangle only changes its color to black (or whatever default color I put in constructor) independently of what color I choose. So every time I pick a color I get the output "color = 0xff0000ff". Is it because I'm not using EventHandler (I somehow couldn't get it to work in the initialize function)? In my understanding if I bind it this function to the OnAction field it should work exactly like a Listener.
public class Main extends Application {
Stage window;
#Override
public void start(Stage primaryStage) {
try {
window = primaryStage;
Parent root = FXMLLoader.load(getClass().getResource("/MainScreen.fxml"));
Scene scene = new Scene(root);
window.setScene(scene);
window.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
public class Controller{
#FXML
private ColorPicker colorPicker = new ColorPicker(Color.BLACK);
#FXML
private Rectangle myRect;
public void initialize(){}
#FXML
public void changeWaveColor()
{
myRect.setFill(colorPicker.getValue());
System.out.println("Function color = " + colorPicker.getValue());
}
}
I have 2 scenes :
The first one has a "Balance" Label, which displays the balance from a variable.
The second scene is the deposit scene where the user adds to the balance.
(Each scene has its controller class)
I want the balance to be updated when the user goes back to the first scene.
what's the best way to do so? I couldn't find an event for the scene shown, I found online only a stage example which triggers an event when the window is closed, but here I am just changing scenes by changing the mainstage scene.
I have tried making an object of the first scene class inside the second scene's class and calling a method to change the label text when I click the back button but that didn't work.
Here's the code for the first scene where lbBalance is the label I want to update, and updateBal is the method I am using in the second scene class.
public class accountController extends Controller implements Initializable {
#FXML private Label gilbert;
#FXML private Label lbBalance;
#FXML private Button deposit;
#FXML private Button btn_showBalance;
private application.depositController depositController;
#Override
public void initialize(URL location, ResourceBundle resources) {
lbBalance.setText(String.valueOf(BAL));
}
#FXML
public void handleDeposit(ActionEvent event) throws IOException {
Parent depositParent = FXMLLoader.load(getClass().getResource("deposit.fxml"));
depositScene = new Scene(depositParent);
mainStage.setScene(depositScene);
mainStage.show();
}
public void updateBal() {
lbBalance.setText(String.valueOf(BAL));
}
}
Here's the second scene's class
accountController backtoscene= new accountController();
#FXML private Label info;
#FXML private Button btn_depositfinal;
#FXML private TextField depositamount;
#FXML private Button btn_back;
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
}
#FXML
public void handleDepositFinal(ActionEvent event) {
deposit(Integer.parseInt(depositamount.getText()));
info.setVisible(true);
}
#FXML
public void handleBackButton(ActionEvent event) throws IOException {
backtoscene.updateBal();
mainStage.setScene(newscene);
}
TL;DR calling the method is giving me a nullPointerException, is there any other way to update the balance label when getting back to previous scene?
NOTE: I haven't tested the code, I just wrote it freehand, but it gives you a general idea.
Your main issue is that you are creating a new AccountController in the DepositController. Meaning it's a different one than the one you originally instantiated.
public class AccountController extends Controller implements Initializable {
#FXML private Label gilbert;
#FXML private Label lbBalance;
#FXML private Button deposit;
#FXML private Button btn_showBalance;
private application.DepositController depositController;
#Override
public void initialize(URL location, ResourceBundle resources) {
lbBalance.setText(String.valueOf(BAL));
}
#FXML
public void handleDeposit(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("deposit.fxml"));
Parent depositParent = loader.load();
depositScene = new Scene(depositParent);
depositController = loader.getController();
depositController .setAccountController(this);
mainStage.setScene(depositScene);
mainStage.show();
}
public void updateBal() {
lbBalance.setText(String.valueOf(BAL));
}
}
Here's the second class where you need to set the AccountController to be the one you originally initialized :
public class DepositController extends Controller implements Initializable {
AccountController backtoscene;
#FXML private Label info;
#FXML private Button btn_depositfinal;
#FXML private TextField depositamount;
#FXML private Button btn_back;
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
}
public void setAccountController(AccountController controller){
backtoscene = controller;
}
#FXML
public void handleDepositFinal(ActionEvent event) {
deposit(Integer.parseInt(depositamount.getText()));
info.setVisible(true);
}
#FXML
public void handleBackButton(ActionEvent event) throws IOException {
backtoscene.updateBal();
mainStage.setScene(newscene);
}
}
Now you have access to the AccountController you originally initialized at the start, and the AccountController has access to the correct DepositController.
I a have tabPane with multiple tabs and inside one of the tabPane i have scrollPane. Inside the scrollPane i have a number of UI controls As shown on this image that i want to be dynamically added when i click a button.
This image here shows the UI setup of what i have. The UI controls are in an Hbox which is inside a Vbox.
When a user clicks the add button i would like to add another row with all the controls as shown in this image.
I have looked at post such as these and still cannt get to achieve the same effect on my code.
JavaFX continuous form dynamically add new row with content in gridpane,
Dynamically add elements to a fixed-size GridPane in JavaFX,
How to maintain GridPane's fixed-size after adding elemnts dynamically
When i followed the approach suggested by another stack-overflow member on the first question cited above, to use a listView the code worked. However his suggestion programmatically codes UI controls and when i try to change and use UI controls i created within scene builder it doesn't work. Also when i put the controls inside a tabPane my code doesn't work. Meaning when i click the add button it doesn't add the UI controls as expected.
My question is how can i dynamically add UI controls within a tab inside a tabPane when a button which is also in that tab is clicked.
Here is my code :
public class DynamicalyAddControlsController {
#FXML
private VBox vbox;
#FXML
private HBox hbox;
#FXML
private StackPane stack1;
#FXML
private Label taskid;
#FXML
private TextField taskname;
#FXML
private ComboBox<String> combobox;
#FXML
private TextArea textarea;
#FXML
private Button save;
private ObservableList<Car> cars = FXCollections.observableArrayList();
public void initialize(URL url, ResourceBundle rb) {
cars.addAll(new Car(CAR_TYPE.CAR1), new Car(CAR_TYPE.CAR2), new Car(CAR_TYPE.CAR3));
ListView<Car> carsListView = new ListView<>();
carsListView.setCellFactory(c -> new CarListCell());
carsListView.setItems(cars);
stack1.getChildren().add(carsListView);
}
private class CarListCell extends ListCell<Car> {
private ChoiceBox<CAR_TYPE> choiceBox = new ChoiceBox<>();
public CarListCell(){
choiceBox.setItems(FXCollections.observableArrayList
(CAR_TYPE.values()));
hbox.getChildren().addAll(taskid,taskname,combobox,choiceBox);
vbox.getChildren().addAll(hbox,textarea);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
setGraphic(vbox);
}
#Override
protected void updateItem(Car item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setGraphic(null);
} else {
setGraphic(vbox);
choiceBox.setValue(item.getType());
save.setOnAction(e -> {
Car newCar = new Car(choiceBox.getValue());
cars.add(newCar);
});
}
}
}
private enum CAR_TYPE {
CAR1, CAR2, CAR3;
}
private class Car {
private CAR_TYPE type;
public Car(CAR_TYPE type) {
this.type = type;
}
public CAR_TYPE getType() {
return type;
}
public void setType(CAR_TYPE type) {
this.type = type;
}
}
public void initialize(URL url, ResourceBundle rb) {
}
}
JavaApplication main class
#Override
public void start(Stage primaryStage) throws Exception{
Parent viewB = FXMLLoader.load(getClass().getResource("DynamicalyAddControls.fxml"));
Stage stageB = new Stage();
stageB.setScene(new Scene(viewB));
stageB.show();
}
public static void main(String[] args) {
launch(args);
}
I have implemented fft for my school project(tuner), although, im not able to pass calculated frequency to GUI. I tried binding, keyframes, i just cant seem to get a grasp of it, im really new to java.
public class FrequencyBean {
double freq;
private SimpleDoubleProperty value = new SimpleDoubleProperty(this, "value");
public void setValue(double value){
this.value.set(value);
System.out.println(value+" set");
}
public DoubleProperty getDoublePropertyValue(){
System.out.println("gotvals");
return value;
}
public FrequencyBean(){
freq = 10.0;
}
that is part of my controller, also i got reccomended to use something called tight binding or so, which would be abstracting of this class. Is that good for my code?
This is my main controller:
public class Controller implements Initializable{
FrequencyBean fbean;
#FXML
private Label otherFq;
#FXML
private Text frequency;
#FXML
private Text sharpFq;
#FXML
private Rectangle sharp6;
#FXML
private Text flatFq;
#FXML
private Rectangle center_rectangle;
#FXML
private Rectangle sharp1;
#FXML
private Rectangle sharp2;
#FXML
private Rectangle sharp3;
#FXML
private Rectangle sharp4;
#FXML
private Rectangle sharp5;
#FXML
private Text centerFq;
#FXML
private Rectangle flat6;
#FXML
private Rectangle flat5;
#FXML
private Rectangle flat4;
#FXML
private Rectangle flat3;
#FXML
private Rectangle flat2;
#FXML
private Rectangle flat1;
#Override
public void initialize(URL location, ResourceBundle resources) {
fbean = new FrequencyBean();
otherFq = new Label();
frequency = new Text();
boolean stop = false;
InputThread input = new InputThread();
Task<Void> in = new Task<Void>() {
#Override
protected Void call() throws Exception {
input.run();
return null;
}
};
Thread th0 = new Thread(in);
th0.start();
frequency.textProperty().bind(fbean.getDoublePropertyValue());
}
Rewrite your FrequencyBean correctly as a 'JavaFX-Bean':
public class FrequencyBean {
private SimpleDoubleProperty frequency = new SimpleDoubleProperty();
/**
* #param frequency the frequency to set
*/
public void setFrequency(double value){
this.frequency.set(value);
}
/**
* #return the frequency as double
*/
public double getFrequency(){
return this.frequency.get();
}
/**
* #return the frequency property
*/
public DoubleProperty frequencyProperty(){
return value;
}
public FrequencyBean(){
frequency = 10.0;
}
}
As Jame_D pointed it out: don't initialize a control annotated with #FXML.
Just bind the control in question like so:
...
#FXML
TextField tf_Frequency;
...
fbean = new FrequencyBean(20.3);
tfFrequency.textProperty().bind(fbean.frequencyProperty().asString("%.2f"));
Note that this is correct if you need a uni-directional binding.
There is also a bindBidirectional method.
I want to get the event of two buttons in my custom component.
the component is a imageview with two buttons to move between images, but I need to get the position of the image that is currently displayed, Im storing the key of the image, but I need to know when a button have been pressed outside the custom component, so I can change a Label outside the custom component.
public class TransitionSlider extends AnchorPane {
#FXML
private AnchorPane transitionSliderPane;
#FXML
private ImageView transitionSliderImageView;
#FXML
private Button prevButton;
#FXML
private Button nextButton;
private Map<Integer,Image> imageMap;
private Image currentImage;
private DropShadow imageViewDropShadow;
private int currentKey = 1;
private Image[] images;
public TransitionSlider() {
FXMLLoader loader = new FXMLLoader();
loader.setRoot(this);
loader.setController(this);
loader.setLocation(this.getClass().getResource("TransitionSlider.fxml"));
loader.setClassLoader(this.getClass().getClassLoader());
try {
loader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
prevButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
if(currentKey <= 1){
currentKey = currentKey + 1;
currentImage = imageMap.get(currentKey);
createTransition(transitionSliderImageView, currentImage);
}
}
});
nextButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
if(currentKey <= imageMap.size()){
currentKey = currentKey - 1;
currentImage = imageMap.get(currentKey);
createTransition(transitionSliderImageView, currentImage);
}
}
});
}
// more code here...
}
I want a way to capture the event and get variables inside the component and change a label outside the custom component...
for example:
public class Gallery extends Application {
#FXML
TransitionSlider ts;
Label label;
#Override
public void start(Stage stage) throws Exception {
label = new Label();
TransitionSlider ts = new TransitionSlider();
ts.captureButtonEvent(){ // need a way to capture this
label.setText(ts.getCurrentKey());
}
// more code here....
}
If I understood your question correctly, you want a binding.. Follow these steps:
1) Put bindable field and its getter/setter into TransitionSlider:
private IntegerProperty currentKey = new SimpleIntegerProperty(1);
public int getCurrentKey() {
return currentKey.get();
}
public void setCurrentKey(int val) {
return currentKey.set(val);
}
public IntegerProperty currentKeyProperty() {
return currentKey;
}
2) Bind this property to label's text in Gallery:
label = new Label();
TransitionSlider ts = new TransitionSlider();
label.textProperty.bind(ts.currentKeyProperty().asString());
Alternatively, if you want to do stuff more than just changing label's text, you can add a change listener to currentKeyProperty:
ts.currentKeyProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue) {
label.setText(newValue);
// do other stuff according to "oldValue" and "newValue".
}
});