Allora, devo specificare che non ho studiato JavaFX, in passato ho giusto seguito un paio di tutorial di un’insegnante di una qualche università (adesso non ricordo) che ha pubblicato delle video lezioni su YouTube (Tecniche di Programmazione), quindi vado a memoria.
Detto questo, ho creato giusto una stupidata per capire (possibilmente) questa cosa.
Chiaramente tu hai scritto tutto a mano, io sono pigro e ho preferito utilizzare SceneBuilder che fa risparmiare un sacco di tempo.
Dicevo ieri, che di default vengono create 2 classi la main:
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("Sample.fxml"));
Scene scene = new Scene(root,300,150);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
… e la SampleController, non ho modificato nulla, ne ho impostato il progetto in maniera seria, perché non mi interessa, ho solo dato un nome poi ?avanti ?avanti ? modificato giusto 2 impostazioni ? fine.
La classe SampleController si presenta vuota, poi si apre SceneBuilder, si crea quello che serve ? salva ? si copia tutto il contenuto presente nello skeleton (così si chiama), e si incolla nell’apposita classe controller.
Quindi mi ritrovo con questi dati:
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
public class SampleController {
@FXML // ResourceBundle that was given to the FXMLLoader
private ResourceBundle resources;
@FXML // URL location of the FXML file that was given to the FXMLLoader
private URL location;
@FXML // fx:id="combo"
private ComboBox<?> combo; // Value injected by FXMLLoader
@FXML // fx:id="btClean"
private Button btClean; // Value injected by FXMLLoader
@FXML // fx:id="btClose"
private Button btClose; // Value injected by FXMLLoader
@FXML
void gestioneCombo(ActionEvent event) {
}
@FXML
void resetta(ActionEvent event) {
}
@FXML
void uscita(ActionEvent event) {
}
@FXML // This method is called by the FXMLLoader when initialization is complete
void initialize() {
assert combo != null : "fx:id=\"combo\" was not injected: check your FXML file 'Sample.fxml'.";
assert btClean != null : "fx:id=\"btClean\" was not injected: check your FXML file 'Sample.fxml'.";
assert btClose != null : "fx:id=\"btClose\" was not injected: check your FXML file 'Sample.fxml'.";
}
}
Apporto giusto un paio di modifiche:
@FXML // fx:id="combo"
private ComboBox<String> combo; // Value injected by FXMLLoader
@FXML
void resetta(ActionEvent event) {
// QUESTO È IL BOTTONE
combo.setValue(null);
if(combo.getValue() == null)
//combo.setValue("Nome");
combo.getSelectionModel().select(combo.getPromptText());
}
@FXML
void uscita(ActionEvent event) {
System.exit(0);
}
@FXML // This method is called by the FXMLLoader when initialization is complete
void initialize() {
...
combo.getItems().addAll("Pippo", "Paperino", "Pluto", "Topolino");
}
...e questa robetta è già bella che pronta.
Il file fxml si riempe quasi in automatico, basta aprirlo una volta per far rilevare le modifiche a Eclipse. Una volta fatto ciò, si può tranquillamente provare l’applicazione.
File fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.171" fx:controller="application.SampleController">
<top>
<Label text="PROVA COMBOBOX" BorderPane.alignment="CENTER">
<font>
<Font name="Abyssinica SIL" size="18.0" />
</font>
<BorderPane.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</BorderPane.margin>
</Label>
</top>
<center>
<VBox alignment="TOP_CENTER" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</BorderPane.margin>
<children>
<ComboBox fx:id="combo" minWidth="210.0" onAction="#gestioneCombo" opacity="0.98" promptText="Nome">
<VBox.margin>
<Insets />
</VBox.margin>
<padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</padding>
<cursor>
<Cursor fx:constant="DEFAULT" />
</cursor>
</ComboBox>
</children>
</VBox>
</center>
<bottom>
<HBox alignment="BOTTOM_CENTER" BorderPane.alignment="CENTER">
<children>
<Button fx:id="btClean" alignment="CENTER" minWidth="100.0" mnemonicParsing="false" onAction="#resetta" text="Cancella">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<font>
<Font name="Abyssinica SIL" size="18.0" />
</font>
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</Button>
<Button fx:id="btClose" alignment="CENTER" minWidth="100.0" mnemonicParsing="false" onAction="#uscita" text="Chiudi">
<font>
<Font name="Abyssinica SIL" size="18.0" />
</font>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</Button>
</children>
<BorderPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</BorderPane.margin>
</HBox>
</bottom>
</BorderPane>
Come vedi non ho fatto chissà cosa, e con queste 2 righe di codice succede questo...
Ieri forse non mi sono spiegato bene, cliccando sul bottone cancella non deve selezionare una stringa già presente nella lista, a me interessa mostrare il TextPrompt, quello base che ho inserito con SceneBuilder, questo perché non voglio che la stringa “Nome” (per questo esempio), si veda cliccando la comboBox.
Perché se inserisco “Nome” come primo elemento della lista, risolverei il problema, ma non è una cosa pulita, non riesco neanche eventualmente a nasconderla.
Ad esempio potrei aggiungere
combo.getItems().addAll(?"Nome"?,"Pippo", "Paperino", "Pluto", "Topolino");
poi nel metodo apposito scrivo:
@FXML
void resetta(ActionEvent event) {
combo.getSelectionModel().selectFirst();
}
E a questo punto mi ritrovo Nome senza dover cliccare 2 volte, ma come dicevo, in questo modo cliccando la comboBox si vede in lista, e io non voglio.
E questo è quanto...
Se hai tempo, tu o qualcun'altro...