当前位置: 首页 > 知识库问答 >
问题:

关于如何显示JavaFX ListView单元格的从属视图的建议

白通
2023-03-14

我们希望将ListView填充为单个JavaFX视图的实例列表。这是我们试图更早地工作,但时间用完了。当时的后退解决方案是有一个四行的静态面板(即不使用ListView)。在静态版本中,每一行都是同一个JavaFX(FXML)视图的一个实例。

每一行都是与一个小型FXML文件匹配的控制器的一个单独(实例)。其工作方式是,当调用initialize()方法时,视图获得一个id,该id映射到模型数据,然后controller/'view'管理它自己的数据行。在静态情况下,我们可以使用FXML include-directive,这使事情变得非常简单。我将单独的行称为行视图。

要以这种方式使用ListView,我们需要执行以下操作:

  • 列表视图控制器必须调用“列表加载程序”来加载/初始化列表
  • 我们希望行视图显示为ListView中的单个行
    • 如果ListView可以获取(子)视图/(子)组件,则可以执行此操作
    • 行视图是预打包的子视图;
    • 是否有方法“克隆”现有视图以生成副本?
      null

    我取得了一些进展。我可以用一个名为“ViewLoader”的类加载一个FXML文件,它使用loadView(urlStr)方法。(放入,只写入日志或sysout)。

        public  AnchorPane   loadView( final String urlStr ){
    
        AnchorPane  fxmlView    = null;
        Parent      root        = null;
        URL         fxmlResource;
    
        try
        {
            fxmlResource = getClass().getResource( urlStr );
            root = FXMLLoader.load( fxmlResource, Resources.getResourceBundle() );
    
            this.fxmlStr  = urlStr;
            this.rootNode = root;
            fxmlView = (AnchorPane) this.rootNode;
        }
        catch (Exception ex)
        {
            Util.puts( "  * Exception on FXMLLoader.load()");
            Util.puts( "  * "+ex.getMessage());
            Util.puts( "    ----------------------------------------\n");
        }
    
        return  fxmlView;
    }
    

    我从一个know布局开始,因此loadView()加载并返回一个AnchorPane(在名为“urlstr”的文件中定义)。到目前为止还不错。在调试器中,我可以观察一个加载的视图,它加载了它的控制器。每个细胞都有自己的控制器,以这种方式独立工作。

    在第一步中,简单的方法是尝试通过CellFactory设置视图。Bzzt!这会使视图无效,所以不能那样做。

    public class CustomListView
    {
        :
    
        public class  CustomCellFactory implements  Callback<ListView<MyObject>, ListCell<MyObject>> 
        {
    
            @Override
            public ListCell<MyObject> call( ListView<MyObject> listView ) {
    
                ListCell<MyObject> cell = new ListCellType();
    
                return cell;
            }
    
        }//CustomCellCallback class
    
    }//CustomListView
    

    在我看来,工厂模式的逻辑,那么新的ListCellType()应该返回加载的AnchorPane作为视图。其中ListCellType定义为ListCell<>的子类...

    public class ListCellType extends ListCell<MyObject>
    {
        :
    
    }//ListCellType
    

    然而,在我看来,我们似乎需要工厂返回加载的视图,因此

      ListCell<MyObject> cell = new ListCellType();
    

    这个应用程序需要返回一个JavaFX节点,或者在这个特定的情况下返回一个AnchorPane(稍后我们可以使其更加通用)。好像:

      ListCell<AnchorPane> cell = new ListCellType();
    

    如何使这个工作,也许与一个不同的工厂/更新方案?

共有1个答案

吉凯捷
2023-03-14

我相信我们已经找到了一个原始的答案,它足够适合于概念的证明,并且可以作为一个“通用”模式的起点。内核来自这个定制的ListView示例的两个扩展:

  • 使用FXML在JavaFX中自定义ListView,以及
  • 自定义列表视图(JavaBuddy)

如前所述。这些示例使用简单对象作为列表内容。第一个要求是拥有子视图的ListView,其中子视图是另一个FXML文件。从概念上讲,这类似于使用fxml- 运算符的ListVeiw。

public class ListCellView   extends CellView
{
    @FXML private Label             label1;
    @FXML private Label             label2;


    @Override
    public void setInfo( MyObject myObject ){

       label1.setText( myObject.getDay() );
       label2.setText( Integer.toString( myObject.getNumber() ) );

       label1.setTextFill( myObject.getColor() );
    }


        /**
         *  Initialize
         *    -- must use java -ea <program>, to check asserts
         **/
    @FXML
    @Override
    protected void initialize() {

        super.initialize();

        assert label1       != null : "fx:id=\"label1\" was not injected: check your FXML file 'CustomCell.fxml'.";
        assert label2       != null : "fx:id=\"label2\" was not injected: check your FXML file 'CustomCell.fxml'.";
    }

}//ListCellView

其中我们使用CellView作为子显示的抽象类,这样子视图可以在保留相似结构的同时进行更改:

public abstract class CellView
{
    @FXML private ResourceBundle    resources;
    @FXML private URL               location;
    @FXML private AnchorPane        customCell;
    @FXML private HBox              hBox;

    public abstract void setInfo( MyObject myObject );

    public HBox getBox() {

        return hBox;
    }

    protected void initialize() {

        assert customCell   != null : "fx:id=\"customCell\" was not injected: check your FXML file 'CustomCell.fxml'.";
        assert hBox         != null : "fx:id=\"hBox\" was not injected: check your FXML file 'CustomCell.fxml'.";
    }

    public  CellView(){
    }

}//CellView

在运行时代码中,ListView类:CustomListView由JavaFX应用程序平台加载。为了测试这个过程,我们用静态数据初始化了显示,所有这些数据都使用了相同的FXML视图,如下所示:“MyObject”对象列表。

public class CustomListView
{
    @FXML private ResourceBundle        resources;
    @FXML private URL                   location;
    @FXML private ListView<MyObject>    listView;

    List<MyObject>                      myList              = prepareMyList();
    ObservableList<MyObject>            myObservableList    = FXCollections.observableList( this.myList );


    private void setListView(){

        this.listView.setItems( this.myObservableList );

        listView.setCellFactory(
            new Callback<ListView<MyObject>, javafx.scene.control.ListCell<MyObject>>() {
                @Override
                public ListCell<MyObject> call(ListView<MyObject> listView) {
                    return new CustomListCell();
                }
            }//callback
        );//setCellFactory

    }//setListView

        /**
         * Initializes the controller class.
         */
    @FXML
    void initialize() {

        assert listView != null : "fx:id=\"listView\" was not injected: check your FXML file 'CustomList.fxml'.";

        this.setListView();
    }

        /**
         *  Prepare My List
         *    - Create dummy list of Views and data = MyObject-s
         **/
    private List<MyObject> prepareMyList() {

        final String    FXML_VIEW = "/fxml/ListCell.fxml";
        List<MyObject>  newList   = new ArrayList<>();

        newList.add(new MyObject( FXML_VIEW, "Sunday",    50, Color.RED        ));
        newList.add(new MyObject( FXML_VIEW, "Monday",    60, Color.GREEN      ));
        newList.add(new MyObject( FXML_VIEW, "Tuesday",   20, Color.BLUE       ));
        newList.add(new MyObject( FXML_VIEW, "Wednesday", 90, Color.VIOLET     ));
        newList.add(new MyObject( FXML_VIEW, "Thursday",  30, Color.BLUEVIOLET ));
        newList.add(new MyObject( FXML_VIEW, "Friday",    62, Color.BROWN      ));
        newList.add(new MyObject( FXML_VIEW, "Saturday",  65, Color.GOLD       ));

        return newList;
    }

}//CustomListView

通过这个框架,MyObject构造函数完成将FXML视图作为CellView对象加载的“工作”。视图和控制器只需要加载一次。每个setInfo()调用只需要更新视图的数据/内容。

public class MyObject
{
    private     ViewLoader      view    = null;
    private     String          day;
    private     int             number;
    private     Color           colour;

    public  String getDay() {

        return day;
    }

    public  int getNumber() {

        return number;
    }

    public  Color getColor(){

        return colour;
    }


    public  CellView    getView(){

        return this.view.getView();
    }


    public  MyObject( final String fxmlView, final String d, final int n, final Color c) {

        view    = new ViewLoader( fxmlView );

        day     = d;
        number  = n;
        colour  = c;
    }

}//MyObject class
public class ViewLoader
{
    private    String      fxmlStr         = "(none)";
    private    Parent      rootNode        = null;
    private    CellView    viewController  = null;


    public  void loadView( final String urlStr ){

        Parent      root        = null;
        URL         fxmlResource;
        FXMLLoader  fxmlLoader  = null;
        try
        {
            fxmlResource = getClass().getResource( urlStr );
            fxmlLoader = new FXMLLoader( fxmlResource, Resources.getResourceBundle() );

            root = fxmlLoader.load( );

            this.viewController = fxmlLoader.getController();
            this.fxmlStr        = urlStr;
            this.rootNode       = root;
        }
        catch (Exception ex)
        {
            puts( "  * Exception on FXMLLoader.load()");
            puts( "  * "+ex.getMessage());
            puts( "    ----------------------------------------\n");
        }
    }


    public  CellView    getView(){

        return this.viewController;
    }

    public  ViewLoader( final String urlStr ){

        loadView( urlStr );
    }

}//ViewLoader class
 类似资料:
  • 我希望我的swift代码在每次按下按钮时都添加一个新的tableview单元格。你可以在下面的gif中看到我想要的东西。这段代码应该在func-tableView(_tableView:UITableView,cellForRowAt-indexPath:indexPath)中添加按钮- 在此输入图像描述

  • 编写Web应用可能是单调的,因为你需要不断的重复某一种模式。 Django尝试从model和 template层移除一些单调的情况,但是Web开发者依然会在view(视图)层经历这种厌烦。 Django的通用视图被开发用来消除这一痛苦。它们采用某些常见的习语和在开发过 程中发现的模式然后把它们抽象出来,以便你能够写更少的代码快速的实现基础的视图。 我们能够识别一些基础的任务,比如展示对象的列表,以

  • 我正在使用这种数据帧: 如果用户输入,,我需要显示和或\n 如果用户输入,,我需要显示和

  • 问题内容: 我有以下代码: 非常简单。如何为带有的元素添加colspan(或等价的colspan)? 问题答案: 据我所知,缺少colspan / rowspan只是的限制之一。

  • 问题内容: 我有以下内容: 我想使整个超链接。我希望不使用JavaScript。这可能吗? 问题答案: 是的,这是可能的,尽管不是字面上的,而是其中的内容。一个简单的技巧是,确保内容扩展到单元格的边界(尽管它本身不包括边界)。 如前所述,这在语义上是不正确的。一个元素是内嵌元件,并且不应该被用作块级元素。但是,这是一个适用于大多数浏览器的示例(但JavaScript加td:hoverCSS样式会更

  • 问题内容: 我有此代码从如何突出显示jtable中的多个单元格: 但是,当我用它突出显示一个单元格时,它会执行错误的操作,就像丢失整个数据一样。Iam是Java Swing的新手。请帮助使单元格在按钮按下动作事件中突出显示。 更新:添加我的示例代码: 我想要的是单击按钮,我只想突出显示单元格编号1(Row1-Column1)。 问题答案: 我使用此类来设置JTables的样式 创建此类的实例,并将