简体   繁体   中英

How do I replace an ImageView with a label at the click of a button and then return the ImageView back?

I have a no internet scene with an ImageView and a button, I need to replace the ImageView by a Label when the button is pressed, and after checking the internet if there is no internet, return the ImageView back.

The problem is that there is no element change in the application and the picture remains static, the Label doesn't even appear for seconds. My code:

MainApplication.java

package com.streamvoice;

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

import java.io.IOException;

import scripts.streamvoice.Scripts;

public class MainApplication extends Application {
    Scripts scripts = new Scripts();

    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader fxmlLoader;

        if (scripts.isConnection()) {
            fxmlLoader = new FXMLLoader(getClass().getResource("StartScene.fxml"));
        }
        else {
            fxmlLoader = new FXMLLoader(getClass().getResource("ConnectionErrorScene.fxml"));
        }

        Scene scene = new Scene(fxmlLoader.load(), 1000, 500);
        stage.setTitle("Stream Voice");
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }
}

ConnectionErrorScene.fxml

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

<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.VBox?>

<VBox fx:id="mVBox" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.streamvoice.ConnectionSceneController">
   <children>
      <ImageView fx:id="mErrorImage" fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true">
         <image>
            <Image url="@../../images/connectionError.png" />
         </image>
      </ImageView>
      <ProgressIndicator progress="0.0" />
      <Button fx:id="mTryConnectButton" mnemonicParsing="false" onAction="#tryConnect" text="try" />
   </children>
</VBox>

ConnectionSceneController.java

package com.streamvoice;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import scripts.streamvoice.Scripts;

public class ConnectionSceneController {
    Scripts scripts = new Scripts();
    @FXML private Button mTryConnectButton;
    @FXML private ImageView mErrorImage;
    @FXML private ProgressIndicator mConnectionProgressIndicator; //Затычка
    @FXML private VBox mVBox;
   
    private void tryConnect() {
        Label labelLoadAnimation = new Label("testText");

        mVBox.getChildren().set(0, labelLoadAnimation);

        if (scripts.isConnection())
        {
            mVBox.getChildren().set(0, mErrorImage);
        }
    }
}

Assuming scripts.isConnection() is a long-running process, executing it on the FX Application Thread will prevent the window from being redrawn until it completes.

At an intuitive level, the FX Application Thread executes a loop that does something like this:

while the application is running:
    if there are user events to handle:
        handle user events
    if there are animations active:
        update animations
    if there are pending runnables in Platform.runLater(), execute them

    if it is time to repaint the scene:
        if there are changes to the scene:
            recompute layout and repaint scene

Therefore, if you execute a long-running process on the FX Application Thread (eg in an event handler or in a Runnable passed to Platform.runLater() ), this loop will not get to repaint the scene until that process is complete.

You need to run the long running process on a background thread. You can use the Task API to do this:

private void tryConnect() {
    Label labelLoadAnimation = new Label("testText");

    mVBox.getChildren().set(0, labelLoadAnimation);

    Task<Boolean> testConnectionTask = new Task<>() {
        @Override
        public Boolean call() throws Exception {
            return scripts.isConnection();
        }
    };

    testConnectionTask.setOnSucceeded(e -> {
        if (testConnectionTask.getValue()) {
            mVBox.getChildren().set(0, mErrorImage);
        }
    }

    Thread thread = new Thread(testConnectionTask);
    thread.start();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM