2014-12-12 2 views
-1

단일 JavaFX보기의 인스턴스 목록으로 ListView를 채우려합니다. 이것은 우리가 일찍 일하려고 시도한 것이고 시간이 없어진 것입니다. 당시 폴백 솔루션은 네 개의 행이있는 정적 패널 (ListView를 사용하지 않음)을 사용하는 것이 었습니다. 정적 버전에서 각 행은 동일한 JavaFX (FXML)보기의 인스턴스입니다.JavaFX ListView 셀의 하위보기를 표시하는 방법에 대한 조언

각 행은 작은 FXML 파일과 일치하는 컨트롤러의 개별 (인스턴스)입니다. 이것이 작동하는 방식은 initialize() 메서드가 호출 될 때 뷰가 id를 얻고 이것이 모델 데이터에 매핑 된 다음 컨트롤러/뷰에서 자체 데이터 행을 관리한다는 것입니다. 정적 인 경우에는 FXML include-directive를 사용할 수 있습니다. 이는 매우 간단합니다. 개별 행, 즉 행 뷰를 호출합니다.

  1. 목록보기 컨트롤러는 "목록 로더"
  2. 우리는 행보기를 원하는 목록을 초기화 /로드를 호출해야합니다 :

    우리가 다음을 수행하기 위해 필요한이 방법으로 목록보기를 사용하려면 ListView에은 (서브)보기/(서브) 성분
  3. 행 시청을 할 경우 수행 OK 보인다 ListView에
    • 개별 행으로 표시되는 것은 사전 패키지 인 서브 전망;
  4. 행 변경에 필요한 새 행 뷰 FXML 정의를 '로드'할 수 있어야합니다.
    • 기존보기를 "복제하여 복사본을 만들 수있는 방법이 있습니까?

이 질문은 POJO 질문 유사하지만는 :

주요 차이점은 우리의 행이 임의 FXML 될 수 있다는 것이다. 이 기계 부품은 기존의 고정 크기 패널을 적용하여 작동한다고 생각합니다. 주요 개념은 디자인/요구 사항이 변경 될 때마다 목록 상자를 다시 코딩 할 필요없이 디스플레이 "스캐 폴드"를 설정하고보기를 스왑 아웃 할 수있게하는 것입니다.

업데이트하려면 ...

나는 약간의 진전을했습니다. "ViewLoader"라는 클래스로 FXML 파일을로드 할 수 있습니다. loadView (urlStr) 메소드가 있습니다. (puts, 그냥 로그 또는 sysout에 기록). 나는에는 loadView 그래서 알고 레이아웃으로 시작() 부하와 "urlStr"에 의해 명명 된 파일에 정의 된 AnchorPane를 반환하고있어

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; 
} 

. 여태까지는 그런대로 잘됐다. 디버거에서로드 된 뷰를 관찰 할 수 있으며 컨트롤러를로드합니다. 각 셀에는 자체 컨트롤러가있어이 방식으로 독립적으로 작동합니다.

첫 번째 단계에서 순진한 접근 방식은 CellFactory를 통해 뷰를 설정하려고 시도하는 것이 었습니다. Bzzt! 이렇게하면보기가 무효화되므로 그렇게 할 수 없습니다.

분명히 사용자 정의 셀보기로 ListView를로드하는 방법이 필요합니다. 나는 그것이 어떻게 일어나게하는지에 관해서 난처하게 돈다. 현재 우리라는 지역 클래스를 사용하는 것이 :

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는 그러나

public class ListCellType extends ListCell<MyObject> 
{ 
    : 

}//ListCellType 

... ListCell<>의 서브 클래스로 정의된다, 그렇게하는 대신

ListCell<MyObject> cell = new ListCellType(); 

이 응용 프로그램의 요구 나에게 보인다 JavaFX Node을 반환하거나이 특정 경우에 AnchorPane을 반환합니다 (나중에 더 일반적으로 만들 수 있습니다). 뭔가 는 다음과 같이-경우 : 이론 확인을 보인다

ListCell<AnchorPane> cell = new ListCellType(); 

있지만, 사실은 ListView.setCellFactory(...)가, ListView가 아닌 ​​노드를 필요로 남아있다.

다른 공장/업데이트 구성표로이 작업을 수행하는 방법은 무엇입니까?

+0

흠 ... 기술적으로 fxml을 알아낼 데이터 요소 목록과 해당 fxml에서 뷰를로드하는 cellFactory가 필요합니다. 결코 시도하지 않았다. – kleopatra

+0

각 행에 대해 동일한 FXML을 재사용하고 싶습니다. 그렇다면 사용자 정의 cellFactory가 있습니다. 고마워, 고마워. – will

+0

이 질문은 적합하다고 보입니다. http://stackoverflow.com/questions/19588029/customize-listview-in-javafx-with-fxml – will

답변

0

우리는 원시 응답을 이라고 생각하고 개념 증명을 위해에 적합하고 '범용'패턴의 출발점으로 사용할 수 있다고 생각합니다. 커널이 사용자 정의의 ListView 예에 대한 확장의 몇에서 온다 :

을 앞서 언급 한 바와 같이. 이 예제에서는 간단한 개체를 목록 내용으로 사용합니다. 첫 번째 요구 사항은 하위 뷰의 ListView를 갖는 것이 었습니다. 하위 뷰는 다른 FXML 파일입니다. 개념적으로 이것은 FXML-< 을 포함하는 ListVeiw와 비슷할 것이며, 연산자는입니다.

원시 솔루션의 기초는 셀 데이터를 셀보기와 연결하는 것입니다. 따라서 사용자 정의 셀 뷰 목록의 경우 ListView에 ObservableList (view, data) 튜플이 필요합니다. 또는 하위보기의 컨트롤러가 모델의 데이터를 찾기에 충분히 똑똑 할 때 "하위보기 목록"일 수 있습니다. 지금까지 원시 예제는 데이터와 뷰의 인스턴스를 함께 유지합니다.

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 

필수 요소는 서브 - 뷰 내에서 디스플레이를 위해 데이터를 갱신 setInfo() 호출 공용 방법이다. 다른 배열이 가능합니다. 하위보기 목록은 목록 위치에 적합한 모델 데이터를 조회하는 데 사용할 수있는 ID로 설정됩니다.런타임 코드에서

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 

의 : 유사한 구조를 유지하면서 우리가 서브 디스플레이를위한 추상 클래스로 CellView을 사용했습니다

는 이러한는 하위 뷰는 주변에 변경 될 수 있음 ListView 클래스 : CustomListView는 JavaFX 응용 프로그램 플랫폼에 의해로드됩니다. 프로세스를 테스트하기 위해 우리는 'MyObject'객체 목록에서 다음과 같이 동일한 FXML 뷰를 사용하여 정적 데이터로 디스플레이를 초기화했습니다. 이 프레임 워크와

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를 생성자는 CellView 개체로 FXML보기를로드하는 '작업'을한다. 뷰와 컨트롤러는 한 번만로드하면됩니다. 각 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 

MyObject를 로딩 후 FXML보기 및 제어기를 유지하기 위해 "ViewLoader"유형을 유지 :

MyObject를 예로 들어 데이터 또는 일부 도면이다.

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 

이 예제는 JavaFX ListView의 하위보기 셀 목록을 행복하게 표시합니다. 하위 뷰는 "MyObject"데이터를 이해해야합니다. 최종 버전에서는 데이터가 하위 뷰에서 분리되어 일부 모델 객체에서 검색됩니다.

각 ListView 셀은 사용중인 특정 'ListCellView'컨트롤러의 고유 한 인스턴스입니다. 이 패턴을 세부 조정하면 데이터 소스로 하위 뷰를 초기화하고 뷰에서 데이터를 완전히 분리 할 수 ​​있습니다. 달리 하위 뷰는 수동으로로드해야합니다. 이 기능을 원하면 기본 CustomListView.fxml에서 보이지 않는 레이블로 FXML 파일 이름을 지정할 수 있습니다.

다른 사람들이 유용하다고 생각하거나 적어도 ListView를 관리하는 데 필요한 작업을 더 많이 볼 수 있으면 좋겠다.

관련 문제