Динамическое рисование с помощью Cairo и wxPython

Я работаю над новым проектом, который написан с использованием wxPython и Cairo, чтобы динамически рисовать объекты на холсте. Все работает довольно хорошо, хотя я заметил большое предостережение с wxPython, с которым мне трудно работать. Я довольно плохо знаком с wxPython и очень плохо знаком с Каиром, поэтому ответ может быть очевиден, но я не могу найти его где-либо.

Проблема, с которой я сталкиваюсь, заключается в том, что кажется, что вы можете рисовать только в графическом контексте (wx.GraphicsContext, я считаю), когда вызывается wx.EVT_PAINT, хотя мне нужны внешние классы, чтобы рисовать на холсте. без труда.

Мой первоначальный план состоял в том, чтобы создать контекст Cairo, затем сохранить его в классе, в котором находится холст, тогда любой класс, которому нужен доступ к контексту для рисования, просто получил бы его, используя что-то вроде canvas.ctx.

Мой общий вопрос: есть ли способ получить доступ к Cairo Context без необходимости вызова wx.EVT_PAINT?

Вот код, с которым я сейчас работаю:

import wx
import CairoAPI

class Canvas(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "test", pos=(0, 0), size=(640,480))
        #self.ShowFullScreen(1)
        self.Bind(wx.EVT_PAINT, self.OnPaint)

    def DrawRectangle(self):
        pass

    def OnPaint(self, event):
        dc = wx.PaintDC(self)
        w,h = dc.GetSizeTuple()
        gc = wx.GraphicsContext.Create(dc)
        nc = gc.GetNativeContext()
        ctx = CairoAPI.Context_FromSWIGObject(nc)


if __name__=="__main__":

    app = wx.App()
    canvas = Canvas()
    canvas.Show()
    app.MainLoop()

В этом коде я хочу создать canvas.DrawRectangle и иметь возможность записи на холст без вызова функции из canvas.OnPaint.

Извините, если я запутал эти вопросы. Я только начал изучать Каир прошлой ночью, и я все еще немного незнаком с тем, как это работает, и с правильной терминологией для некоторых вещей.

Спасибо!

РЕДАКТИРОВАТЬ: Я забыл некоторый код: модуль "CairoAPI" я кое-что получил из учебника (не могу вспомнить, какой из них от руки). Вот источник для этого.

import ctypes
import cairo
from ctypes.util import find_library

cairo_dll = ctypes.CDLL(find_library("cairo"))

# Pycairo's API representation (from pycairo.h)
class Pycairo_CAPI(ctypes.Structure):
   _fields_ = [
      ('Context_Type', ctypes.py_object),
      ('Context_FromContext', ctypes.PYFUNCTYPE(ctypes.py_object,
                                                ctypes.c_void_p,
                                                ctypes.py_object,
                                                ctypes.py_object)),
      ('FontFace_Type', ctypes.py_object),
      ('FontFace_FromFontFace', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
      ('FontOptions_Type', ctypes.py_object),
      ('FontOptions_FromFontOptions', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
      ('Matrix_Type', ctypes.py_object),
      ('Matrix_FromMatrix', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
      ('Path_Type', ctypes.py_object),
      ('Path_FromPath', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
      ('Pattern_Type', ctypes.py_object),
      ('SolidPattern_Type', ctypes.py_object),
      ('SurfacePattern_Type', ctypes.py_object),
      ('Gradient_Type', ctypes.py_object),
      ('LinearGradient_Type', ctypes.py_object),
      ('RadialGradient_Type', ctypes.py_object),
      ('Pattern_FromPattern', ctypes.c_void_p),
      ('ScaledFont_Type', ctypes.py_object),
      ('ScaledFont_FromScaledFont', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
      ('Surface_Type', ctypes.py_object),
      ('ImageSurface_Type', ctypes.py_object),
      ('PDFSurface_Type', ctypes.py_object),
      ('PSSurface_Type', ctypes.py_object),
      ('SVGSurface_Type', ctypes.py_object),
      ('Win32Surface_Type', ctypes.py_object),
      ('XlibSurface_Type', ctypes.py_object),
      ('Surface_FromSurface', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
      ('Check_Status', ctypes.PYFUNCTYPE(ctypes.c_int, ctypes.c_int))]

# look up the API
ctypes.pythonapi.PyCObject_Import.restype = ctypes.POINTER(Pycairo_CAPI)
pycairo_api = ctypes.pythonapi.PyCObject_Import("cairo", "CAPI").contents

ContextType = pycairo_api.Context_Type

def Context_FromSWIGObject(swigObj):
    ptr = ctypes.c_void_p(int(swigObj))
    #increment the native context's ref count, since the Pycairo_Context decrements it
    #when it is finalised.
    cairo_dll.cairo_reference(ptr)
    return pycairo_api.Context_FromContext(ptr, ContextType, None)

1 ответ

Решение

Я сделал так, как мне велел Майк Дрисколл ( в комментарии выше), и разместил свой вопрос как в группе wxPython, так и в списке рассылки Каира, а ответ от одного из членов списка Каира был следующим:

Посмотрите на wxWindowDC, wxClientDC.

Посмотрев эти классы, я прочитал:

WxClientDC должен быть создан, если приложение желает рисовать в клиентской области окна снаружи события OnPaint. Это обычно должно быть построено как временный объект стека; не храните объект wxClientDC.

Это именно то, что я искал. Я надеюсь, что это поможет любому столкнуться с той же проблемой в будущем.

Спасибо! Джереми Оверман

Другие вопросы по тегам