【问题标题】:Infinite JavaFX coordinate system pane无限 JavaFX 坐标系窗格
【发布时间】:2018-05-09 03:03:26
【问题描述】:

我需要编写一个行为类似于无限二维笛卡尔坐标系的自定义窗格。首次显示时,我希望 0,0 位于窗格的中心。用户应该能够通过按住鼠标左键并拖动来导航窗格。它需要具有放大和缩小的能力。我还必须能够将节点放置在特定坐标处。

当然我知道这是一个非常具体的控件,我并没有要求任何人给我分步说明或为我编写。

我是 JFX 自定义控件领域的新手,不知道如何解决这个问题,尤其是整个无穷大问题。

【问题讨论】:

    标签: java javafx custom-controls coordinate-systems


    【解决方案1】:

    一种方法是按照here 的建议在Canvas 中呈现任意内容。对应的GraphicsContext 使您可以最大程度地控制坐标。作为一个具体的例子, 使用jfreechart-fx 渲染图表,其ChartViewer 包含一个扩展CanvasChartCanvas。从这个example 开始,下面的变体将域轴设置为在将对应点添加到三个系列后跨越以零为中心的区间。使用鼠标滚轮或上下文菜单进行缩放;有关缩放和平移的更多信息,请参阅此相关 answer

    for (double t = -3; t <= 3; t += 0.5) {
        series.add(t, Math.sin(t) + i);
    }
    …
    xAxis.setRange(-Math.PI, Math.PI);
    …
    plot.setDomainPannable(true);
    

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.axis.NumberAxis;
    import org.jfree.chart.entity.ChartEntity;
    import org.jfree.chart.entity.LegendItemEntity;
    import org.jfree.chart.entity.XYItemEntity;
    import org.jfree.chart.fx.ChartViewer;
    import org.jfree.chart.fx.interaction.ChartMouseEventFX;
    import org.jfree.chart.fx.interaction.ChartMouseListenerFX;
    import org.jfree.chart.labels.StandardXYToolTipGenerator;
    import org.jfree.chart.plot.XYPlot;
    import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
    import org.jfree.data.xy.XYSeries;
    import org.jfree.data.xy.XYSeriesCollection;
    
    /**
     * @see https://stackoverflow.com/a/44967809/230513
     * @see https://stackoverflow.com/a/43286042/230513
     */
    public class VisibleTest extends Application {
    
        @Override
        public void start(Stage stage) {
            XYSeriesCollection dataset = new XYSeriesCollection();
            for (int i = 0; i < 3; i++) {
                XYSeries series = new XYSeries("value" + i);
                for (double t = -3; t <= 3; t += 0.5) {
                    series.add(t, Math.sin(t) + i);
                }
                dataset.addSeries(series);
            }
            NumberAxis xAxis = new NumberAxis("domain");
            xAxis.setRange(-Math.PI, Math.PI);
            NumberAxis yAxis = new NumberAxis("range");
            XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, true);
            renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
            XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
            JFreeChart chart = new JFreeChart("Test", plot);
            ChartViewer viewer = new ChartViewer(chart);
            viewer.addChartMouseListener(new ChartMouseListenerFX() {
                @Override
                public void chartMouseClicked(ChartMouseEventFX e) {
                    ChartEntity ce = e.getEntity();
                    if (ce instanceof XYItemEntity) {
                        XYItemEntity item = (XYItemEntity) ce;
                        renderer.setSeriesVisible(item.getSeriesIndex(), false);
                    } else if (ce instanceof LegendItemEntity) {
                        LegendItemEntity item = (LegendItemEntity) ce;
                        Comparable key = item.getSeriesKey();
                        renderer.setSeriesVisible(dataset.getSeriesIndex(key), false);
                    } else {
                        for (int i = 0; i < dataset.getSeriesCount(); i++) {
                            renderer.setSeriesVisible(i, true);
                        }
                    }
                }
    
                @Override
                public void chartMouseMoved(ChartMouseEventFX e) {}
            });
            stage.setScene(new Scene(viewer));
            stage.setTitle("JFreeChartFX");
            stage.setWidth(640);
            stage.setHeight(480);
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    【讨论】:

    • 我利用了你的几个想法。感谢您指出这么多例子,并花时间写出如此详细的答案!
    【解决方案2】:

    这并不像您想象的那么难实现。只需从一个简单的窗格开始。这已经为您提供了无限坐标系。与您的要求的唯一区别是点 0/0 在左上角而不是在中间。这可以通过对窗格应用转换转换来解决。然后可以通过将相应的鼠标侦听器添加到窗格中以类似的方式实现缩放和平移。

    【讨论】:

    • 谢谢!你带领我走上了正确的道路。我最终在 ScrollPane 中使用了一个窗格。我禁用了两个 ScrollBar,所以 ScrollPane 只能通过平移来导航。
    猜你喜欢
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 2014-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多