wxPython in Action(112)

12.2 处理设备上下文

正如我们本章早先所说的,绘制到屏幕是一个UI工具包所做的最基本的事情。 wxPython所做的大多数绘制都被封装进了每个窗口部件的绘制方法中。因一个UI工具包所做的第二最本的事情大概就是封装了。然而,对你来说,这并不 终是能满足你的要求。有时,如第6章中,你需要响应用户的命令来进行绘制。有时你想要一些喜受的动画。有时你想像一台打印机一样在屏幕上绘制一个非标准的 显示。有时,你希望一个自定义外观的窗口部件,有时你仅仅想要一些装饰。在wxPython中,所有这些任务都通过操作一个适当的设备上下文来管理。

设 备上下文是一个抽象的东西,wxPython用以使你能够在一个图形设备上下进行绘制,诸如屏幕或打印机,而不用知道相关设备的细节。这通过提供一个抽象 的父类:wx.DC来得到管理,wx.DC定义了一个公共的API,这个API被它的一系列子类的所使用,每个子类代表一个不同的图形设备。第6章所述的 设备上下文使用了关于如何使用它们的一个扩展的例子。在随后的部分,我们将更详细的讨论设备上下文。

12.2.1 什么是设备上下文,以及如何创建它?

在wxPython中有十个wx.DC的子类,分成下面的三组:

用于绘制到屏幕的上下文

用于绘制到另一个地方,而非屏幕的上下文

用于缓冲一个设备上下文,直到你准备将它绘制到一个屏幕的上下文

基于屏幕的设备上下文

第一级代表了绘制到屏幕的设备上下文。你可能认为只需要它们中的一个就可以了,但实际上wxPython根据你的确切绘制对象和确切的绘制时机提供了四个。

wx.ClientDC

wx.PaintDC

wx.WindowDC

wx.ScreenDC


屏幕设备上下文是指临时创建的。这意味你无论你何时需要它们时只应该局部地创建它们,并且使它们能够被正常垃圾回收。你不应该试图以一个实例变量的形式占有一个设备上下文——这是不安全的,并可能导致程序的不稳定。

通 常,你会使用wx.ClientDC或wx.PaintDC来绘制到屏幕上的一个窗口。使用哪个取决于你执行绘制的时机。如果你在一个EVT_PAINT 事件处理期间绘制到屏幕,那么你必须使用wx.PaintDC。在其它的时间,你必须使用wx.ClientDC。实际上,无论你何时绑定一个处理器到 EVT_PAINT事件,你都必须在该处理器方法中创建一个wx.PaintDC对象,即使你不使用它(不创建一个wx.PaintDC会导致平台认为该 事件并未完全处理,并因此会发送另一个事件)。描绘(paint)事件要求不同的设备上下文的原因是,这个wx.PaintDC实例是被优化来只在重绘事 件期间的窗口刷新区域中进行绘制的,以便重绘更快。

你可以经由一个简单的构造函数来创建一个客户区(client)或描绘(paint) 上下文,构造函数的一个参数是你希望在其上进行绘制的wxPython窗口部件,两者的构造函数分别是wx.ClientDC(window)和 wx.PaintDC(window)。当你使用这两个上下文时,你将只能在该窗口部件的客户区中进行绘制。这意味在一个框架中,你不能在边框、标题栏或 其它装饰物上进行绘制。

如果你需要在框架的整个区域上进行绘制,包括边框和装饰物,那么你应该使用wx.WindowDC。创建一个 wx.WindowDC的方法和wx.ClientDC相似,相应的构造函数是wx.WindowDC(window)。和wx.ClientDC一样, 你不应该在一个描绘(paint)事件期间创建一个wx.WindowDC——边框绘制行为与描绘(paint)设备上下文的局部优化是不兼容的。

有 时,你不愿被限制于只绘制到一个单一的窗口,你想让整个屏幕作为你的画布。在这种情况下,你可以使用wx.ScreenDC。同样地,你不能在一描绘 (paint)事件期间创建它。这个构造函数没有参数(因为你不需要再指定绘制到的对象)——wx.ScreenDC()。创建了一个 wx.ScreenDC之后,你就可以像使用其它的设备上下文一样使用它了。你绘制的图像将显示在你的显示器中的所有的窗口的上层。

非屏幕设备上下文

第二组设备上下文用于绘制到项目,而非屏幕。这是不同事物的聚合,它们可被认为在逻辑上等同于屏幕显示。

wx.MemoryDC

wx.MetafileDC

wx.PostScriptDC

wx.PrinterDC


第 一个是wx.MemoryDC,它使你能够绘制到一个储存在内存中位图而非正显示的。你可以使用一个不带参数的构造函数wx.MemoryDC()来创建 一个wx.MemoryDC,但在使用它之前,你必须将它与一个位图相关联。这通过调用一个带有一个wx.Bitmap类型的参数的方法 SelectObject(bitmap)来实现。一旦你这样做了,你就可以绘制到这个内存设备上下文,并且内部的位图被改变。当你完成绘制时,你可以使 用Blit()方法将位图绘制到一个窗口。在随后的部分,我们将更详细地讨论内存设备上下文。

微软Windows图元文件 (metafile)的创建通过使用wx.MetafileDC上下文被简化了。这个上下文只在Windows系统上有效。创建一个图元文件设备上下文, 使用wx.MetafileDC(filename="")。如果filename为空,那么图元文件被创建在内存中。创建之后,发送给这个设备上下文的 绘制命令被写到这个文件。当你完成绘制后,你可以选择调用Close()方法,它对文件本身没有影响,只是返回一个wxPython的 wx.Metafile对象。对于当前版本的wxPython,你对一个wx.Metafile对象能做的唯一的事情是使用SetClipboard (width=0,height=0)方法把它发送到剪贴板。

类似的功能是更广泛使用的跨平台的对象wx.PostScriptDC,它 创建Encapsulated PostScript files(.eps)文件。你可以根据一个打印数据对象创建一个wx.PostScriptDC 文件——wx.PostScriptDC(printData)。参数printData是一个wx.PrintData,我们将在第17章对它进行讨 论。一旦创建后,PostScript设备上下文可以像其它的设备上下文一样被使用。你保存到的文件名可在wx.PrintData对象中被设置。因此, 你可以像下面的例子一样保存.eps文件。

    data = wx.PrintData() 
    data.SetFileName("/tmp/test.eps") 
    data.SetPaperId(wx.PAPER_LETTER) 
    dc = wx.PostScriptDC(data) 
    dc.StartDoc("") 
    dc.DrawCircle(300,300, 100) 
    dc.EndDoc() # the file is written at this point 

在Windows系统上,你可以使用wx.PrinterDC访问任何的Windows打印机的驱动。这个类也是根据一个打印数据对象来创建的——wx.PrinterDC(printData)。我们将在第17章进一步讨论打印。

缓冲设备上下文

第三组设备上下文使你能够缓冲一个设备上下文,直到你准备将之绘制到屏幕。

wx.BufferedDC

wx.BufferedPaintDC


缓冲使你能够发送单独的绘制命令到缓冲区,然后一次性地把它们绘制到屏幕。当你一下做几个重绘时,这防止了屏幕的闪烁。因此,当做动画或其它屏幕密集绘制时,缓冲是一个常见的技术。

在wxPython 中有两个缓冲设备上下文——wx.BufferedDC,它可被用于缓冲任何的设备上下文(但是通常只用于wx.ClientDC); wx.BufferedPaintDC,它专门被设计用来缓冲一个wx.PaintDC。作为内存设备上下文的一个简单包装,这两个缓冲上下文的工作方式 基本上是一样。wxBufferedDC的构造函数要求一个设备上下文和一个可选的位图作为参数——wx.BufferedDC(dc, buffer= None)。另一方面,wx.BufferedPaintDC要求一个窗口和一个可选的位图作为参数——wx.BufferedPaintDC(dc,  buffer=None)。参数dc是最终你想要绘制到的设备上下文,对于wx.BufferedPaintDC,窗口参数被用于内在地创建一个 wx.PaintDC,buffer参数是一个位图,它被作为临时的缓冲。如果buffer参数没有指定,那么该设备上下文内在地创建它自己的位图。一旦 缓冲设备上下文被创建,你就可以像其它的设备上下文样使用它。在内部,缓冲上下文使用一个内存设备上下文和该位图来储存绘制。这样的捷径就是你不需要做任 何特别的事来得到缓冲以绘制到实际的设备上下文。当缓冲设备上下文被垃圾回收时(通常当该方法结束且它已经退出作用域时),C++销毁函数触发Blit (),这将绘制缓冲区的内容到实际的设备上下文,而没有更多的工作需要你做。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值