与wxPython集成

场景类wxgl.wxscene.WxScene是wx.glcanvas.GLCanvas的派生类,因此可以无缝地在wxPython中使用该类。三维绘图功能封装在wxgl.Scheme中,只需要将一个Scheme类实例传到场景类中即可显示三维绘图结果。

import os
import wx
import numpy as np
import wxgl

class MainFrame(wx.Frame):
    """桌面程序主窗口类"""
 
    def __init__(self):
        """构造函数"""
 
        wx.Frame.__init__(self, None, -1, '在WxPython中使用WxGL', size=(640,480), style=wx.DEFAULT_FRAME_STYLE)
        self.Center()
        self.SetBackgroundColour((224, 224, 224))

        self.scene = wxgl.wxscene.WxScene(self, self.draw(), fovy=40)
        self.visible = True

        btn_home = wx.Button(self, -1, '复位', size=(100, -1))
        btn_animate = wx.Button(self, -1, '启动/停止', size=(100, -1))
        btn_visible = wx.Button(self, -1, '隐藏/显示', size=(100, -1))
        btn_save = wx.Button(self, -1, '保存', size=(100, -1))

        sizer_btn = wx.BoxSizer(wx.VERTICAL)
        sizer_btn.Add(btn_home, 0, wx.TOP|wx.BOTTOM, 20)
        sizer_btn.Add(btn_animate, 0, wx.TOP|wx.BOTTOM, 20)
        sizer_btn.Add(btn_visible, 0, wx.TOP|wx.BOTTOM, 20)
        sizer_btn.Add(btn_save, 0, wx.TOP|wx.BOTTOM, 20)

        sizer_max = wx.BoxSizer()
        sizer_max.Add(self.scene, 1, wx.EXPAND|wx.LEFT|wx.TOP|wx.BOTTOM, 5)
        sizer_max.Add(sizer_btn, 0, wx.ALL, 20)
        
        self.SetAutoLayout(True)
        self.SetSizer(sizer_max)
        self.Layout()

        self.Bind(wx.EVT_BUTTON, self.on_home, btn_home)
        self.Bind(wx.EVT_BUTTON, self.on_animate, btn_animate)
        self.Bind(wx.EVT_BUTTON, self.on_visible, btn_visible)
        self.Bind(wx.EVT_BUTTON, self.on_save, btn_save)

    def draw(self):
        """绘制网格球和圆柱的组合体"""

        tf = lambda t : ((0, 1, 0, (0.03*t)%360), )
        sch = wxgl.Scheme()
        sch.sphere((0,0,0), 1, fill=False)
        sch.cylinder((-1.2,0,0), (1.2,0,0), 0.3, color='cyan', transform=tf, name='cudgel')
        sch.circle((-1.2,0,0), 0.3, vec=(-1,0,0), color='cyan', transform=tf, name='cudgel')
        sch.circle((1.2,0,0), 0.3, vec=(1,0,0), color='cyan', transform=tf, name='cudgel')
        sch.axes()
        
        return sch

    def on_home(self, evt):
        """点击复位按钮"""

        self.scene.home()

    def on_animate(self, evt):
        """点击启动/停止按钮"""

        self.scene.pause()

    def on_visible(self, evt):
        """点击隐藏/显示按钮"""

        self.visible = not self.visible
        self.scene.set_visible('cudgel', self.visible)

    def on_save(self, evt):
        """点击保存按钮"""

        im = self.scene.get_buffer()

        wildcard = 'PNG files (*.png)|*.png|JPEG file (*.jpg)|*.jpg'
        dlg = wx.FileDialog(self, message='保存为文件', wildcard=wildcard, style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
        dlg.SetFilterIndex(0)
 
        if dlg.ShowModal() == wx.ID_OK:
            fn = dlg.GetPath()
            name, ext = os.path.splitext(fn)
            
            if ext != '.png' and ext != '.jpg':
                ext = ['.png', '.jpg'][dlg.GetFilterIndex()]

            if ext == '.jpg':
                im.convert('RGB').save('%s%s'%(name, ext))
            else:
                im.save('%s%s'%(name, ext))
        
        dlg.Destroy()

if __name__ == '__main__':
    app = wx.App()
    frame = MainFrame()
    frame.Show()
    app.MainLoop()

wx.png