2014-10-08 55 views
3

我有一个简单的带有Canvas和ScrollBar的JavaFX应用程序。 Canvas充当虚拟化画布,其内容可以使用ScrollBar进行滚动。JavaFX ScrollBar值混淆

画布的宽度为500像素,但画布的逻辑宽度为1000像素。 我已将ScrollBar的最大值设置为1000,并将ScrollBar的可见值设置为500. 问题是,当滚动条一直滚动到右侧时,滚动条的值为1000,而不是500. 逻辑上,当ScrollBar一直滚动到右侧,应该有一些方法来确定实际的滚动偏移量,这似乎不可能。 请建议如何获得所需的滚动量。谢谢

以下是滚动到左侧的示例。 滚动条看起来不错。它的可见宽度是窗口大小的50%。

enter image description here

这里是例子中途向右滚动。 这里的问题很明显。画布向右滚动500像素,但如果Canvas中途正确滚动,它将滚动仅250像素。

enter image description here

这里是滚动一路权的例子。 enter image description here

import javafx.application.Application; 
import javafx.beans.value.*; 
import javafx.scene.Scene; 
import javafx.scene.canvas.Canvas; 
import javafx.scene.canvas.GraphicsContext; 
import javafx.scene.control.ScrollBar; 
import javafx.scene.layout.*; 
import javafx.scene.paint.Color; 
import javafx.scene.paint.CycleMethod; 
import javafx.scene.paint.LinearGradient; 
import javafx.scene.paint.Stop; 
import javafx.stage.Stage; 

public class Sc extends Application { 

    public ScrollBar scrollBar; 
    double scrolled; 
    Canvas canvas; 

    @Override 
    public void start(Stage stage) { 
     VBox vbox = new VBox(); 
     Scene scene = new Scene(vbox); 
     stage.setScene(scene); 

     canvas = new Canvas(500, 100); 
     scrollBar = new ScrollBar(); 
     scrollBar.setMin(0); 
     scrollBar.setMax(1000); 
     scrollBar.setVisibleAmount(500); 
     vbox.getChildren().addAll(canvas, scrollBar); 
     draw(); 

     scrollBar.valueProperty().addListener(new ChangeListener<Number>() { 
      public void changed(ObservableValue<? extends Number> ov, 
       Number old_val, Number new_val) { 
       scrolled = new_val.doubleValue(); 
       draw(); 
      } 
     }); 

     stage.show(); 
    } 

    private void draw() 
    { 
     GraphicsContext graphics = canvas.getGraphicsContext2D(); 
     graphics.clearRect(0, 0, canvas.getWidth(), canvas.getHeight()); 
     Stop[] stops = new Stop[] { new Stop(0, Color.BLACK), new Stop(1, Color.RED)}; 
     LinearGradient lg = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, stops); 
     graphics.setFill(lg); 
     graphics.fillRect(0-scrolled, 30, 1000, 40); 
    } 

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

回答

3

认为它是这样的:

minmaxvalue是滚动条的逻辑值。 value的范围在minmax之间,并且等于min当且仅当滚动条一直滚动到左边(或顶部,对于垂直滚动条)。当且仅当滚动条尽可能向右(或向下)滚动时,它等于max。

visibleAmount属性实际上只是一个决定“拇指”大小的视觉属性。的关系是一样的东西

thumbSize/trackSize = visibleAmount/(max - min) 

visibleAmount会影响实际像素与“逻辑单元”之间的关系;但是它不会改变value可以在[min, max]的整个范围内变化的事实。

所以,你需要对你的代码的唯一变化是滚动条的最大值设置为可以通过,这是1000 - canvas.getWidth()(不是你正在绘制图像的大小)滚动最大:

import javafx.application.Application; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.scene.Scene; 
import javafx.scene.canvas.Canvas; 
import javafx.scene.canvas.GraphicsContext; 
import javafx.scene.control.ScrollBar; 
import javafx.scene.layout.VBox; 
import javafx.scene.paint.Color; 
import javafx.scene.paint.CycleMethod; 
import javafx.scene.paint.LinearGradient; 
import javafx.scene.paint.Stop; 
import javafx.stage.Stage; 

public class ScrollBarExample extends Application { 

    private final static double TOTAL_WIDTH = 1000 ; 


    @Override 
    public void start(Stage stage) { 
     VBox vbox = new VBox(); 

     Scene scene = new Scene(vbox, 500, 130); 
     stage.setScene(scene); 

     Canvas canvas = new Canvas(500, 100); 
     ScrollBar scrollBar = new ScrollBar(); 
     scrollBar.setMin(0); 
     scrollBar.setMax(TOTAL_WIDTH - canvas.getWidth()); 

     scrollBar.setVisibleAmount(scrollBar.getMax() * canvas.getWidth()/TOTAL_WIDTH); 

     vbox.getChildren().addAll(canvas, scrollBar); 
     draw(canvas, scrollBar.getValue()); 

     scrollBar.valueProperty().addListener(new ChangeListener<Number>() { 
      @Override 
      public void changed(ObservableValue<? extends Number> ov, 
       Number old_val, Number new_val) { 
       draw(canvas, scrollBar.getValue()); 
      } 
     }); 


     stage.show(); 
    } 

    private void draw(Canvas canvas, double scrollAmount) 
    { 
     GraphicsContext graphics = canvas.getGraphicsContext2D(); 
     graphics.clearRect(0, 0, canvas.getWidth(), canvas.getHeight()); 
     Stop[] stops = new Stop[] { new Stop(0, Color.BLACK), new Stop(1, Color.RED)}; 
     LinearGradient lg = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, stops); 
     graphics.setFill(lg); 
     graphics.fillRect(0-scrollAmount, 30, TOTAL_WIDTH, 40); 
    } 

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

谢谢!这实际上是我在等待你的建议时开始做的。我只是觉得这个解决方案太hacky了,一定有更好的方法哈哈哈! – 2014-10-09 05:21:02