JavaFX:一次有2个独立的窗口

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaFX:一次有2个独立的窗口相关的知识,希望对你有一定的参考价值。

我想一次创建2个独立的窗口。一个窗口可以容纳一个可观察的列表,另一个窗口将显示所选的列表对象的属性。我正在尝试将listview创建为通用列表,并将其与特定于对象的窗口(例如,客户属性,啤酒属性,商店属性)相结合。

简而言之:如果用户单击“客户”,它将显示包含所有客户的列表视图,并且第一个客户的属性将显示在单独的客户特定窗口中。

如果用户点击“商店”,它会显示相同的列表视图,但会填充商店。特定于商店的窗口也会打开并包含第一个商店的属性。

我尝试使用2个FXMLLoader,但出于某种原因我无法弄清楚如何使用它们。我在JavaFX上相当平庸,所以我甚至无法弄清楚从哪里开始。这就是我所拥有的,但它似乎错了。

 FXMLLoader loader = new FXMLLoader(getClass().getResource("List.fxml"));
 loader.setRoot(this);
 loader.setController(this);
 FXMLLoader loader2 = new FXMLLoader(getClass().getResource("StoreWindow.fxml"));
 loader2.setRoot(this);
 loader2.setController(this);
 try {
        loader.load();
        loader2.load(); 
     } catch (IOException ex) {
        throw new RuntimeException(ex);
     }
答案

以下是共享相同模型的两个窗口(阶段)的演示。 演示尽可能简单:一个窗口显示一个列表。第二个窗口动态显示第一个选中的项目:

enter image description here

共享模型包含两个窗口所需的信息。基本上是项目列表和所选项目列表:

package two_windows;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class Model {

    private final ObservableList<String> list;
    private ObservableList<String> selected;

    Model(){
        list = FXCollections.observableArrayList();
    }

    void addMessage(String msg){
        list.add(msg);
    }

    ObservableList<String> getMessages(){
        return list;
    }

    ObservableList<String> getSelectedMessages(){
        return selected;
    }

    void setSelected(ObservableList<String> selected) {
        this.selected = selected;
    }
}

第一个窗口的内容由List.fxml及其控制器定义:

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

<?import javafx.scene.layout.Pane?>
<?import javafx.scene.control.ListView?>

<Pane xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1"
 fx:controller="two_windows.ListController">
   <children>
        <ListView fx:id="list" prefHeight="300.0" prefWidth="150.0" />
    </children>
</Pane>

控制器接受Model,在模型中设置选定的项目列表,监听并响应模型更改:

package two_windows;

import java.util.List;
import javafx.collections.ListChangeListener;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;

public class ListController {

    @FXML ListView<String> list;

    void setModel(Model model) {

        list.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);//allow multiple selection

        //sets the selected items of the list to the model 
        model.setSelected(list.getSelectionModel().getSelectedItems());

        //listen to changes in model, and respond
        model.getMessages().addListener(
                                        (ListChangeListener<String>) c -> {
                                            c.next();
                                            addElements(c.getAddedSubList());
                                        }
                                    );
    }

    private void addElements(List<? extends String> msgList){

        for(String msg : msgList){
            list.getItems().add(msg);
        }
    }
}

第二个窗口的内容与第一个窗口的内容非常相似,由Selected.fxml定义:

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

<?import javafx.scene.layout.Pane?>
<?import javafx.scene.control.ListView?>  

<Pane xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1"
 fx:controller="two_windows.SelectedController">
   <children>
        <ListView fx:id="selected" prefHeight="300.0" prefWidth="150.0" />
    </children>
</Pane>

它的控制器,像其他控制器一样接受Model并响应其中的变化:

package two_windows;

import java.util.List;
import javafx.collections.ListChangeListener;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;

public class SelectedController {

    @FXML ListView<String> selected;

    void setModel(Model model) {

        //listen to changes in model, and respond
        model.getSelectedMessages().addListener(
                    (ListChangeListener<String>) c -> {
                        c.next();
                        removeElements(c.getRemoved());
                        addElements(c.getAddedSubList());
                    }
                );
    }

    private void removeElements(List<? extends String> msgList){

        for(String msg : msgList){
            selected.getItems().remove(msg);
        }
    }

    private void addElements(List<? extends String> msgList){

        for(String msg : msgList){
            selected.getItems().add(msg);
        }
    }
}

把它们放在一起并测试:

package two_windows;

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

public class TwoWindows extends Application {

    private Model model;

    @Override
    public void start(Stage primaryStage) throws Exception{

        model = new Model();

        FXMLLoader listLoader = new FXMLLoader(getClass().getResource("List.fxml"));
        Parent list = listLoader.load();
        ListController listController = listLoader.getController();
        listController.setModel(model);

        FXMLLoader selectedLoader = new FXMLLoader(getClass().getResource("Selected.fxml"));
        Parent selected = selectedLoader.load();
        SelectedController selectedController = selectedLoader.getController();
        selectedController.setModel(model);

        primaryStage.setScene(new Scene(list));
        primaryStage.setX(350); primaryStage.setY(300);

        Stage secondaryStage = new Stage();
        secondaryStage.setScene(new Scene(selected));
        secondaryStage.setX(550); secondaryStage.setY(300);

        addMessages();
        primaryStage.show();
        secondaryStage.show();
    }

    private void addMessages() {

        int counter = 0;
        while(counter < 15) {
            model.addMessage("message number "+ counter++);
        }
    }

    public static void main(final String[] args) {
        launch(args);
    }
}
另一答案

你基本上必须遵循@Slaw指令。创建一个Model。在两个Model之间分享Controllers。观察模型的当前Customer并做出相应的反应。 MCVE下面:

主类:(使用正确的场景加载两个阶段。创建模型并将其传递给两个控制器):

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

/**
 *
 * @author sedri
 */
public class JavaFXApplication36 extends Application {

    @Override
    public void start(Stage stage) {
        try {
            FXMLLoader listViewFXMLLoader = new FXMLLoader(getClass().getResource("ListViewFXML.fxml"));
            Parent listViewRoot = listViewFXMLLoader.load();
            ListViewController listViewController = listViewFXMLLoader.getController();
            Scene scene1 = new Scene(listViewRoot);
            stage.setScene(scene1);           

            FXMLLoader detailsFXMLLoader = new FXMLLoader(getClass().getResource("DetailsFXML.fxml"));
            Parent detailsRoot = detailsFXMLLoader.load();
            DetailsController detailsController = detailsFXMLLoader.getController();
            Scene scene2 = new Scene(detailsRoot);
            Stage stage2 = new Stage();
            stage2.setScene(scene2);

            DataModel model = new DataModel();
            listViewController.initModel(model);
            detailsController.initModel(model);

            stage.show();
            stage2.show(); 
        } catch (IOException ex) {
            Logger.getLogger(JavaFXApplication36.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

模型类:(跟上客户的当前客户和ObservableList)

import javafx.beans.Observable;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

/**
 *
 * @author sedrick
 */
public class DataModel {
    private final ObservableList<Customer> customerList = FXCollections.obser

以上是关于JavaFX:一次有2个独立的窗口的主要内容,如果未能解决你的问题,请参考以下文章

JavaFX窗口拖动

PostgreSQL,一次有两个窗口函数

JavaFX自定义窗口标题栏

使用#pragma一次有什么危险? [重复]

记一次有手就行的getshell

记一次有手就行的getshell