I'd like to update the value of text in thread(ScheduledService) when I push the button. I can update the value of text in GUI but the value isn't capable of updating it in thread(ScheduledService).
How should I do to update the value of text in thread(ScheduledService) area?
[Procesure]
(1)when I input the value of text and push the button,the value is shown in GUI
by the following code(in EventHandler)
label.setText(text);
Value = Integer.parseInt( text);
(2)I want to pass the value of "Value" to thread by the following
recieve(Value);
(3) the value of "Value" is shown by the following code
System.out.println(a);
But , the value of "Value" is not update .it is still "0".
the value of "0" is the initial value of "Value".
public Integer Value = 0;
My Code is the following:
package javafxapplication16;
import java.io.IOException;
import javafx.application.Application;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBuilder;
import javafx.scene.control.Label;
import javafx.scene.control.LabelBuilder;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFieldBuilder;
import javafx.scene.layout.HBox;
import javafx.scene.layout.HBoxBuilder;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.stage.Stage;
import javafx.stage.StageBuilder;
public class JavaFXApplication16 extends Application {
public Label label;
public Integer Value = 0;
public Button bt_co;
public TextField tx;
#Override
public void start(Stage stage) throws Exception{
tx = TextFieldBuilder.create().text("").build();
Font font = Font.font("Arial",FontPosture.ITALIC,20);
label = LabelBuilder.create().text("value")
.alignment(Pos.CENTER)
.font(font)
.prefWidth(200).build();
bt_co = ButtonBuilder.create().text("")
.prefWidth(200)
.alignment(Pos.CENTER)
.id("")
.build();
HBox root = HBoxBuilder.create().spacing(100).children(tx,label,bt_co).build();
Scene scene = new Scene(root);
scene.addEventHandler(ActionEvent.ACTION,actionHandler);
recieve(Value); // pass the value of "Value" to thread
stage = StageBuilder.create().width(640).height(640).scene(scene).title(" ").build();
stage.show();
}
/* thread */
private void recieve(int a ) throws IOException {
ScheduledService<Boolean> ss = new ScheduledService<Boolean>()
{
#Override
protected Task<Boolean> createTask()
{
Task<Boolean> task = new Task<Boolean>()
{
#Override
protected Boolean call() throws Exception
{
System.out.println(a);
return true;
};
};
return task;
}
};
ss.start();
}
/* Event Handler */
EventHandler<ActionEvent> actionHandler = new EventHandler<ActionEvent>(){
public void handle (ActionEvent e){
Button src =(Button)e.getTarget();
String text = tx.getText();
label.setText(text);
Value = Integer.parseInt( text);
}
};
public static void main(String[] args) {
launch(args);
}
}
Parameter values are evaluated right before the method is invoked. It's that value that is passed, not some value that may be written to some field involved in the expression used as function parameter.
This means what happens is
UI is build.
Event handler is added
receive is executed and the value currently stored in the Value field is passed as parameter, which is 0 at this time.
(ScheduledService prints 0 repeatedly)
At some time the event handler is executed writing a new value to the Value field
(ScheduledService continues printing 0, since this is the value of a)
For any different behavior you'd need to use a expression inside the task that actually changes it's value, e.g.
volatile Integer Value;
...
receive();
...
private void recieve() /* throws IOException */ {
ScheduledService<Boolean> ss = new ScheduledService<Boolean>()
{
#Override
protected Task<Boolean> createTask()
{
Task<Boolean> task = new Task<Boolean>()
{
#Override
protected Boolean call() throws Exception
{
System.out.println(a);
return true;
};
};
return task;
}
};
ss.start();
}
BTW: You should get rid of those uses of builders. They are all deprecated in JavaFX 8, not even documented in the javadocs and will probably be removed in JavaFX 9.
Related
I'm trying to set the width of a JavaFX Dialog to fit my Text.
I know how to do it, but there is a "Fudge Factor" of 32 that I would like to understand.
Can anyone explain how I can determine the value empirically?
I'm using the Zulu OpenJDK 17 with bundled JavaFX under Windows 10.
Here's some example code:
import static javafx.scene.control.Alert.AlertType.INFORMATION;
import javafx.application.Application;
import javafx.scene.control.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class AlertWide extends Application {
private static final String INFO_TEXT = """
A couple of lines...
1) Line 1 is quite short
2) Line 2 is too wide to fit in the standard Alert Label, so it needs to be widened manually, that is to say, once a year
3) the last line
""";
public static void main(final String[] args) {
launch(args);
}
#Override
public void start(final Stage primaryStage) throws Exception {
final var infoWidth = new Text(INFO_TEXT).getBoundsInLocal().getWidth();
final var alert = new Alert(INFORMATION);
; alert.setContentText(INFO_TEXT);
; alert.showAndWait();
setLabelWidth(alert, infoWidth ); alert.showAndWait();
setLabelWidth(alert, infoWidth + 32); alert.showAndWait(); // TODO why 32?
}
private void setLabelWidth(final Alert alert, final double preferredLabelWidth) {
alert.getDialogPane().getChildren().forEach(node -> {
if (node instanceof Label nodeLabel) {
nodeLabel.setPrefWidth(preferredLabelWidth);
}
});
}
}
Having delved into the depths of Dialog, I found a very simple solution.
Rather than iterating through the DialogPane's children, I simply replaced the Label with a new Instance.
P.S. "replaced" is not strictly speaking correct: the built-in DialogPane Label is set to unmanaged & invisible & so takes no part in the rendering.
The following was just fine for my purposes:
import static javafx.scene.control.Alert.AlertType.INFORMATION;
import javafx.application.Application;
import javafx.scene.control.*;
import javafx.stage.Stage;
public class AlertWideSetContent extends Application {
private static final String INFO_TEXT = """
A couple of lines...
1) Line 1 is quite short
2) Line 2 is too wide to fit in the standard Alert Label, so it needs to be widened manually, that is to say, once a year
3) the last line
""";
public static void main(final String[] args) {
launch(args);
}
#Override
public void start(final Stage primaryStage) throws Exception {
final var alert = new Alert(INFORMATION);
; alert.getDialogPane().setContent(new Label(INFO_TEXT));
; alert.showAndWait();
}
}
But, as #kleopatra observed, setting the Preferred Width to -1 (USE_COMPUTED_SIZE) does it too:
import static javafx.scene.control.Alert.AlertType.INFORMATION;
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.stage.Stage;
public class AlertWideUseComputedSize extends Application {
private static final String INFO_TEXT = """
A couple of lines...
1) Line 1 is quite short
2) Line 2 is too wide to fit in the standard Alert Label, so it needs to be widened manually, that is to say, once a year
3) the last line
""";
public static void main(final String[] args) {
launch(args);
}
#Override
public void start(final Stage primaryStage) throws Exception {
final var alert = new Alert (INFORMATION);
; alert.setContentText(INFO_TEXT );
for (final Node node : alert.getDialogPane().getChildren()) {
if (node instanceof Label nodeLabel) {
nodeLabel.setPrefWidth(Label.USE_COMPUTED_SIZE);
}
}
alert.showAndWait();
}
}
I want to test, if a certain TextField (maybe there are several TextFields) has an EventHandler set via setOnAction. In the test code I can set the content (e.g. "HelloWorld") into the TextField. In my understanding I have to place the curser at the end of the text in the TextField and then, call press(KeyCode.ENTER). Is there a TestFX call to place the curser a a certain point within a certain TextField? Or is there another way to test this?
Regards, Jörg
[EDIT]
Here is an example:
package testestfx;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
public class SimpleGui extends VBox {
private static final org.slf4j.Logger logger =
org.slf4j.LoggerFactory.getLogger(SimpleGui.class);
private TextField field1;
private TextField field2;
private Label label;
public SimpleGui() {
field1 = new TextField("Textfield1");
field2 = new TextField("Textfield2");
field1.setOnAction((event) -> onActionDoThis());
field2.setOnAction((event) -> onActionDoThat());
label = new Label("Label");
getChildren().addAll(field1, field2 );
}
public TextField getField1() {
return field1;
}
public TextField getField2() {
return field2;
}
public Label getLabel() {
return label;
}
void onActionDoThis() {
logger.info("This");
label.setText("This");
}
void onActionDoThat() {
logger.info("That");
label.setText("That");
}
}
And here is the test:
package testtestfx;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.stage.Stage;
import org.junit.Test;
import org.testfx.framework.junit.ApplicationTest;
import testestfx.SimpleGui;
import static org.junit.Assert.assertEquals;
public class TestSimpleGUI extends ApplicationTest {
private static final org.slf4j.Logger logger =
org.slf4j.LoggerFactory.getLogger(TestSimpleGUI.class);
private SimpleGui gui;
#Override
public void start(final Stage stage) throws Exception {
super.start(stage);
gui = new SimpleGui();
stage.setScene(new Scene(gui));
stage.show();
}
#Test
public void testEnterKeystroke() {
TextField t2 = gui.getField2();
TextField t1 = gui.getField1();
Label l1 = gui.getLabel();
t2.setText("bar");
t1.setText("foo");
press(KeyCode.ENTER);
assertEquals("That", l1.getText());
}
}
The console output is:
15:43:29.366 [JavaFX Application Thread] [INFO] SimpleGui - This
org.junit.ComparisonFailure:
Expected :That
Actual :This
```
You can set the focus on a TextField like this:
myTextField.requestFocus();
kind regards
Amadeus
I am trying to build a Combobox in JavaFX that should work as followed.
The user should only type numbers in, but the typed numbers have to be formattet.
ex. 111-111-1111.
So if the user types in three numbers a - should be added automatically.
I figured out how to do that.
I blocked everything but numbers with a TexFormatter.
Now the main Part of the problem comes the part after this.
I added a keyevent.key_released place the caret at the end when a key is released.
But if the user is typing too fast it won't work.
Most of the time it works just fine like that, but when is the user every doing something only the way I expect?
I could not find another way to get the actual value of the combobox, because it seems to refresh after hitting enter or so.
Adding the - in the Textformatter resultet in the programm listening to itself and I wasn't able to place the caret at the end position.
import java.util.function.UnaryOperator;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextFormatter;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author
*/
public class tester extends Application{
ComboBox<String> combo = new ComboBox<String>();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
System.out.println("test");
HBox root = new HBox();
//
UnaryOperator<TextFormatter.Change> filter = new UnaryOperator<TextFormatter.Change>() {
#Override
public TextFormatter.Change apply(TextFormatter.Change t) {
System.out.println(t.getText());
if (t.isReplaced())
if(t.getText().matches("[^0-9]")) {
t.setText(t.getControlText().substring(t.getRangeStart(), t.getRangeEnd()));}
if (t.isAdded()) {
// Add in Formatter //
if (t.getControlText().length() == 2 || t.getControlText().length() == 6 && t.getText().matches("[0-9]")){
t.setText(t.getText() + "-");
combo.getEditor().end();
}
//
if (t.getText().matches("[^0-9]")) {
t.setText("");}
}
return t;
}
};
combo.setEditable(true);
combo.getEditor().setTextFormatter(new TextFormatter<>(filter));
combo.getEditor().addEventFilter(KeyEvent.KEY_RELEASED, e -> {
combo.getEditor().end();
});
root.getChildren().add(combo);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
I would like to set a units to a spinner which is accepting only numbers.
Ideally the spinner textfield would display the units right next to the number itself (example: 2500 ms or 125 % etc.).
Is there a way to set a format to the textfield?
I thought it would be fairly easy but I can't find a way.
Thanks, Jan
The spinner value factory has a converter that is used to convert the value to and from the text value displayed or entered in the editor. You can use this to configure how the value is displayed:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class SpinnerWithUnits extends Application {
#Override
public void start(Stage primaryStage) {
Spinner<Integer> spinner = new Spinner<>();
spinner.setEditable(true);
SpinnerValueFactory.IntegerSpinnerValueFactory valueFactory = new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 10000, 0, 100);
valueFactory.setConverter(new StringConverter<Integer>() {
#Override
public String toString(Integer value) {
return value.toString()+" ms";
}
#Override
public Integer fromString(String string) {
String valueWithoutUnits = string.replaceAll("ms", "").trim();
if (valueWithoutUnits.isEmpty()) {
return 0 ;
} else {
return Integer.valueOf(valueWithoutUnits);
}
}
});
spinner.setValueFactory(valueFactory);
StackPane root = new StackPane(spinner);
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Of course, you probably want to use a more appropriate type than Integer as the type of the spinner: in this case it would probably make more sense to use a Duration. You can still use a converter on the (now custom) spinner value factory to display the value formatted as you need.
I'm trying to follow: CheckBoxTableCell changelistener not working
The given code answer to that question is below and dependent on the model 'Trainee'
final CheckBoxTableCell<Trainee, Boolean> ctCell = new CheckBoxTableCell<>();
ctCell.setSelectedStateCallback(new Callback<Integer, ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(Integer index) {
return table.getItems().get(index).selectedProperty();
}
});
I would like to obtain that selected property value and add a listener to it, but I don't think I'm doing it right. I attempted to add all kind of listeners to it so that I know when the checkbox in each row is changed and I can add logic to each. I presume the code above allow ctCell to now observe changes and I can just call a change listener to it and detect selection per given row.
I tried some change properties here just to detect the changes:
ctCell.selectedStateCallbackProperty().addListener(change -> {
System.out.println("1Change happened in selected state property");
});
ctCell.selectedProperty().addListener(change -> {
System.out.println("2Change happened in selected property");
});
ctCell.itemProperty().addListener(change -> {
System.out.println("3Change happened in item property");
});
ctCell.indexProperty().addListener(change -> {
System.out.println("4Change happened in index property");
});
...but none seemed to be called.
This is the shorten set up that I have:
requestedFaxCol.setCellValueFactory(new PropertyValueFactory("clientHasRequestedFax"));
requestedFaxCol.setCellFactory(CheckBoxTableCell.forTableColumn(requestedFaxCol));
final CheckBoxTableCell<ClinicClientInfo, Boolean> ctCell = new CheckBoxTableCell<>();
ctCell.setSelectedStateCallback(new Callback<Integer, ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(Integer index) {
return clinicLinkTable.getItems().get(index).clientHasRequestedFaxProperty();}
});
Let me know if I need to provide a more information! What am I not understanding in terms of why I cannot bridge a change listener to my table cell check boxes? Or if someone can point out the a direction for me to try. Thanks!
UPDATE to depict the ultimate goal of this question
package testapp;
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TestApp extends Application {
private TableView<ClinicClientInfo> clientTable = new TableView<>();
private TableColumn<ClinicClientInfo, String> faxCol = new TableColumn<>("Fax");
private TableColumn<ClinicClientInfo, Boolean> requestedFaxCol = new TableColumn<>("Requested Fax");
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
ObservableList<ClinicClientInfo> list = FXCollections.observableArrayList(
new ClinicClientInfo("", false),
new ClinicClientInfo("945-342-4324", true));
root.getChildren().add(clientTable);
clientTable.getColumns().addAll(faxCol, requestedFaxCol);
clientTable.setItems(list);
clientTable.setEditable(true);
clientTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
faxCol.setCellValueFactory(new PropertyValueFactory<>("clinicFax"));
faxCol.setVisible(true);
requestedFaxCol.setCellValueFactory(new PropertyValueFactory("clientHasRequestedFax"));
requestedFaxCol.setCellFactory(CheckBoxTableCell.forTableColumn(requestedFaxCol));
requestedFaxCol.setVisible(true);
requestedFaxCol.setEditable(true);
//My attempt to connect the listener
//If user selects checkbox and the fax value is empty, the alert should prompt
CheckBoxTableCell<ClinicClientInfo, Boolean> ctCell = new CheckBoxTableCell<>();
ctCell.setSelectedStateCallback(new Callback<Integer, ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(Integer index) {
ObservableValue<Boolean> itemBoolean = clientTable.getItems().get(index).clientHasRequestedFaxProperty();
itemBoolean.addListener(change -> {
ClinicClientInfo item = clientTable.getItems().get(index);
if(item.getClinicFax().isEmpty() && item.getClientHasRequestedFax()){
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("Warning");
alert.show();
}
});
return itemBoolean;
}
});
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public class ClinicClientInfo {
private final StringProperty clinicFax;
private final BooleanProperty clientHasRequestedFax;
public ClinicClientInfo(String fax, boolean clientHasRequestedFax){
this.clinicFax = new SimpleStringProperty(fax);
this.clientHasRequestedFax = new SimpleBooleanProperty(clientHasRequestedFax);
}
public String getClinicFax(){
return clinicFax.get();
}
public void setClinicFax(String clinicFax){
this.clinicFax.set(clinicFax);
}
public StringProperty clinicFaxProperty(){
return clinicFax;
}
public boolean getClientHasRequestedFax(){
return clientHasRequestedFax.get();
}
public void setClientHasRequestedFax(boolean clientHasRequestedFax){
this.clientHasRequestedFax.set(clientHasRequestedFax);
}
public BooleanProperty clientHasRequestedFaxProperty(){
return clientHasRequestedFax;
}
}
}
The goal is to get a prompt when the user tries to select fax request when the fax string is empty.
This is already fully explained in the question you already linked, so I don't know what more I can add here other than just to restate it.
The check boxes in the cell are bidirectionally bound to the property that is returned by the selectedStateCallback. If no selectedStateCallback is set, and the cell is attached to a column whose cellValueFactory returns a BooleanProperty (which covers almost all use cases), then the check box's state is bidirectionally bound to that property.
In your code sample, I don't understand what ctCell is for. You just create it, set a selectedStateCallBack on it, and then don't do anything with it. It has nothing to do with your table and nothing to do with the cell factory you set.
So in your case, no selected state callback is set on the cells produced by your cell factory, and the cell value factory returns a boolean property, so the default applies, and the check box state is bidirectionally bound to the property returned by the cell value factory. All you have to do is register a listener with those properties.
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class CheckBoxTableCellTestApp extends Application {
private TableView<ClinicClientInfo> clientTable = new TableView<>();
private TableColumn<ClinicClientInfo, String> faxCol = new TableColumn<>("Fax");
private TableColumn<ClinicClientInfo, Boolean> requestedFaxCol = new TableColumn<>("Requested Fax");
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
ObservableList<ClinicClientInfo> list = FXCollections.observableArrayList(
new ClinicClientInfo("", false),
new ClinicClientInfo("945-342-4324", true));
// add listeners to boolean properties:
for (ClinicClientInfo clinic : list) {
clinic.clientHasRequestedFaxProperty().addListener((obs, faxWasRequested, faxIsNowRequested) ->{
System.out.printf("%s changed fax request from %s to %s %n",
clinic.getClinicFax(), faxWasRequested, faxIsNowRequested);
});
}
root.getChildren().add(clientTable);
clientTable.getColumns().addAll(faxCol, requestedFaxCol);
clientTable.setItems(list);
clientTable.setEditable(true);
clientTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
faxCol.setCellValueFactory(new PropertyValueFactory<>("clinicFax"));
faxCol.setVisible(true);
requestedFaxCol.setCellValueFactory(new PropertyValueFactory<>("clientHasRequestedFax"));
requestedFaxCol.setCellFactory(CheckBoxTableCell.forTableColumn(requestedFaxCol));
requestedFaxCol.setVisible(true);
requestedFaxCol.setEditable(true);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public class ClinicClientInfo {
private final StringProperty clinicFax;
private final BooleanProperty clientHasRequestedFax;
public ClinicClientInfo(String fax, boolean clientHasRequestedFax){
this.clinicFax = new SimpleStringProperty(fax);
this.clientHasRequestedFax = new SimpleBooleanProperty(clientHasRequestedFax);
}
public String getClinicFax(){
return clinicFax.get();
}
public void setClinicFax(String clinicFax){
this.clinicFax.set(clinicFax);
}
public StringProperty clinicFaxProperty(){
return clinicFax;
}
public boolean getClientHasRequestedFax(){
return clientHasRequestedFax.get();
}
public void setClientHasRequestedFax(boolean clientHasRequestedFax){
this.clientHasRequestedFax.set(clientHasRequestedFax);
}
public BooleanProperty clientHasRequestedFaxProperty(){
return clientHasRequestedFax;
}
}
}