I have a Scala Program with JavaFX GUI. When I fire a button, I disable my button and change a label text before calling a function that takes several tens of seconds to execute (RobotWebCore.runSearch()). The problem is that the GUI do not display the changes I bring to it before calling my function (but only after) :/
Here my code:
class GuiController extends Initializable {
#FXML
var GUI : VBox = null;
#FXML
var RQ_TEXT_FIELD : TextField = null;
#FXML
var SEARCH_BUTTON : Button = null;
#FXML
var STATE_LABEL : Label = null;
override def initialize(location : URL, resources : ResourceBundle ) = {
Printer.activeGui = true;
GuiController.instance = this;
SEARCH_BUTTON.setOnMousePressed(e => runSearch());
}
def setStateMessage(message: String) = STATE_LABEL.setText(message);
private def runSearch() = {
val p = ExpressionParser.LocalParser.parse(RQ_TEXT_FIELD.getText);
if (p.successful) {
GUI.setCursor(Cursor.WAIT);
SEARCH_BUTTON.setDisable(true);
setStateMessage("Recherche en cours");
RobotWebCore.runSearch(p.get);
SEARCH_BUTTON.setDisable(false);
GUI.setCursor(Cursor.DEFAULT);
} else {
setStateMessage("RequĂȘte invalide ! Exemple : (chat and chat) or perroquet");
}
}
}
Related
I have this code:
using Gtk;
class ConquerLauncher : Gtk.Application {
protected override void activate() {
var window = new ApplicationWindow(this);
window.add(new InputList());
window.show_all();
}
}
public int main(string[] args) {
return new ConquerLauncher().run(args);
}
class InputList : Box {
public InputList() {
this.set_orientation(Orientation.VERTICAL);
var listStore = new Gtk.ListStore(1,typeof(Label));
var treeView = new TreeView.with_model(listStore);
this.pack_start(treeView);
this.pack_start(new InputBox(this,listStore));
var column = new TreeViewColumn();
column.set_title("Foo bar's");
treeView.append_column(column);
treeView.set_model(listStore);
}
}
class InputBox : Box {
public InputBox(InputList list,Gtk.ListStore store) {
this.set_orientation(Orientation.HORIZONTAL);
var entry = new Entry();
this.pack_start(entry);
var button = new Button.with_label("Add foo bar");
this.pack_start(button);
button.clicked.connect(() => {
var text = entry.text;
entry.text = "";
TreeIter tp;
store.append(out tp);
store.set(tp, 0, new Label(text), -1);
this.show_all();
list.show_all();
});
}
}
What I want to do:
I want to create some sort of input form consisting of three elements:
In an Entry the user should write some text. If the presses the button, it should be added to the TreeView with a ListStore as a model.
Expectation:
The user enters a text, presses the button, the contents of the Entry are added to the TreeView and the text input field is cleared.
Reality:
Everything works, except the label that is added to the TreeView is blank.
Before:
Here an example input:
After pressing the button:
I would like to make click counter in Scala Swing. I used for this ActionListener interface. But I don't know if I did it correctly. The program works, but I want to find out how to do this according to best practies. I will be very thankful for the answer how to do it correctly.
import javax.swing._
import java.awt._
import java.awt.event._
class UI extends JFrame {
var title_ : String = "Hello, Swing in Scala"
setTitle(title_)
val textArea = new JTextArea
var text : String = "Hello, Swing world in Scala!"
textArea.setText(text)
val scrollPane = new JScrollPane(textArea)
val panel = new JPanel
var text2 : String = "Click Here"
val button =new JButton(text2)
panel.add(button)
var clicks:Int = 0
def onClick(): Unit = {
clicks += 1
text = "Number of button clicks: " + clicks.toString
textArea.setText(text)
}
button.addActionListener(new ActionListener {
override def actionPerformed(e: ActionEvent): Unit = onClick() })
getContentPane.add(scrollPane, BorderLayout.CENTER)
getContentPane.add(panel, BorderLayout.SOUTH)
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
setSize(new Dimension(600, 400))
setLocationRelativeTo(null)
def display() {
setVisible(true)
}
}
object SwingExample extends App {
val ui = new UI
ui.display()
println("End of main function")
}
there are simple things, which improve code quality and maintainability.
it seems that text, text2 and title_ can remove and put that value directly into.
to shorten it, try this statement for the onClick
def onClick(): Unit = {
clicks += 1
textArea.setText(s"Number of button clicks: $clicks")
}
see String Interpolation.
you can shorten your ActionListener by
button.addActionListener(e => onClick())
We would like to implement AutoCompleteTextField field, once user has selected the field from AutoComplete result, then system would auto populate on other text field, i have used the component AjaxFormComponentUpdatingBehavior (blur), however this will take effect on every text input from AutoCompleteTextField field, but if i change to AjaxFormComponentUpdatingBehavior (change), it doesnt work.
Below is the sample code:
AutoCompleteTextField<String> field_postcode = new AutoCompleteTextField<String>("field_postcode",
new PropertyModel<String>(getModelObject(), "wAdditionalInfo.postal"), autoCompleteRenderer) {
private static final long serialVersionUID = 1L;
#Override
protected Iterator<String> getChoices(String input) {
if (Strings.isEmpty(input)) {
List<String> emptyList = Collections.emptyList();
return emptyList.iterator();
}
List<String> choices = new ArrayList<String>();
List<Postcode> postcodeList = getProfileManager().findAllPostcodeByPostcode(input);
for (Postcode p : postcodeList) {
String postcode = p.getPostcode();
if (postcode.startsWith(input)) {
choices.add(p.getPostcode());
if (choices.size() == 10) {
break;
}
}
}
return choices.iterator();
}
};
field_postcode.setRequired(true);
field_postcode.add(new AjaxFormComponentUpdatingBehavior("blur"){
private static final long serialVersionUID=-1107858522700306810L;
#Override protected void onUpdate( AjaxRequestTarget target){
Postcode postcode = getProfileManager().findPostcodeByPostcode(field_postcode.getInput());
if (postcode != null) {
City city = postcode.getCity();
State state = city.getState();
field_city.setModelObject(city.getCity());
ddl_state.setModelObject(state);
if (isDisplayTip) {
//isDisplayTip true mean is from widrawal webform
isReadonly = true;
} else {
field_city.setEnabled(false);
}
ddl_state.setEnabled(false);
} else {
if (isDisplayTip) {
isReadonly = false;
} else {
field_city.setEnabled(true);
}
ddl_state.setEnabled(true);
}
target.add(field_city, ddl_state);
}
}
);
Is there any api from wicket to achieve this? We need to have something when user select the option from Auto complete, then it only onUpdate method of AjaxFormComponentUpdatingBehavior
According to https://github.com/apache/wicket/blob/cbc237159c4c6632b4f7db893c28ab39d1b40ed4/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/wicket-autocomplete.js#L620 it should trigger change event on the HTMLInputElement and thus notify you on the server side.
Use the browser debugger to see whether https://github.com/apache/wicket/blob/cbc237159c4c6632b4f7db893c28ab39d1b40ed4/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/autocomplete/wicket-autocomplete.js#L453 is executed and whether it leads to an Ajax call with the value in the parameters.
In JavaFX, how do you model the following:
I show a List of Customers in a Scene. On the left side there is a table on the right side (contentPane) the currently select customer's details are shown.
(Relevant part of) Main-Controller:
#jfxf.FXML
protected def newButtonPressed(): Unit =
{
contentPane.getChildren.clear
contentPane.getChildren.add(FXMLLoader.load(GUILoader.load("customers/form.fxml")))
}
There is a Button to add a new Customer. Upon clicking this button instead of opening a Popup, I replace the "details"-part of the scene and add a form there.
Now for this form (designed - like the rest of the GUI - in the SceneBuilder and saved as .fxml) I use another controller.
class Form extends Main with jfxf.Initializable
{
#jfxf.FXML
private var foreNameTextField: jfxsc.TextField = _
#jfxf.FXML
private var lastNameTextField: jfxsc.TextField = _
#jfxf.FXML
private var ageTextField: jfxsc.TextField = _
override def initialize(url: URL, resourceBundle: ResourceBundle): Unit =
{
}
#jfxf.FXML
protected def ok(): Unit =
{
// TODO validation
val newPerson = new Person(-1, foreNameTextField.getText, lastNameTextField.getText, ageTextField.getText.toInt)
// Save to DB
// Close whole form
}
}
When I'm done with filling in a new customer's detail I click on another button (that calls ok()) and save it to a database.
What I want to do now is close the form and replace it with the detail-form.
Something like calling a protected method in the main-controller like:
protected def clearDetails(): Unit =
{
contentPane.getChildren.clear
contentPane.getChildren.add(savedOldDetails)
}
won't work of course. (Will throw a runtime-exception because there is no contentpane in the sub/form-controller (even if I make it protected)
In Qt (C++) I'd use signals/slots and connect them accordingly.
Seems like in JavaFX there is nothing the like. How am I supposed to share such information?
Do I need to create a "super-controller" for the contentPane?
(I don't know Scala, so I'll write this in Java, hope that is ok).
You can define an observable property in the Form controller, and observe it when you load the form from the main controller:
public class Form implements Initializable {
private final ObjectProperty<Person> person = new SimpleObjectProperty<>(null);
public ObjectProperty<Person> personProperty() {
return person ;
}
public final Person getPerson() {
return personProperty().get();
}
public final void setPerson(Person person) {
personProperty().set(person);
}
// ... code you had before...
#FXML
protected void ok() {
Person person = new Person(-1, foreNameTextField.getText(), lastNameTextField.getText(), ageTextField.getText());
// save to DB...
personProperty().set(person);
}
}
Now in your main controller, load the form as follows:
#FXML
protected void newButtonPressed() {
contentPane.getChildren().clear();
FXMLLoader loader = new FXMLLoader(getClass().getResource("customers/form.fxml"));
Parent form = loader.load();
Form formController = loader.getController();
formController.personProperty().addListener((obs, oldPerson, newPerson) {
if (newPerson != null) {
// clear form, etc, e.g.
clearDetails();
}
});
contentPane.getChildren().add(form);
}
I have the following Code:
public class GuiView extends Application {
private ObservableList<String> shareNames = FXCollections.observableArrayList();
public void start(Stage stage) {
...
ComboBox<String> comboBox = new ComboBox<String>();
comboBox.getItems().addAll(this.shareNames);
MenuItem open = new MenuItem("Open...");
open.setOnAction( e -> {
// FileChooser code...
if (selctedFile != null) {
this.shareNames.addAll("teststring");
}
});
}
}
When I run through the open dialog successfully the combo box doesn't update and shows the teststring. What is going wrong here?
You are updating shareNames, but that is not the list used by the combo box.
Either replace
comboBox.getItems().addAll(this.shareNames);
with
comboBox.setItems(this.shareNames);
or replace
this.shareNames.addAll("teststring");
with
comboBox.getItems().add("teststring");