Есть ли способ реорганизовать все мои повторяющиеся VBox в пользовательский тег JavaFX? - PullRequest
0 голосов
/ 06 февраля 2020

TL; DR находится внизу.

Я создаю приложение погоды в JavaFX, и я использую настройку для отображения 5 VBoxes по горизонтали в виде HBox, который представляет 5-дневные данные прогноза погоды. Проблема в том, что все эти VBoxes практически идентичны, за исключением фактических данных, отображаемых внутри них.

Например, у всех есть Label для даты, ImageView для значка погоды (облачно, солнечно, дождливо и т. Д.), Label для температуры и т. Д. Это делает мой Controller класс ОЧЕНЬ МНОГО @FXML аннотированных надписей и кнопок, ImageVeiws, все кратно 5.

Есть ли способ организовать все мои элементы в пользовательском теге под названием WeatherBox что в значительной степени будет VBox, в котором будут размещены все компоненты для меня? Вместо того, чтобы все повторяться 5 раз в моем Controller классе, у меня было бы просто 5 WeatherBoxes. Я посмотрел на некоторые другие вопросы, касающиеся Vboxes и HBoxes, и я не чувствую, что понял идею (или проблема, к которой они обращаются, принципиально иная). Все они предлагают сделать класс WeatherBox классом Controller с его собственным файлом FXML, и я не уверен, как бы я поместил ie все в мой основной файл fxml, в котором будут размещаться теги WeatherBox

Расширение VBox похоже на путь к go, но я не понимаю, как это сделать правильно и как использовать его для решения моей проблемы. У кого-нибудь есть какие-нибудь предложения?

TL; DR Я создаю приложение погоды, и у меня есть 5 VBoxes, которые все в значительной степени идентичны. Все они имеют дочерние метки и изображения, а что нет. Это заставляет мой Controller class выглядеть нелепо, потому что всего 5 (не DRY). Могу ли я / как мне реорганизовать все в пользовательский тег с расширением VBox, чтобы я мог вставить его в FXML, в который будут встроены все Labels, Buttons и ImageViews?

package sample;

import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import sample.datamodel.DataUtils;
import sample.datamodel.Location;

import java.io.IOException; 
import java.util.Optional;

public class Controller {

@FXML
private BorderPane borderPane;
@FXML
private VBox forecast1;
@FXML
private VBox forecast2;
@FXML
private VBox forecast3;
@FXML
private VBox forecast4;
@FXML
private VBox forecast5;
@FXML
private Label date1;
@FXML
private Label date2;
@FXML
private Label date3;
@FXML
private Label date4;
@FXML
private Label date5;
@FXML
private Label description1;
@FXML
private Label description2;
@FXML
private Label description3;
@FXML
private Label description4;
@FXML
private Label description5;
@FXML
private Label percipitation1;
@FXML
private Label percipitation2;
@FXML
private Label percipitation3;
@FXML
private Label percipitation4;
@FXML
private Label percipitation5;
@FXML
private Label temperature1;
@FXML
private Label temperature2;
@FXML
private Label temperature3;
@FXML
private Label temperature4;
@FXML
private Label temperature5;
@FXML
private ImageView img1;
@FXML
private ImageView img2;
@FXML
private ImageView img3;
@FXML
private ImageView img4;
@FXML
private ImageView img5;
@FXML
private Button details1;
@FXML
private Button details2;
@FXML
private Button details3;
@FXML
private Button details4;
@FXML
private Button details5;
@FXML
private Button otherLocsButton;
@FXML
private Button todaysWeatherButton;
@FXML
private Button fiveDayButton;
@FXML
private Button refreshButton;
@FXML
private ListView<Location> locListView;

public void initialize() {
    locListView.setItems(DataUtils.getInstance().getLocations());
    locListView.getSelectionModel().selectFirst();
    fiveDayButton.fire();
}

@FXML
public void refresh() {
    Location location = locListView.getSelectionModel().getSelectedItem();
    location.updateWeather();
    fiveDayForecast();

}

@FXML
public void fiveDayForecast() {
    Location location = locListView.getSelectionModel().getSelectedItem();
    location.updateWeather();
    Location.Day[] days = location.getDays();
    Location.Weather weather;
    VBox[] wthrPanes = {forecast1, forecast2, forecast3, forecast4, forecast5};
    Label[] dates = {date1, date2, date3, date4, date5};
    Label[] description = {description1, description2, description3, description4, description5};
    Label[] percipitation = {percipitation1, percipitation2, percipitation3, percipitation4, percipitation5};
    Label[] temp = {temperature1, temperature2, temperature3, temperature4, temperature5};
    ImageView[] images = {img1, img2, img3, img4, img5};

    for (int i = 0; i < days.length; i++) {
        weather = days[i].getWeather()[0];
        String date = days[i].getDate();
        String dateFormat = date.substring(5, 7) + "." + date.substring(8, 10);
        dates[i].setText(dateFormat);
        Image image = new Image("WeatherIcons/png/001-windy-2.png");
        images[i].setImage(image);
        images[i].setFitHeight(50);
        images[i].setPreserveRatio(true);
        String des = weather.getDescription();
        double tempMax = weather.getMaxTemp();
        double tempMin = weather.getMinTemp();
        double percip = weather.getPrecipitation();
        temp[i].setText(tempMax + "\\" + tempMin);
        percipitation[i].setText(Double.toString(percip));
    }
}



@FXML
public void addLocationDialog() {
    Dialog<ButtonType> dialog = new Dialog<>();
    dialog.initOwner(borderPane.getScene().getWindow());
    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(getClass().getResource("newLocationDialog.fxml"));
    try {
        dialog.getDialogPane().setContent(loader.load());

    } catch (IOException e) {
        System.out.printf("New Item Dialog didn't load.");
        e.printStackTrace();
        return;
    }
    dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
    dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);

    Optional<ButtonType> result = dialog.showAndWait();
    if (result.isPresent() && result.get() == ButtonType.OK) {
        NewLocationController controller = loader.getController();
        Location location = controller.newLocation();
        location.updateWeather();
    }
}

@FXML
public void forecastDetails(Event event) {
    System.out.println(event.getEventType().getName());
    Button button = (Button) event.getSource();
    button.getId();
}

}

И вот этот файл F XML, связанный с Controller. Обратите внимание, что все VBox в основном одинаковы и не следуют принципу DRY.

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

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.image.ImageView?>
<BorderPane fx:id="borderPane" xmlns="http://javafx.com/javafx/10.0.2-internal"
            xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
    <center>
        <GridPane fx:id="gridPane" alignment="TOP_CENTER" hgap="50" prefHeight="400.0" vgap="30" gridLinesVisible="true">
            <columnConstraints>
                <ColumnConstraints percentWidth="15"/>
                <ColumnConstraints percentWidth="15"/>
                <ColumnConstraints percentWidth="15"/>
                <ColumnConstraints percentWidth="15"/>
                <ColumnConstraints percentWidth="15"/>
            </columnConstraints>

            <VBox fx:id="forecast1" GridPane.columnIndex="0" GridPane.rowIndex="0" alignment="TOP_CENTER">
                <Label fx:id="date1">
               <font>
                  <Font size="18.0" />
               </font></Label>
                <ImageView fx:id="img1"/>
                <Label fx:id="description1"/>
                <Label fx:id="temperature1"/>
                <Label fx:id="percipitation1"/>
                <Button fx:id="details1" text="Details" onAction="#forecastDetails"/>
            </VBox>

            <VBox fx:id="forecast2" GridPane.columnIndex="1" GridPane.rowIndex="0" alignment="TOP_CENTER">
                <Label fx:id="date2">
               <font>
                  <Font size="18.0" />
               </font></Label>
                <ImageView fx:id="img2"/>
                <Label fx:id="description2"/>
                <Label fx:id="temperature2"/>
                <Label fx:id="percipitation2"/>
                <Button fx:id="details2" text="Details" onAction="#forecastDetails"/>
            </VBox>

            <VBox fx:id="forecast3" GridPane.columnIndex="2" GridPane.rowIndex="0" alignment="TOP_CENTER">
                <Label fx:id="date3">
               <font>
                  <Font size="18.0" />
               </font></Label>
                <ImageView fx:id="img3"/>
                <Label fx:id="description3"/>
                <Label fx:id="temperature3"/>
                <Label fx:id="percipitation3"/>
                <Button fx:id="details3" text="Details" onAction="#forecastDetails"/>
            </VBox>

            <VBox fx:id="forecast4" GridPane.columnIndex="3" GridPane.rowIndex="0" alignment="TOP_CENTER">
                <Label fx:id="date4">
               <font>
                  <Font size="18.0" />
               </font></Label>
                <ImageView fx:id="img4"/>
                <Label fx:id="description4"/>
                <Label fx:id="temperature4"/>
                <Label fx:id="percipitation4"/>
                <Button fx:id="details4" text="Details" onAction="#forecastDetails"/>
            </VBox>

            <VBox fx:id="forecast5" GridPane.columnIndex="4" GridPane.rowIndex="0" alignment="TOP_CENTER">
                <Label fx:id="date5">
               <font>
                  <Font size="18.0" />
               </font></Label>
                <ImageView fx:id="img5"/>
                <Label fx:id="description5"/>
                <Label fx:id="temperature5"/>
                <Label fx:id="percipitation5"/>
                <Button fx:id="details5" text="Details" onAction="#forecastDetails"/>
            </VBox>
        </GridPane>
    </center>

    <top>
        <VBox>
            <MenuBar>
                <Menu text="Location">
                    <MenuItem text="Change Location" />
                    <MenuItem onAction="#addLocationDialog" text="Add New Location" />
                </Menu>
            </MenuBar>
            <ToolBar>
                <Button fx:id="otherLocsButton" text="Other Locations" />
                <Button fx:id="todaysWeatherButton" text="Today" />
                <Button fx:id="fiveDayButton" onAction="#fiveDayForecast" text="5 day" />
                <Button fx:id="refreshButton" onAction="#refresh" text="Refresh" />
            </ToolBar>
        </VBox>
    </top>
    <left>
        <VBox>
            <ListView fx:id="locListView" />
        </VBox>
    </left>
</BorderPane>

1 Ответ

3 голосов
/ 07 февраля 2020

Вот пример:

main F XML:

<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>

<?import sample.WeatherBox?>

<GridPane alignment="center" hgap="10" vgap="10" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
   <children>
      <VBox prefHeight="200.0" prefWidth="294.0">
         <children>
            <Button mnemonicParsing="false" text="Button" />
               <WeatherBox dateText="example1" descriptionText="description1"/>
               <WeatherBox dateText="example2" descriptionText="description2"/>
         </children></VBox>
   </children>
   <columnConstraints>
      <ColumnConstraints />
   </columnConstraints>
   <rowConstraints>
      <RowConstraints />
   </rowConstraints>
</GridPane>

WeatherBox.f xml:

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


<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<?import javafx.scene.image.ImageView?>
<?import javafx.scene.text.Font?>
<fx:root type="VBox" xmlns:fx="http://javafx.com/fxml">
    <Label fx:id="date">
        <font>
            <Font size="18.0" />
        </font></Label>
    <ImageView fx:id="img"/>
    <Label fx:id="description"/>
    <Label fx:id="temperature"/>
    <Label fx:id="percipitation"/>
    <Button fx:id="details" text="Details" onAction="#forecastDetails"/>
</fx:root>

WeatherBox. java

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;

import java.io.IOException;


public class WeatherBox extends VBox {

    @FXML
    private Label date;
    @FXML
    private Label description;
    @FXML
    private Label temperature;
    @FXML
    private Label percipitation;
    @FXML
    private Button details;
    @FXML
    private ImageView img;

    public WeatherBox() {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("WeatherBox.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }


    @FXML
    protected void forecastDetails() {
        System.out.println("The button was clicked!");
    }


    public String getDateText() {
        return date.getText();
    }

    public void setDateText(String dateText) {
        this.date.setText(dateText);
    }

    public String getDescriptionText() {
        return description.getText();
    }

    public void setDescriptionText(String dateText) {
        this.description.setText(dateText);
    }
}

Вы должны использовать класс контроллера, чтобы определить, как будет работать logi c.

...