Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

En mer komplett app for å lage nye Counter-objekter og telle dem opp.

I starten har en ikke noe Counter-objekt. En ny lages ved å fylle inn den øvre grensa i tekstfeltet og trykke New Counter-knappen. Tilstanden til dette Counter-objektet vises på linja under og en kan telle opp telleren ved å trykke Count-knappen.

Som over så starter vi med å redigere FXML-koden, slik at vi får en linje med et tekstfelt, av typen TextField, og en knapp til. For å få ønsket layout, med to rader, så må vi i tillegg ha en HBox rundt tekstfeltet og knappen, og en VBox (vertical box) utenpå den eksisterende HBox-en og den nye. Under til venstre vises ønsket struktur, og til høyre en kort forklaring på hvordan få det til.

Image Added

En kan pakke (eng: wrap) et VBox-panel rundt eksisterende elementer ved å velge disse, høyreklikke og velge Wrap In > VBox.

Et nytt HBox-panel legges inn ved å velge Container-seksjonen i paletten og dra og slippe et HBox-objekt inn VBox-objektet, men over det eksisterende HBox-panelet. Markøren gir tilbakemelding om hvor objektet havner når du slipper, men det er lett å bomme. Da må en i så fall dra og slippe objektet innen hierarkiet til det havner på rett plass.

TextField- og Button-objektene finner du begge i Controls-seksjonen, som generelt har interaktive elementer. (Text-objektet var i Shapes-seksjonen, siden det er passiv grafikk.)

I panelet til venstre er forøvrig visning av fx:id slått på, ved å velge Hierarchy displays > fx:id i nedtrekksmenyen markert med tannhjul. Vi ser det allerede er lagt inn en fx:id for tekstfeltet med navn endInput, som betyr at vi må ha et tilsvarende felt i CounterController-klassen. Dette trengs fordi vi må kunne lese teksten ut av feltet fra CounterController-objektet, når vi skal lage et nytt Counter-objekt med en spesifikk øvre grense.

Under er FXML- og Java-koden for den utvidete varianten vist, med forklaring til høyre.

FXML- og Java-kodeForklaring
Code Block
languagejavafx
<VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="counter.CounterController">
   <children>
      <HBox>
         <children>
            <TextField fx:id="endInput" />
            <Button mnemonicParsing="false" onAction="#handleNewCounterAction" text="New Counter" />
         </children>
      </HBox>
      <HBox>
         <children>
            <Text fx:id="counterOutput" strokeType="OUTSIDE" strokeWidth="0.0" text="Current counter value: 0" />
       	    <Button onAction="#handleCountAction" text="Count" />
         </children>
      </HBox>
   </children>
</VBox>
Code Block
languagejava
 public class CounterController {

	Counter counter = null;

	@FXML
	TextField endInput;

	@FXML
	Label counterOutput;

	@FXML
	void initialize() {
		counterOutput.setText("No counter");
	}

	void updateCounterOutput() {
		counterOutput.setText("Current counter value: " + counter.getCounter());
	}

	@FXML
	void handleNewCounterAction() {
		int end = Integer.valueOf(endInput.getText());
		counter = new Counter(end);
		updateCounterOutput();
	}

	@FXML
	void handleCountAction() {
		counter.count();
		updateCounterOutput();
	}
}

FXML-koden har blitt litt større, dels fordi vi har utvidet hierarkiet med et nivå til og lagt til ekstra elementer, og dels fordi SceneBuilder har lagt til ekstra <children>-elementer og noen attributter. <children>-elementene er egentlig implisitt inni panel-elementer og dermed overflødige her, men det er greit å la dem stå.

Det viktigste er at det nye TextField-elementet har et fx:id-attributt og det nye Button-elementet et onAction-attributt.

Java-koden har tilsvarende et nytt felt av typen TextField med navn tilsvarende fx:id-attrbibuttet og og en metode med navn tilsvarende onAction-attributtet. Og begge har med @FXML-annotasjonen, som angir at de brukes av JavaFX og FXML-mekanismen.

Java-koden har forøvrig fått følgende endringer:

  • initialize-metoden lager ikke lenger et Counter-objekt, som dermed starter som null, og setter i stedet counterOutput-teksten til "No counter".
  • Vi har en hjelpemetode for å oppdatere counterOutput-teksten med teller-verdien. Dette er praktisk fordi vi må oppdatere to steder, når vi i handleNewCounterAction lager et nytt Counter-objekt og når vi i handleCountAction teller opp.
  • handleNewCounterAction-metoden henter ut teksten fra endInput-tekstfeltet og konverterer til en int vha. Integer.valueOf-metoden, og lager et nytt Counter-objekt. Det nye Counter-objektet erstatter det gamle (uavhengig av om det er telt opp til grensen eller ikke).

 

Når du kjører FXML-koden, så kan du forresten legge merke til to bruksproblemer:

  • Det sjekkes ikke om den øvre grensa i tekstfeltet faktisk er et gyldig tall. Hvis en f.eks. skriver fem i stedet for 5 og trykker på New Counter-knappen så skjer det tilsynelatende ingenting. Det er fordi konverteringskoden i Integer.valueOf-metoden kræsjer og det derfor ikke legges inn noe nytt Counter-objekt. Det hadde vært bedre om en hele tiden sjekket om teksten var gyldig og evt. markerte det med farge. New Counter-knappen kunne dessuten blir deaktivert, hvis teksten var ugyldig.
  • En kan trykke på Count-knappen selv om det ikke er laget noe Counter-objekt ennå. counter.count()-kallet vil kræsje fordi counter-feltet er null. Også her vil det være bedre om knappen var deaktivert, inntil et Counter-objekt faktisk var laget.

Prøv gjerne å fikse disse problemene, men merk at løsningen på det første problemet er mer komplisert enn en skulle tro. Det andre problemer er enklere å løse... hint: gjør det mulig å nå knappen vha. et fx:id og et felt, og bruk Button sin setDisabled-metode.