Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Kotlin: JavaFX -käyttöliittymän alustus

Sivun loppuun

Matti Holopainen [26.08.2021 20:05:25]

#

Minulla on IntelliJ / Kotlin -sovellus, johon olen tehnyt käyttöliittymän siten, että piirrän kaikki buttonit, labelit, kuvat ja vastaavat itse formin canvakselle.

Tämä toimii oikein hyvin, mutta nyt haluaisin tehdä saman sovelluksen oikeilla käyttöliittymäkomponenteilla JavaFX:ää ja Scene Builderiä käyttäen. Osa käyttöliittymän komponenteista pitäisi alustaa koodissa käynnistyksen yhteydessä, mutta en löydä paikkaa, mihin alustuksen voisi kirjoittaa.

Laitan tähän näkyviin IntelliJ:n JavaFX HelloApplication-projektin koodin.

Kuinka tähän lisätään heti sovelluksen käynnityksessä kutsuttava funktio, joka asettaa welcomeText-labeliin vaikkapa "Ohjelmointiputka". Mihin tämä funktio kirjoitetaan ja mistä sitä kutsutaan?

HelloApplication.kt:

package com.example.demo

import javafx.application.Application
import javafx.fxml.FXMLLoader
import javafx.scene.Scene
import javafx.stage.Stage

class HelloApplication : Application() {
    override fun start(stage: Stage) {
        val fxmlLoader = FXMLLoader(HelloApplication::class.java.getResource("hello-view.fxml"))
        val scene = Scene(fxmlLoader.load(), 320.0, 240.0)
        stage.title = "Hello!"
        stage.scene = scene
        stage.show()
    }
}

fun main() {
    Application.launch(HelloApplication::class.java)
}

HelloController.kt:

package com.example.demo

import javafx.fxml.FXML
import javafx.scene.control.Label

class HelloController {
    @FXML
    private lateinit var welcomeText: Label

    @FXML
    private fun onHelloButtonClick() {
        welcomeText.text = "Welcome to JavaFX Application!"
    }
}

hello-view.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>

<?import javafx.scene.control.Button?>
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml"
      fx:controller="com.example.demo.HelloController">
    <padding>
        <Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
    </padding>

    <Label fx:id="welcomeText"/>
    <Button text="Hello!" onAction="#onHelloButtonClick"/>
</VBox>

Jere Sumell [27.08.2021 09:00:54]

#

Mikset luo initComponents() -metodia, ja kutsu sitä konstruktorissa ennen ohjelman muuta toimintaa.

Mitä olen Swing-komponenttien kanssa ohjelmoinut, niin AMK:n Ohjelmoinnin jatkokurssilla, kun niitä käsiteltiin, niin sielläkin pistettiin alustukset tuon GUI-komponentin esittelyn yhteyteen, jonka näkyvyysalueeksi määriteltiin private, mahdollisteti myos muuttuja oli staattinen static avainsanalla.

Mulla kävi yksi aika ennen kesää 2021 mielessä noihin Swing-komponentteihin liittyvän Boilerplaten, en tiedä tarkkaa suomennosta, ohjelmointia, niin siinä ideoin tuota, että pitäisi olla jokin alustusmetodi, jota sitten konstruktori kutsuu,että ei tarvitsisi GUI-komponentin esittelyn yhteydessä luoda sitä olio-ilmentymää. Koodista tulee järkyttävän näkoista nimittäin, jos noita graafisen käyttoliittymän komponentteja on useampia.

Jere Sumell [27.08.2021 09:32:20]

#

Kävi mielessä tuossa sen jälkeen, kun olin vastaillut ja luin muita säikeitä täällä Ohjelmointiputkassa, ja sitten kävin tupakalla, niin tuli mieleen vielä parempi ratkaisu, miten varmaan itse toteuttaisin tuo, eli

1. Luo rajapinta, jossa on pelkät GUI-komponenttien esittelyt
2. Luo uusi tietotyyppi Esim. CompInit, jossa on toteutettuna tuo aiemmin luotu rajapinta, ja setterit ja getterit niiden komponenttioliomuuttujien luonnin lisäksi.
3. Sittenhän selviät vain yhden muuttujan käytollä pääohjelmassasi, kun esittelet ja luot tuosta kakkoskohdassa luodusta tietotyypistä oliomuuttujan, josta sitten pistenotaatiolla, kun viittaat jonkin komponentin get-metodiin, niin sittenhän pääset käsiksi niiden komponenttien alkuperäisiin valmiiksi määriteltyihin metodeihin.

Tuo taitaa olla järkevä ratkaisu.

Matti Holopainen [27.08.2021 09:55:27]

#

Jere Sumell kirjoitti:

Mikset luo initComponents() -metodia, ja kutsu sitä konstruktorissa ennen ohjelman muuta toimintaa.

Juuri näin olen yrittänyt tehdä, mutta en ole löytänyt konstruktoria, se taitaa olla jossain Scene Builderin sisuksissa.

Kysymykseni oli siis, mihin tuo initComponents() -metodi lisätään ja mihin sen kutsu tulee? Vastauksen haluaisin ylläolevaan koodiin päivitettynä!

Jere Sumell [27.08.2021 09:57:47]

#

Tässä koodia Swing-komponetein tuo edellinen rajapinta/tietyyppi-luonti ohjeistus

Rajapinta

import javax.swing.*;

public interface MyComps {

	//Attribuutit
	static JButton myButton=null;

	//Metodit
	public void setMyButton();

	public JButton getMyButton();


}

tietotyyppi, jossa toteutetaan edellinen rajapinta

import javax.swing.JButton;

public class CompInit implements MyComps {

	private JButton myButton;

	@Override
	public void setMyButton() {
		this.myButton = new JButton("My Button");

	}

	@Override
	public JButton getMyButton() {
		return this.myButton;
	}

}

Sitten pääohjelma

import javax.swing.*;
import java.awt.*;

public class ButtonDemo extends JFrame {

	private CompInit init;

	public ButtonDemo() {
		setSize(352,288);
		setTitle("GUI-demo");
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		init = new CompInit();
		init.setMyButton();
		startti();

	}

	public void startti() {
		Container con = getContentPane();
		init.getMyButton().setText("My Button text modified");
		con.add(init.getMyButton());
	}

	public static void main(String[] args) {
		ButtonDemo demo = new ButtonDemo();
		demo.setVisible(true);
	}




}

Matti Holopainen [27.08.2021 11:03:52]

#

Kiitos vain, mutta kysymykseni koskee JavaFX:ää ja sen Scene Builderia.

Metabolix [27.08.2021 13:38:21]

#

En ole käyttänyt JavaFX:ää enkä tietysti testannut näitä ratkaisuja, mutta googletuksen perusteella ehdottaisin:

Kun kontrolleri on luotu, kutsutaan sen initialize-metodia. Eli jos teet sinne kyseisen metodin, voit siinä muuttaa tekstiä.

@FXML
public fun initialize() {
    welcomeText.text = "Ohjelmointiputka"
}

Toinen (varmasti huonompi) vaihtoehto olisi säätää jo tuolla start-metodissa:

val root = fxmlLoader.load()
val scene = Scene(root, 320.0, 240.0)
val hc = root.getController()
if (hc is HelloController) {
    hc.kutsutaanPublicFun()
}

Matti Holopainen [27.08.2021 13:52:57]

#

Kiitos!
Toimii.
Nyt kun tiesin, mitä funktiota etsiä, niin löysin sen sitten googlesta itsekin.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta