JavaFX 之 Canvas

技术概述

javaFX Canvas API提供了一个灵活的画笔。它可以通过创建canvas对象,获取其GraphicsContext以及调用绘图操作以在屏幕上呈现自定义形状,它可以在JavaFX场景图中使用。本次项目你画我猜要求呈现出一个画板并且能够绘制自定义图形,因此学习此组件来应用于项目中。

技术详述

定义GraphicsContext对象g,之后使用GraphicsContext提供的一组图形命令来实现绘制图像。

GraphicsContext g = getGraphicsContext2D();

设置监听器来获取画笔的大小和颜色

nowSize.addListener(evt -> {
        g.setLineWidth(nowSize.get() * Math.min(getWidth(), getHeight()));
    });
nowColor.addListener(evt -> g.setStroke(nowColor.get()));

实现画笔绘制操作事件,包括按下鼠标,拖动鼠标,释放鼠标三个响应事件

//鼠标按下事件
setOnMousePressed(evt -> {
        if (!myTurn || !evt.isPrimaryButtonDown())
            return;
        nowPi = new PainInfo();
        pis.add(nowPi);

        g.beginPath();
        double x = evt.getX() / getWidth();
        double y = evt.getY() / getHeight();

        nowPi.xys.add(new BinaryDoubleTuple(x, y));

        g.moveTo(x * getWidth(), y * getHeight());
        g.lineTo(x * getWidth(), y * getHeight());
        g.stroke();
        
        count = 0;
    });
 //鼠标拖动事件   
setOnMouseDragged(evt -> {
        if (!myTurn || !evt.isPrimaryButtonDown())
            return;
        count++;
        if (count % 20 == 0) {
            double x = evt.getX() / getWidth();
            double y = evt.getY() / getHeight();
            nowPi.xys.add(new BinaryDoubleTuple(x, y));

            g.lineTo(x * getWidth(), y * getHeight());
            g.stroke();
        }
        
    });
//鼠标释放事件
setOnMouseReleased(evt -> {
        g.closePath();
        refresh();

        PainInfo painInfoLast=null;
        if(pis!=null) {
        	painInfoLast= pis.get(pis.size()-1);
        }
        
        HashMap <String,Object> hm = new HashMap<>();
        
        Color color1;
        double size1;
        color1 = nowColor.get();
        size1 = nowSize.get();
        hm.put("drawed", new TernaryTuple<>(color1,size1,painInfoLast.xys));
        System.out.println("i do it");
        NewIo.send(ClientPost.Type.DRAW, hm);
        System.out.println("i do it end");
    });

技术使用中遇到的问题和解决过程

问题:画布的大小无法随着窗口自适应,用户在放大或缩小窗口后画布仍保持原大小。
解决方法:在javaFX中没有方法可以调整画布自适应,唯一的解决方案是从Canvas扩展。

重写isResizable()方法并返回true

@Override
public boolean isResizable() {
    return true;
}

重写prefWidth()和prefHeight()方法,返回getWidth()和getHeight()的值

@Override
public double prefWidth(double var1) {
    return getWidth();
}

@Override
public double prefHeight(double var1) {
    return getHeight();
}

将侦听器添加到画布的width和height属性中,以便在画布大小更改时触发重绘。

//添加窗口大小监听器
widthProperty().addListener(evt -> refresh());
heightProperty().addListener(evt -> refresh());

//设计重绘方法
private void refresh() {
    Color color = nowColor.get();
    double size = nowSize.get();
    clear();
    for (PainInfo pi : pis) {
        nowColor.set(pi.color);
        nowSize.set(size);
        g.beginPath();
        BinaryDoubleTuple first = pi.xys.getFirst();
        g.moveTo(first.first * getWidth(), first.second * getHeight());
        for (BinaryDoubleTuple xy : pi.xys) {
            g.lineTo(xy.first * getWidth(), xy.second * getHeight());
            g.stroke();
        }
        g.closePath();
    }
    nowColor.set(color);
    nowSize.set(size);
}

将画布的width和height属性绑定到父窗格StackPane的width和height属性。

DngCanvas dc = new DngCanvas();
StackPane ret = new StackPane(dc);
dc.widthProperty().bind(ret.widthProperty());
dc.heightProperty().bind(ret.heightProperty());

总结

javafx中的Canvas能很好的帮助我们实现画板绘制功能,必要时也需创建子类对其进行功能拓展和完善,以满足项目产品的需求。

参考文献

Canvas JavaFX8

JavaFX - Resize Canvas when screen is resized

posted @ 2021-06-28 14:51  我的叶绿体  阅读(1645)  评论(1编辑  收藏  举报