Calculate % of textbox filled in - java

I am working on a javafx project in which I'm providing a textbox to be filled in.I want to calculate % of textbox filled in..say for eg 100 characters is a limit and 50 are filled in so 50 should be the % value but it should change automatically as i keep typing .I don't know exactly how to do that (specially the Automatic thing). I want to show that % value on progressbar like this :
(Ignore buttons)
Need help! Thank you in advance

You can define yourself a DoubleBinding which is bound to the textProperty and on each change revaluates it's value.
final double max = 100;
TextField text = new TextField();
DoubleBinding percentage = new DoubleBinding() {
{
super.bind(text.textProperty());
}
#Override
protected double computeValue() {
return text.getText().length() / max;
}
};
In the static initializer block of the DoubleBinding you bind the textProperty of your TextField. This will cause the reevaluation of the binding through the computeValue method. Then you can bind it to the textProperty of a Label:
Label lbl = new Label();
lbl.textProperty().bind(percentage.asString());
Of course you can also bind it to other controls than a Label like a ProgressBar or ProgressIndicator:
ProgressBar bar = new ProgressBar();
bar.progressProperty().bind(percentage);
ProgressIndicator indicator = new ProgressIndicator();
indicator.progressProperty().bind(percentage);
This binding then can be used to display the percentage already filled in. You might also take a look at this documentation by Oracle. The type of this binding is a low-level binding.

Related

JavaFX, variable does not update on actionEvent

I have an issue where I have a button and when clicked I want to update a value but I cannot update it because the lambda expression needs to be final. In this example I want to add to the current number the change number and save it, so there is a new current and every time I click the button, it takes it and add change. How can I get around this issue?
This is the class, I want when one of the buttons with an arrow is selected to either increase or decrease the value by 'int change'. Now, when you click the button it takes the current value and increases it by 'change' but it does not update it? How can I fix this?
And, also how can I add padding or margins to an imageView as I tried everything but it does not work? Or can I add padding to a specific part of a borderPane?
Image with buttons
private Pane getControls(String paneName, String imageName, String symbol, double min, double max, double def, double change) {
BorderPane borderPane = new BorderPane();
ImageView image = getImage(imageName);
image.setFitHeight(80);
image.setFitWidth(60);
Label defLabel;
int current = (int) def;
if (min > 20) {
int def1 = (int) def;
defLabel = new Label(def1 + "");
} else {
defLabel = new Label(def + "");
}
defLabel.setStyle("-fx-text-fill: #ff0000;");
defLabel.setFont(new Font(50));
Label symbolLabel = new Label(symbol);
symbolLabel.setStyle("-fx-text-fill: #ffffff;");
symbolLabel.setFont(new Font(24));
symbolLabel.setPadding(new Insets(30, 40, 0, 0));
borderPane.setRight(symbolLabel);
borderPane.setCenter(defLabel);
borderPane.setLeft(image);
ImageView imageUp = getImage("up-icon.png");
ImageView imageDown = getImage("down-icon.png");
imageUp.setFitHeight(50);
imageUp.setFitWidth(50);
imageDown.setFitHeight(50);
imageDown.setFitWidth(50);
Button buttonUp = new Button();
Button buttonDown = new Button();
buttonUp.setOnAction((ActionEvent event) -> {
defLabel.setText((current + (int) change) + "");
current += (int) change;
System.out.println((current + (int) change) + " Up button pressed.");
});
buttonUp.setGraphic(imageUp);
buttonDown.setGraphic(imageDown);
buttonUp.setPrefSize(50, 50);
buttonDown.setPrefSize(50, 50);
buttonUp.setStyle("-fx-background-color: #6b4218;");
buttonDown.setStyle("-fx-background-color: #6b4218;");
HBox hbox = new HBox(12);
hbox.getChildren().add(buttonUp);
hbox.getChildren().add(buttonDown);
hbox.setAlignment(Pos.CENTER);
hbox.setPadding(new Insets(0, 0, 24, 0));
borderPane.setBottom(hbox);
borderPane.setPadding(new Insets(100));
BorderedTitledPane borderedTitledPane = new BorderedTitledPane(paneName, borderPane, 300, 200);
return borderedTitledPane;
}
I'll try to explain it to you using an example
If you don't understand my explaination, then read this tutorial (it is really well explained there): https://www.baeldung.com/java-lambda-effectively-final-local-variables
You can only access a variable from within a lambda if you could set that variable to final:
int i = 5; // You could set this variable to final and it would still compile
runSomething(() -> {
System.out.println(i); // Will compile since i could be set final
});
and that's what happens when you change i again:
int i = 5; // i was defined
// ...
i = 10; // assigned new value to i therefore i could no longer be final
runSomething(() -> {
System.out.println(i); // Will NOT compile since i could not be final anymore after it got changed
});
before Java 1.8+ we had to declare variables final to use them when implementing an interface (/ lambda (only exists since 1.8)) like this.
Therefore to access a variable from outside, (unless it is a field of a class) inside of a lamda you would need to be able to make it final. You can never change such a value (like you tried to) since you can't change final variables. Your 'current' variable is 'final' inside of your lambda, even though you never set it to final (this is because the method containing the variable could have already finished its execution before the lamda is being called from somewhere else. Since you can't alter the past the variable is unchangable inside the lamda body).
btw. your 'defLabel' is also 'final' inside of your lambda's body, since it never got changed (that's also why you can access it inside of the lamda)

How can I display a DoubleProperty on my scene?

I want this totalSalesAmountProperty to display the value but even after it is updated, and has an actual value, it still doesn't display. I know this has a value because I system.out the getter method and I get a value. Why would that be happening?
Label lblTotalSales = new Label(String.valueOf(newSale.getTotalSalesAmount1()));
You need to bind the label's text property to the totalSalesAmountProperty:
label.textProperty().bind(totalSalesAmountProperty);
Then the label text will automatically update any time the totalSalesAmountProperty is modified.
try this (what is the return type of getTotalSalesAmount1() ?? Here I consider it double)
Label lblTotalSales = new Label(" " + newSale.getTotalSalesAmount1());
By using
Label lblTotalSales = new Label(String.valueOf(newSale.getTotalSalesAmount1()));
you set the text to the String returned by String.valueOf(newSale.getTotalSalesAmount1()) just before calling the Label constructor, i.e. it yields the same result as
String s = String.valueOf(newSale.getTotalSalesAmount1());
Label lblTotalSales = new Label(s);
Strings are neither mutable nor observable in java and therefore the text is not automatically updated.
To fix this bind the textProperty of the Label to the String version of the DoubleProperty. This will add listeners to the property that will update the text of the Label every time the DoubleProperty changes.
DoubleProperty propertyToShow = ...
Label label = new Label();
label.textProperty().bind(propertyToShow.asString());

How to make ticker(animated text) in javafx [duplicate]

I am trying to achieve effect similar to marquee - line of long (in my case) text which is moved in horizontal axis. I managed to get it work, but I can't call it satisfactory.
My Controller class looks as below:
#FXML
private Text newsFeedText;
(...)
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
TranslateTransition transition = TranslateTransitionBuilder.create()
.duration(new Duration(7500))
.node(newsFeedText)
.interpolator(Interpolator.LINEAR)
.cycleCount(Timeline.INDEFINITE)
.build();
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
int width = gd.getDisplayMode().getWidth();
transition.setFromX(width);
transition.setToX(-width);
transition.play();
}
newsFeedText is binded to some text source which is dynamically updated, so it contains various amount of text.
My code has at least two drawbacks:
Transition goes from -width to +width; width is monitor's resolution width
There will be moments when text will not be visible at all if window is not full-screened.
If text will be longer and newsFeedText width will be greater than monitor's resolution width then transition will disappear "in half" (still being on a screen).
Currently Duration is not dependent on a width of newsFeedText.
Now, it's nothing worng, but if transition's fromX and toX were be dynamically calculated then it will result in various speeds of marquee.
How to get rid of these drawbacks?
I have managed it to work, any recalculations can happen only after transition is stopped so we cannot set its cycleCount to Timeline.INDEFINITE. My requirement was that I could change text inside component so there are fxml wirings:
#FXML
private Text node; // text to marquee
#FXML
private Pane parentPane; // pane on which text is placed
The code which works is:
transition = TranslateTransitionBuilder.create()
.duration(new Duration(10))
.node(node)
.interpolator(Interpolator.LINEAR)
.cycleCount(1)
.build();
transition.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
rerunAnimation();
}
});
rerunAnimation();
where rerunAnimation() is:
private void rerunAnimation() {
transition.stop();
// if needed set different text on "node"
recalculateTransition();
transition.playFromStart();
}
and recalculateTransition() is:
private void recalculateTransition() {
transition.setToX(node.getBoundsInLocal().getMaxX() * -1 - 100);
transition.setFromX(parentPane.widthProperty().get() + 100);
double distance = parentPane.widthProperty().get() + 2 * node.getBoundsInLocal().getMaxX();
transition.setDuration(new Duration(distance / SPEED_FACTOR));
}
You should be able to do this by listening to your scene's widthProperty. You can either access this via newsFeedText.getScene().widthProperty() or get a reference from your main class and expose it from there or pass it to a method or constructor to access within your class that declares newsFeedText.
The benefit of this approach is that now your logic is dependent upon the width of your scene (a dynamic dependency) rather than the width of your monitor (a static dependency). Note that I have not tested this approach but at the moment see no reason (perhaps naively) it shouldn't work.
As for your duration dependency, you can solve that by performing some sort of calculation based on the length of the text in newsFeedText. Something like Duration.seconds(newsFeedText.get Text().length()/denominator) where denominator is some value you specify (such as 7500, as in your code). This will make your duration dynamically computed based on the length of your text.
If you want to operate with the width of newsFeedText itself, rather than the length of its text, then simply replace newsFeedText.getText().length() with newsFeedText.getWidth(). Ensure you perform this computation after newsFeedText has been laid out so a call to get its width returns the actual width. You can also replace the call with any of getPrefWidth(), getMinWidth(), or getMaxWidth().

using LayoutClickListener to terminary replace components

I have grid layout witch some fields added like that:
private Component userDetailsTab(final User user) {
final GridLayout details = new GridLayout(2, 1);
details.setMargin(true);
details.setSpacing(true);
details.addComponent(createDetailLabel(Messages.User_Name));
final Component username = createDetailValue(user.getName());
details.addComponent(username);
...
I have also Layout click listener which replace labels on text field, it looks like that:
final TextField tf = new TextField();
details.addListener(new LayoutClickListener() {
private static final long serialVersionUID = -7374243623325736476L;
#Override
public void layoutClick(LayoutClickEvent event) {
Component com = event.getChildComponent();
if (event.getChildComponent() instanceof Label) {
Label label = (Label)event.getChildComponent();
details.replaceComponent(com, tf);
tf.setValue(label.getValue());
}
}
});
In future I want to enable click on label, edit it and write changes to database after clicking somewhere else (on different label for example).
Now when I click on 1st label and then on 2nd label, effect is: 1st has value of 2nd and 2nd is text field witch value of 2nd. Why it's going that way? What should i do to after clicking on 1st and then 2nd get 1st label witch value of 1st?
You don't need to swap between Labels and TextFields, you can just use a TextField and style it look like a Label when it's not focused.
When I tried to create click-to-edit labels, it created a ton of extra work for me. I'd discourage it (and do as Patton suggests in the comments).
However, if you're going to insist on trying to create in-place editing, you will want to do the following:
Create a new class that extends a layout (e.g. HorizontalLayout), which can swap out a label for a text field
use LayoutClickListener to removeComponent(myLabel) and addComponent(myTextField)
use BlurListener to swap back to the label
use ValueChangeListener on the text field to copy its value to the label
This is a still a bad idea because:
Users cannot see affordances as easily (they can't tell what's editable)
Users cannot use the keyboard to tab to the field they want to edit
It adds unncessary complexity (maintenance time, etc).
I would recommend, if you want in-place editing, just show the text field, and save the new value with the BlurListener.

How to add text on jprogressbar?

I am using a jprogressbar to indicate the availability status.
i want to display a text of 40%[assumption] inside the progressbar.
how to do it? the text was changed according to the availability value
You can use:
Initialising:
progressBar.setStringPainted(true);
Updating:
progressBar.setValue(newValue);
Use setStringPainted(true) to show the Percentage of work completed.
Use setValue() which will help setting the incremental value and setString() to display the end message when done...
Here is an example from my code base :
final JProgressBar bar = new JProgressBar(0 , 100); // 0 - min , 100 - max
bar.setStringPainted(true);
panel.add(bar); // panel is a JPanel's Obj reference variable
JButton butt = new JButton("start");
butt.addActionListener(){
public void actionPerformed(){
new Thread(new Runnable(){
public void run(){
int x = 0;
while(x<=100) {
x++;
bar.setValue(x); // Setting incremental values
if (x == 100 ){
bar.setString("Its Done"); // End message
try{
Thread.sleep(200);
}catch(Exception ex){ }
}
}).start();
}
});
I am using a jprogressbar to indicate the availability status.
please read tutorial about JProgressBar
i want to display a text of 40%[assumption] inside the progressbar.
Using Determinate Progress Bars in the JProgressBar tutorial
how to do it? the text was changed according to the availability value
more in the SwingWorker tutorial
This will show the progress inside the bar
progressBar.setStringPainted(true);
This shows the progress percentage inside the progress bar
progressBar.setStringPainted(true);
I'm unclear if your [assumption] is part of the string you want displayed. If so, the complete solution would be something like:
private static final String PROGRESS_MASK = "%d%% [assumption]";
public void someMethod() {
...
progressBar.addChangeListener(new ChangeListener() {
#Override
void stateChanged(ChangeEvent e) {
progressBar.setString(String.format(PROGRESS_MASK,
progressBar.getValue()));
}
}
progressBar.setStringPainted(true);
}
... as you would be unable to rely on the default string which merely displays the percentage.
Two things you should notice here. Those are,
1) You have to set paintString variable of JProgressBar using setStringPainted method. You can do that like
jprogressBar.setStringPainted(true)
you have to do this because,
isStringPainted()
method should return true, if the progress bar has to show the values or percentage of progress on it.
2) Now to customize with your custom value, set the your custom on jprogressBar instance using
jprogressBar.setString(customString)
then it should work fine.
Here is the tutorial link which shows how to set the value (i.e. 10% or 40%...) according to the status of the progress bar http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html

Categories