2017-11-13 9 views
1

여기에서 목표는 ScrollPane에 대해 사용자 정의 ScrollBar을 사용하여 창을 최대화/최소화 할 때 레이아웃에 문제가없는 것입니다.창과 레이아웃 패스 최대화

import javafx.application.Application; 
import javafx.geometry.Insets; 
import javafx.geometry.Orientation; 
import javafx.scene.Scene; 
import javafx.scene.control.ScrollBar; 
import javafx.scene.control.ScrollPane; 
import javafx.scene.control.ScrollPane.ScrollBarPolicy; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.layout.Background; 
import javafx.scene.layout.BackgroundFill; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.CornerRadii; 
import javafx.scene.layout.Pane; 
import javafx.scene.layout.Region; 
import javafx.scene.layout.VBox; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 

public class Layout extends Application 
{ 
    @Override 
    public void start(Stage stage) 
    { 
     BorderPane main = new BorderPane(); 
     main.setPrefSize(800, 600); 

     BorderPane center = new BorderPane(); // begin center 
     center.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY))); 
     main.setCenter(center); // end center 

     BorderPane left = new BorderPane(); // begin left 

     ScrollPane pane = new ScrollPane(); 
     pane.setFitToWidth(true); 

     Pane p1 = new Pane(); // child 1 
     p1.setPrefSize(200, 100); 
     p1.setBackground(new Background(new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, Insets.EMPTY))); 
     this.makeResizable(p1); 
     Pane p2 = new Pane(); // child 2 
     p2.setPrefSize(200, 100); 
     p2.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY))); 
     this.makeResizable(p2); 
     VBox content = new VBox(10, p1, p2); // content in scroll pane 
     pane.setContent(content); 

     // replace normal bars 
     pane.setHbarPolicy(ScrollBarPolicy.NEVER); 
     pane.setVbarPolicy(ScrollBarPolicy.NEVER); 

     // with custom 
     ScrollBar sb = new ScrollBar(); 
     sb.setOrientation(Orientation.VERTICAL); 
     sb.minProperty().bind(pane.vminProperty()); 
     sb.maxProperty().bind(pane.vmaxProperty()); 
     sb.visibleAmountProperty().bind(pane.heightProperty().divide(content.heightProperty())); 
     sb.managedProperty().bind(sb.visibleAmountProperty().lessThan(1.0)); // bar should be managed when it is needed (content too long) 
     sb.visibleProperty().bind(sb.managedProperty()); // and also visible only when managed 
     sb.valueProperty().bindBidirectional(pane.vvalueProperty()); 

     left.setCenter(pane); // content 
     left.setRight(sb); // scroll bar 
     main.setLeft(left); //end left 

     Scene scene = new Scene(main); 
     stage.setScene(scene); 
     stage.show(); 
    } 

    // Simple for testing 
    double prevY; 
    boolean dragging; 

    // Makes node resizable on drag. 
    private void makeResizable(Region region) 
    { 
     region.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> 
     { 
      this.dragging = true; 
      region.setPrefHeight(region.getHeight()); 
      this.prevY = e.getSceneY(); 
     }); 
     region.addEventFilter(MouseEvent.MOUSE_DRAGGED, e -> 
     { 
      if (!this.dragging) return; 
      region.setPrefHeight(region.getPrefHeight() + (e.getSceneY() - this.prevY)); 
      this.prevY = e.getSceneY(); 
     }); 
     region.addEventFilter(MouseEvent.MOUSE_RELEASED, e -> this.dragging = false); 
    } 

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

그것은 내용 (2 개 노드 p1p2가) 범위를 초과 할 때 나타나는 사용자 정의 ScrollBar 왼쪽에 ScrollPane와 GUI를 생성합니다 :

은 예제 프로그램을 생각해 보자. 쉽게 테스트 할 수 있도록 p1p2은 마우스로 드래그 할 때 크기를 조정할 수 있습니다 (시도해보십시오). ScrollBar이 예상대로 작동하고 작동하는 동안 창을 최대화하고 최소화하기 시작하면 레이아웃에 결함이 있습니다.

예를 들어

:

  1. 시작 프로그램
  2. 크기 조정 내용이 너무 ScrollBar가 나타납니다,하지만 너무 훨씬
  3. 최대화 창을 (당신이 그것을 극대화 할 때, 그것은 경계에있을 수 있도록 그것을 확인) - 막대가 사라질 수도 있지만 "빈 공간"이 표시됩니다.
  4. 이제 어떻게하면 새로 고침 (예 : 콘텐츠의 크기를 다시 조정)하면 레이아웃 통과 업데이트로 인해 막대가 사라집니다.

기타 버그 :

  1. 시작 프로그램과 극대화 할 수 있습니다.
  2. 크기가 최대화 된 창에 계속 포함되도록 크기를 조정하지만 최소화 할 때 제한을 초과 할 정도로 충분히 커야합니다.
  3. 어떻게 ScrollBar이 잘못 배치되었는지주의하십시오.

당신이 (1 예제를 사용하여) 다른 물건을하려고 노력하지만, 모든 당신이 극대화 때/이런 일이 발생 최소화한다는 사실에서 발생한다면 다른 몇 가지 버그가 있습니다

  1. ScrollBar 관리하고 볼 수는 (콘텐츠가 초과한다고 생각할 때).
  2. 극대화가
  3. 창 크기를 조정할 레이아웃이 계산된다 (이전 값을 사용하여 - = 실제 관리 & & = 눈에 보이는 사실)
  4. 레이아웃이 발생, 모든, 모든 속성은 sb.visibleAmountProperty()ScrollBar 세트를 관리하기 등 업데이트를받을 장소에 false로 표시됩니다 (바운드되어 있으므로 코드 참조).
  5. ScrollBar은 보이지 않고 관리되지 않지만 레이아웃은 이미 발생했으며 다시 실행되지 않습니다.

어떻게하면 창을 최대화 할 수 있습니까? 어떻게 내가 최대화 할 때 깨지지 않는 ScrollBar을 바인딩 할 수 있습니까? 크기를 조정하지 않고 최대화에 대해 이야기하고 있습니다 (어떤 방식으로 작동하는지).

답변

0

나는 하나의 해결책을 찾았지만 더 좋은 것이 있다면 절대적으로 최선의 방법으로 보이지는 않습니다. 공유하십시오. 이 이후

sb.managedProperty().addListener(e -> Platform.runLater(() -> content.requestLayout())); 

는 "나중에"실행됩니다 (또한 이전의 레이아웃을 완료해야 1 주 스레드에 있기 때문에),이 일이 레이아웃 작업의 원인이됩니다.

왜 좋지 않습니까? 하나의 경우에는 실제로 필요하지 않을 때 (최대화하지 않음) 이중 레이아웃을 유발할 때도 호출됩니다. (그리고 우리는 몇몇 if 문으로 이것을 더 이상 무시할 수 없습니다).