无限的JavaFX坐标系面板

3
我需要编写一个自定义面板,它的行为类似于无限二维笛卡尔坐标系。首次显示时,我希望0,0位于面板中心。用户可以通过按住左键并拖动来导航该面板。它需要具有缩放功能。我还需要能够在特定坐标处放置节点。
当然,我知道这是一个非常特定的控件,我不要求任何人为我提供详细的步骤说明或编写代码。
我只是对JFX自定义控件的世界感到陌生,不知道如何解决这个问题,尤其是整个无限性的事情。
2个回答

4

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


谢谢!你让我找对了方法。最终我使用了一个 Pane 放在 ScrollPane 中。我禁用了两个 ScrollBar,这样 ScrollPane 只能通过平移来导航。 - DeLoreanDriver

3
一种方法是在Canvas中渲染任意内容,如此处所建议。相应的GraphicsContext使您能够最大程度地控制坐标。作为一个具体的例子,使用jfreechart-fx来呈现图表,其ChartViewer拥有一个扩展了CanvasChartCanvas。从这个示例开始,下面的变化将域轴设置为跨越以零为中心的区间,在添加相应点到三个系列之后。使用鼠标滚轮或上下文菜单进行缩放;有关缩放和平移的更多信息,请参见此相关答案
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);

image

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://dev59.com/hKPia4cB1Zd3GeqPuzWY#44967809
 * @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);
    }
}

我使用了你的几个想法。感谢你指出了这么多例子,并花时间写下如此详细的答案! - DeLoreanDriver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接