程序目的
经过将processing封装成数组排序算法可视化工具(详见:文章传送门)后,我发现其实如果是为了在一般的python程序中使用processing做可视化的话,更好的交互命令不应该是将python程序发送给processing命令(通过本地网络通讯)的格式设置成这种:“将数组元素a和b交换位置”
“将数组元素c通过编程红色一段时间强调一下”
更好的方式应该是:画出一个坐标x,大小x的圆
画出一个坐标x到坐标x的直线
也就是说,我觉得更好的方式应该是将命令设计的更底层一些,就好像是在python解释器中写processing程序一样。这样是更有扩展性的,能够使开发者完全在自己的python程序中实现可视化功能,而不再更改processing功能。
另外,我还学习了python中更先进的实现远程调用的方法,我学习的时候主要参考了这里。
下面先看一下调用画图功能的程序写法
python程序:画图程序客户端(调用方)。
程序包括了:连接到画图服务器
定义画图器类
实例化一个画图器
给画图器发出指令
在使用画图程序时,前两部分时候直接复制,如果只想学其使用方法而不想理解其内部功能的话可以只看后两部分。
import socket, json
# 连接到画图服务器
address = ('127.0.0.1', 12345)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(address)
# 这个类封装了画图命令,使用时候可以直接复制,可以把它理解成一个画图器
class RPCProxy:
def __init__(self, connection):
self._connection = connection
def __getattr__(self, name):
def do_rpc(*args, **kwargs):
self._connection.send(json.dumps((name, args, kwargs)).encode())
self._connection.send("@".encode())
return do_rpc
# 实例化画图器
rpc = RPCProxy(s)
# 给画图器发出命令
rpc.rect(100,100,20,100)
rpc.ellipse(100,70,60,60)
rpc.ellipse(81,70,16,32)
rpc.ellipse(119,70,16,32)
rpc.line(90,150,80,160)
rpc.line(110,150,120,160)
可以看出,在我们的画图端程序的发命令部分,和processing中的编程命令是非常类似的,只是在每个函数的前面加了一个 “rpc.” 。比如说上面的画图程序就来自processing官网的一个入门教程。对应的在processing中的画图命令是这样的:
# 对应的processing程序代码
size(200,200);
rectMode(CENTER);
rect(100,100,20,100);
ellipse(100,70,60,60);
ellipse(81,70,16,32);
ellipse(119,70,16,32);
line(90,150,80,160);
line(110,150,120,160);
可以看出,我们的客户端对于使用过processing的同学也非常友好。
而如果你深入看画图器类的源码,你会发现我们的程序主要使用了以下的技巧:python高级面向对象知识
本地网络连接
json编码与解码
将字符串通过encode() 方法转换成二进制形式
理解了画图器的用法后,我们看一下效果视频:画图器效果https://www.zhihu.com/video/1166116193302941696
可以看出我们的程序实现了预料的功能。
processing端源码放送以及使用注意事项
add_library('net')
import json
class RPCHandler:
def __init__(self):
self._functions = { }
def register_function(self, func):
self._functions[func.__name__] = func
def handle_mesg(self, mesg):
mg = mesg.split("@")
for m in mg:
if len(m) == 0: continue
m = json.loads(m)
func_name, args, kwargs = m
try:
r = self._functions[func_name](*args,**kwargs)
except Exception as e:
pass
handler = RPCHandler()
fs = [arc, circle, ellipse, line, point, quad, rect, square, triangle, \
fill, stroke, background]
for f in fs:
handler.register_function(f)
s = Server(this, 12345) # 这里的12345是端口号
def setup():
size(200,200)
rectMode(CENTER)
def draw():
c = s.available()
if c != None:
mesg = c.readString()
print(mesg)
handler.handle_mesg(mesg)
print(frameCount)
在使用processing的客户端程序是还有一些需要注意的,首先是安装processing软件以及python模式。
另外就是在setup()函数中需要指定 画图串口的尺寸,以及 rectMode(),该函数控制了画长方形时候的坐标参数代表中心坐标还是一个角的坐标。
还有最后一点,在我们的画图器中,可用的画图命令包括:arc, circle, ellipse, line, point, quad, rect, square, triangle, fill, stroke, background, 这些命令的详细用法和在processing中是一致的,可以参考:processing reference。
后续文章计划
可能会做一些使用这个新的画图器,进行算法可视化或者别的好玩事情的工程。