乐趣区

关于python:wxpython入门第八步画图

wxPython graphics

GDI(Graphics Device Interface,图形设施接口)是一个与图形工作的接口,用于与显示器、打印机或文件等图形设施交互。它用于与显示器、打印机或文件等图形设施进行交互。GDI 容许程序员在屏幕或打印机上显示数据,而不用关注特定设施的细节。GDI 将程序员与硬件隔离开来。

从程序员的角度来看,GDI 是一组用于解决图形的类和办法。GDI 由二维矢量图形、字体和图像组成。

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/gdi2.png” alt=”The GDI” style=”zoom:50%;” />

要开始绘制图形,咱们必须创立一个 设施上下文 DC)对象。在 wxPython 中,设施上下文被称为 wx.DC。文档中把wx.DC 定义为一个能够绘制图形和文本的设施上下文。它以一种通用的形式示意设施的数量。同一段代码能够写到不同类型的设施上。无论是屏幕还是打印机。wx.DC不是用来间接应用的。相同,程序员应该抉择一个派生类。每个派生类都是为了在特定条件下应用。

派生 wx.DC 类

  • wxBufferedDC
  • wxBufferedPaintDC
  • wxPostScriptDC
  • wxMemoryDC
  • wxPrinterDC
  • wxScreenDC
  • wxClientDC
  • wxPaintDC
  • wxWindowDC

wx.ScreenDC用于在屏幕上的任何中央绘画。wx.WindowDC用于在整个窗口上作画 (仅限 Windows)。这包含窗口装璜。wx.ClientDC 用于在窗口的客户端区域绘制。客户端区域是指没有装璜的窗口区域(题目和边框)。wx.PaintDC也用于在客户端区域进行绘制。然而 wx.PaintDCwx.ClientDC之间有一个区别。wx.PaintDC只能在 wx.PaintEvent 中应用。wx.ClientDC不应该在 wx.PaintEvent 中应用。wx.MemoryDC用于在位图上绘制图形。wx.PostScriptDC用于在任何平台上写入 PostScript 文件。wx.PrinterDC用于拜访打印机(仅限 Windows)。

画线

咱们的第一个例子将在窗口的客户端区域画一条简略的线。

DrawLine(self, x1, y1, x2, y2)

这种办法是从第一点到第二点画一条线;不包含第二点。

#draw_line.py

import wx

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        wx.CallLater(2000, self.DrawLine)

        self.SetTitle("Line")
        self.Centre()

    def DrawLine(self):

        dc = wx.ClientDC(self)
        dc.DrawLine(50, 60, 190, 60)

def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

两秒过后,咱们在框架窗口上画一条线。

wx.CallLater(2000, self.DrawLine)

咱们在窗口创立后调用 DrawLine() 办法。咱们这样做是因为,当窗口创立时,它就被绘制了。因而,咱们所有的绘图都将失落。咱们能够在窗口被创立后再开始绘制。这就是为什么咱们调用 wx.CallLater() 办法的起因。

def DrawLine(self):

    dc = wx.ClientDC(self)
    dc.DrawLine(50, 60, 190, 60)

咱们创立一个 wx.ClientDC 设施上下文。惟一的参数是咱们要绘制的窗口。在咱们的例子中,它是 self,是对wx.Frame widget 的援用。咱们调用设施上下文的DrawLine() 办法。这个调用实际上是在咱们的窗口上画一条线。

了解以下行为是十分重要的。如果咱们调整窗口的大小,这条线就会隐没。为什么会呈现这种状况?如果调整窗口的大小,每个窗口都会被从新绘制。如果它被最大化,它也会被从新绘制。如果咱们用另一个窗口笼罩窗口,而后再揭开,窗口也会被从新绘制。窗口被绘制到默认状态,咱们的线就会失落。每次调整窗口的大小时,咱们都必须画线。解决办法是wx.PaintEvent。每次窗口被从新绘制时,这个事件都会被触发。咱们将在一个与 paint 事件挂钩的办法中画线。

上面的例子展现了如何实现。

#draw_line2.py

import wx

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetTitle("Line")
        self.Centre()

    def OnPaint(self, e):

        dc = wx.PaintDC(self)
        dc.DrawLine(50, 60, 190, 60)


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

咱们画的是同一条线。这一次是对 paint 事件的反馈。

self.Bind(wx.EVT_PAINT, self.OnPaint)

这里咱们将 OnPaint 办法绑定到 wx.PaintEvent 事件。这意味着每次咱们的窗口被从新绘制时,咱们调用 OnPaint() 办法。当初,如果咱们调整窗口的大小(笼罩它,最大化它),这条线不会隐没。

dc = wx.PaintDC(self)

请留神,这次咱们应用了wx.PaintDC

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101102113582.png” alt=”image-20201101102113582″ style=”zoom:50%;” />

计算机图形

有两种不同的计算机图形。矢量和光栅图形。栅格图形以像素的汇合来示意图像。矢量图形是应用几何基元,如点、线、曲线或多边形来示意图像。这些基元是应用数学公式创立的。

两种类型的计算机图形都有长处和毛病。与光栅相比,矢量图形的长处是:

  • 尺寸较小
  • 可有限放大
  • 挪动、缩放、填充或旋转不会升高图像的品质。

以下是局部图形的列表。

  • points
  • lines
  • polylines
  • polygons
  • circles
  • ellipses
  • splines

属性

蕴含几个属性,如 Brush、Pen 或 Font。wx.Brush是一个用于填充区域的绘画工具。它用于绘制形态的背景。它有一个色彩和一个款式。wx.Pen用于绘制形态的轮廓。它有一个色彩,一个宽度和一个款式。wx.Font是一个决定文本外观的对象。

根本对象

在上面的行文中,咱们将介绍几个根本的对象:色彩、笔刷、笔、连贯、帽和突变。

色彩

色彩是代表红、绿、蓝(RGB)强度值组合的对象。无效的 RGB 值的范畴是 0 到 255。有三种办法能够设置色彩。咱们能够创立一个 wx.Colour 对象,应用一个预约义的色彩名称或应用十六进制值字符串。wx.Colour(0,0,255)'BLUE''#0000FF'。这三种符号产生雷同的色彩。

咱们有一个预约义的色彩名称列表,咱们能够在程序中应用。

AQUAMARINE BLACK BLUE BLUE VIOLET BROWN
CADET BLUE CORAL CORNFLOWER BLUE CYAN DARK GREY
DARK GREEN DARK OLIVE GREEN DARK ORCHID DARK SLATE BLUE DARK SLATE GREY
DARK TURQUOISE DIM GREY FIREBRICK FOREST GREEN GOLD
GOLDENROD GREY GREEN GREEN YELLOW INDIAN RED
KHAKI LIGHT BLUE LIGHT GREY LIGHT STEEL BLUE LIME GREEN
MAGENTA MAROON MEDIUM AQUAMARINE MEDIUM BLUE MEDIUM FOREST GREEN
MEDIUM GOLDENROD MEDIUM ORCHID MEDIUM SEA GREEN MEDIUM SLATE BLUE MEDIUM SPRING GREEN
MEDIUM TURQUOISE MEDIUM VIOLET RED MIDNIGHT BLUE NAVY ORANGE
ORANGE RED ORCHID PALE GREEN PINK PLUM
PURPLE RED SALMON SEA GREEN SIENNA
SKY BLUE SLATE BLUE SPRING GREEN STEEL BLUE TAN
THISTLE TURQUOISE VIOLET VIOLET RED WHEAT
WHITE YELLOW YELLOW GREEN

上面的例子应用了一些色彩值。

#colours.py

import wx

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetTitle("Colours")
        self.Centre()


    def OnPaint(self, e):

        dc = wx.PaintDC(self)
        dc.SetPen(wx.Pen('#d4d4d4'))

        dc.SetBrush(wx.Brush('#c56c00'))
        dc.DrawRectangle(10, 15, 90, 60)

        dc.SetBrush(wx.Brush('#1ac500'))
        dc.DrawRectangle(130, 15, 90, 60)

        dc.SetBrush(wx.Brush('#539e47'))
        dc.DrawRectangle(250, 15, 90, 60)

        dc.SetBrush(wx.Brush('#004fc5'))
        dc.DrawRectangle(10, 105, 90, 60)

        dc.SetBrush(wx.Brush('#c50024'))
        dc.DrawRectangle(130, 105, 90, 60)

        dc.SetBrush(wx.Brush('#9e4757'))
        dc.DrawRectangle(250, 105, 90, 60)

        dc.SetBrush(wx.Brush('#5f3b00'))
        dc.DrawRectangle(10, 195, 90, 60)

        dc.SetBrush(wx.Brush('#4c4c4c'))
        dc.DrawRectangle(130, 195, 90, 60)

        dc.SetBrush(wx.Brush('#785f36'))
        dc.DrawRectangle(250, 195, 90, 60)


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101102536628.png” alt=”image-20201101102536628″ style=”zoom:50%;” />

咱们画出九个长方形,并用不同的色彩填充。

dc.SetBrush(wx.Brush('#c56c00'))
dc.DrawRectangle(10, 15, 90, 60)

咱们用十六进制符号指定笔刷的色彩。画笔就是形态的背景填充。而后咱们用 DrawRectangle() 办法绘制矩形。

wx.Pen

Pen 是一个根本的图形对象,它用于绘制矩形、椭圆形、多边形或其余形态的线条、曲线和轮廓。

wx.Pen(wx.Colour colour, width=1, style=wx.SOLID)

wx.Pen构造函数有三个参数:色彩、宽度和款式。上面是一个笔的款式列表。

  • wx.SOLID
  • wx.DOT
  • wx.LONG_DASH
  • wx.SHORT_DASH
  • wx.DOT_DASH
  • wx.TRANSPARENT
#pens.py

import wx

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetTitle("Pens")
        self.Centre()

    def OnPaint(self, event):
        dc = wx.PaintDC(self)

        dc.SetPen(wx.Pen('#4c4c4c', 1, wx.SOLID))
        dc.DrawRectangle(10, 15, 90, 60)

        dc.SetPen(wx.Pen('#4c4c4c', 1, wx.DOT))
        dc.DrawRectangle(130, 15, 90, 60)

        dc.SetPen(wx.Pen('#4c4c4c', 1, wx.LONG_DASH))
        dc.DrawRectangle(250, 15, 90, 60)

        dc.SetPen(wx.Pen('#4c4c4c', 1, wx.SHORT_DASH))
        dc.DrawRectangle(10, 105, 90, 60)

        dc.SetPen(wx.Pen('#4c4c4c', 1, wx.DOT_DASH))
        dc.DrawRectangle(130, 105, 90, 60)

        dc.SetPen(wx.Pen('#4c4c4c', 1, wx.TRANSPARENT))
        dc.DrawRectangle(250, 105, 90, 60)


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101103120278.png” alt=”image-20201101103120278″ style=”zoom:50%;” />

如果咱们没有指定自定义画笔,则应用默认的画笔,默认的画笔是wx.WHITE_BRUSH。默认的笔刷是wx.WHITE_BRUSH。矩形的周长是由钢笔绘制的。最初一个矩形没有边框。它是通明的,即不可见。

Join 和 Cap

一个钢笔对象有两个额定的参数:join 和 cap。连贯定义了线条之间的连贯形式。连贯款式有以下选项。

wx.JOIN_MITER

wx.JOIN_BEVEL

wx.JOIN_ROUND

当应用 wx.JOIN_MITER 时,线条的外缘会被延长。它们以肯定的角度相遇,这个区域被填充。在 wx.JOIN_BEVEL 中,两条线之间的三角形缺口被填充。在 wx.JOIN_ROUND 中,填充了两条线之间的圆弧。默认值是 wx.JOIN_ROUND。

cap 定义了钢笔如何绘制线端。选项有

  • wx.CAP_ROUND
  • wx.CAP_PROJECTING
  • wx.CAP_BUTT

wx.CAP_ROUND画的是圆形的两端。wx.CAP_PROJECTINGwx.CAP_BUTT 画的是方形端点。它们之间的区别是 wx.CAP_PROJECTING 会超出端点一半的线条尺寸。wx.CAP_ROUND也会超出端点。

#joins_caps.py

import wx

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetTitle("Joins and caps")
        self.Centre()

    def OnPaint(self, e):

        dc = wx.PaintDC(self)

        pen = wx.Pen('#4c4c4c', 10, wx.SOLID)

        pen.SetJoin(wx.JOIN_MITER)
        dc.SetPen(pen)
        dc.DrawRectangle(15, 15, 80, 50)

        pen.SetJoin(wx.JOIN_BEVEL)
        dc.SetPen(pen)
        dc.DrawRectangle(125, 15, 80, 50)

        pen.SetJoin(wx.JOIN_ROUND)
        dc.SetPen(pen)
        dc.DrawRectangle(235, 15, 80, 50)

        pen.SetCap(wx.CAP_BUTT)
        dc.SetPen(pen)
        dc.DrawLine(30, 150,  150, 150)

        pen.SetCap(wx.CAP_PROJECTING)
        dc.SetPen(pen)
        dc.DrawLine(30, 190,  150, 190)

        pen.SetCap(wx.CAP_ROUND)
        dc.SetPen(pen)
        dc.DrawLine(30, 230,  150, 230)

        pen2 = wx.Pen('#4c4c4c', 1, wx.SOLID)
        dc.SetPen(pen2)
        dc.DrawLine(30, 130, 30, 250)
        dc.DrawLine(150, 130, 150, 250)
        dc.DrawLine(155, 130, 155, 250)


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()
pen = wx.Pen('#4c4c4c', 10, wx.SOLID)

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101103337422.png” alt=”image-20201101103337422″ style=”zoom:50%;” />

为了看到各种 join 和 cap 款式,咱们须要将笔的宽度设置为大于 1。

dc.DrawLine(150, 130, 150, 250)
dc.DrawLine(155, 130, 155, 250)

请留神两条突围的竖线。它们之间的间隔是 5px。这正好是以后笔宽的一半。

突变

突变是指从浅色到深色或从一种色彩到另一种色彩的平滑混合。在二维绘图程序和绘画程序中,突变用于创立多彩的背景和特殊效果,以及模仿灯光和暗影。

GradientFillLinear(self, rect, initialColour, destColour, nDirection=RIGHT)

此办法用线性突变填充 “rect “ 指定的区域,从 “initialColour “ 开始,最终突变到 “destColour”。nDirection参数指定色彩变动的方向,默认值是wx.EAST

#gradients.py

import wx

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetTitle("Gradients")
        self.Centre()

    def OnPaint(self, event):

        dc = wx.PaintDC(self)

        dc.GradientFillLinear((20, 20, 180, 40), '#ffec00', '#000000', wx.NORTH)
        dc.GradientFillLinear((20, 80, 180, 40), '#ffec00', '#000000', wx.SOUTH)
        dc.GradientFillLinear((20, 140, 180, 40), '#ffec00', '#000000', wx.EAST)
        dc.GradientFillLinear((20, 200, 180, 40), '#ffec00', '#000000', wx.WEST)


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101103621870.png” alt=”image-20201101103621870″ style=”zoom:50%;” />

在例子中,四个矩形被填充了突变。

wx.Brush

Brush 是一个根本的图形对象。它用于绘制图形形态的背景,如矩形、椭圆或多边形。

wxPython 内置了以下笔刷类型。

  • wx.SOLID
  • wx.STIPPLE
  • wx.BDIAGONAL_HATCH
  • wx.CROSSDIAG_HATCH
  • wx.FDIAGONAL_HATCH
  • wx.CROSS_HATCH
  • wx.HORIZONTAL_HATCH
  • wx.VERTICAL_HATCH
  • wx.TRANSPARENT
#brushes.py

import wx

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetTitle("Brushes")
        self.Centre()

    def OnPaint(self, e):

        dc = wx.PaintDC(self)

        dc.SetBrush(wx.Brush('#4c4c4c', wx.CROSS_HATCH))
        dc.DrawRectangle(10, 15, 90, 60)

        dc.SetBrush(wx.Brush('#4c4c4c', wx.SOLID))
        dc.DrawRectangle(130, 15, 90, 60)

        dc.SetBrush(wx.Brush('#4c4c4c', wx.BDIAGONAL_HATCH))
        dc.DrawRectangle(250, 15, 90, 60)

        dc.SetBrush(wx.Brush('#4c4c4c', wx.CROSSDIAG_HATCH))
        dc.DrawRectangle(10, 105, 90, 60)

        dc.SetBrush(wx.Brush('#4c4c4c', wx.FDIAGONAL_HATCH))
        dc.DrawRectangle(130, 105, 90, 60)

        dc.SetBrush(wx.Brush('#4c4c4c', wx.HORIZONTAL_HATCH))
        dc.DrawRectangle(250, 105, 90, 60)

        dc.SetBrush(wx.Brush('#4c4c4c', wx.VERTICAL_HATCH))
        dc.DrawRectangle(10, 195, 90, 60)

        dc.SetBrush(wx.Brush('#4c4c4c', wx.TRANSPARENT))
        dc.DrawRectangle(130, 195, 90, 60)


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101103835780.png” alt=”image-20201101103835780″ style=”zoom:50%;” />

例子中应用了八种不同的内置笔刷类型。

Custom Patterns

咱们不受限于应用预约义的模式。咱们能够轻松地创立本人的自定义模式。

#custom_patterns.py

import wx

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetTitle("Custom patterns")
        self.Centre()

    def OnPaint(self, e):

        dc = wx.PaintDC(self)

        dc.SetPen(wx.Pen('#C7C3C3'))

        brush1 = wx.Brush(wx.Bitmap('pattern1.png'))
        dc.SetBrush(brush1)
        dc.DrawRectangle(10, 15, 90, 60)

        brush2 = wx.Brush(wx.Bitmap('pattern2.png'))
        dc.SetBrush(brush2)
        dc.DrawRectangle(130, 15, 90, 60)

        brush3 = wx.Brush(wx.Bitmap('pattern3.png'))
        dc.SetBrush(brush3)
        dc.DrawRectangle(250, 15, 90, 60)


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101104057139.png” alt=”image-20201101104057139″ style=”zoom:50%;” />

brush1 = wx.Brush(wx.Bitmap('pattern1.png'))
dc.SetBrush(brush1)
dc.DrawRectangle(10, 15, 90, 60)

刷子是由位图创立的,它用于填充一个矩形的外部。

Points

最简略的几何物体是一个点。它是窗口上的一个一般点。

DrawPoint(self, x, y)

此办法在 x、y 坐标处画一个点。

#points.py

import wx
import random

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetTitle("Points")
        self.Centre()

    def OnPaint(self, e):

        dc = wx.PaintDC(self)

        dc.SetPen(wx.Pen('RED'))

        for i in range(1000):

            w, h = self.GetSize()
            x = random.randint(1, w-1)
            y = random.randint(1, h-1)
            dc.DrawPoint(x, y)


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101104319232.png” alt=”image-20201101104319232″ style=”zoom:50%;” />

单点可能很难看到,所以咱们发明 1000 点。

dc.SetPen(wx.Pen('RED'))

这里咱们将笔的色彩设置为红色。

w, h = self.GetSize()
x = random.randint(1, w-1)

这些点在窗口的客户端区域四周随机散布。它们也是动静散布的。如果咱们调整窗口的大小,这些点将在新的客户端大小上随机抽取。randint(a, b)办法返回一个范畴为 [a, b] 的随机整数,例如,包含两个点。

Shapes

shape 是比较复杂的几何图形对象。咱们在上面的例子中画出各种几何图形。

#shapes.py

import wx

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetTitle("Shapes")
        self.Centre()


    def OnPaint(self, e):

        dc = wx.PaintDC(self)
        dc.SetBrush(wx.Brush('#777'))
        dc.SetPen(wx.Pen("#777"))

        dc.DrawEllipse(20, 20, 90, 60)
        dc.DrawRoundedRectangle(130, 20, 90, 60, 10)
        dc.DrawArc(240, 40, 340, 40, 290, 20)

        dc.DrawRectangle(20, 120, 80, 50)
        dc.DrawPolygon(((130, 140), (180, 170), (180, 140), (220, 110), (140, 100)))
        dc.DrawSpline(((240, 170), (280, 170), (285, 110), (325, 110)))

        dc.DrawLines(((20, 260), (100, 260), (20, 210), (100, 210)))
        dc.DrawCircle(170, 230, 35)
        dc.DrawRectangle(250, 200, 60, 60)


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101110119404.png” alt=”image-20201101110119404″ style=”zoom:50%;” />

在咱们的例子中,咱们画了一个椭圆、一个圆角矩形、一个弧形、一个矩形、一个多边形、S 型线、线条、一个圆和一个正方形。圆是一种非凡的椭圆,正方形是一种非凡的矩形。

Regions

一个区域能够是任何形态,如矩形或圆形。通过 “Union”、”Intersect”、”Substract “ 和 “Xor “ 操作,咱们能够创立简单的区域。区域用于勾画、填充和剪切。

咱们能够用三种形式创立区域。最简略的办法是创立一个矩形区域。更简单的区域能够从位图的点列表中创立。

在咱们进入区域之前,咱们将先创立一个小例子。

#lines.py

import wx
from math import hypot, sin, cos, pi

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetTitle('Lines')
        self.Centre()

    def OnPaint(self, e):

        dc = wx.PaintDC(self)
        size_x, size_y = self.GetClientSize()
        dc.SetDeviceOrigin(size_x/2, size_y/2)

        radius = hypot(size_x/2, size_y/2)
        angle = 0

        while (angle < 2*pi):
            x = radius*cos(angle)
            y = radius*sin(angle)
            dc.DrawLine((0, 0), (x, y))
            angle = angle + 2*pi/360


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101110419096.png” alt=”image-20201101110419096″ style=”zoom:50%;” />

在这个例子中,咱们从客户端区域的两头画出 360 条线。两条线之间的间隔是 1 度。

import wx
from math import hypot, sin, cos, pi

咱们须要三个数学函数和一个数学模块的常数。

dc.SetDeviceOrigin(size_x/2, size_y/2)

办法 SetDeviceOrigin() 创立了一个新的坐标系终点。咱们把它放到客户端区域的两头。通过从新定位坐标系,咱们使咱们的绘图不那么简单。

radius = hypot(size_x/2, size_y/2)

在这里,咱们失去了斜边。它是最长的线,咱们能够从客户端区域的两头绘制。它是应该从开始画到窗口角落的线的长度。

x = radius*cos(angle)
y = radius*sin(angle)

这些是参数函数。它们用来寻找曲线上的 [x,y] 点。所有的 360 线都是从坐标系的终点开始画到圆上的点。

Clipping

“ 剪切 “ 是将绘图限度在某一区域。剪裁通常用于创立成果和进步应用程序的性能。咱们通过 SetClippingRegionAsRegion() 办法将绘图限度在某个区域。

在上面的例子中,咱们将对之前的程序进行批改和加强。

#star.py

import wx
from math import hypot, sin, cos, pi

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.SetTitle("Star")
        self.Centre()

    def OnPaint(self, e):

        dc = wx.PaintDC(self)

        dc.SetPen(wx.Pen('#424242'))
        size_x, size_y = self.GetClientSize()
        dc.SetDeviceOrigin(size_x/2, size_y/2)

        points = (((0, 85), (75, 75), (100, 10), (125, 75), (200, 85),
            (150, 125), (160, 190), (100, 150), (40, 190), (50, 125)))

        region = wx.Region(points)
        dc.SetDeviceClippingRegion(region)

        radius = hypot(size_x/2, size_y/2)
        angle = 0

        while (angle < 2*pi):

            x = radius*cos(angle)
            y = radius*sin(angle)
            dc.DrawLine((0, 0), (x, y))
            angle = angle + 2*pi/360

        dc.DestroyClippingRegion()


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101110734081.png” alt=”image-20201101110734081″ style=”zoom:50%;” />

咱们再次画出所有的 360 线。但这次只画出了一部分。咱们限度绘制的区域是一个五角星。

region = wx.Region(points)
dc.SetDeviceClippingRegion(region)

咱们从点的列表中创立一个区域。SetDeviceClippingRegion()办法将绘图限度在指定的区域内。在咱们的例子中,它是一个星形对象。

dc.DestroyClippingRegion()

咱们必须 destroy 剪切区域。

Region 操作

区域能够组合成更简单的形态。咱们能够应用四种汇合操作:union, intersect, substract, xor.

上面的例子展现了所有这四种操作的操作。

#region_operations.py

import wx

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):

         self.Bind(wx.EVT_PAINT, self.OnPaint)

         self.SetTitle("Regions")
         self.Centre()

    def OnPaint(self, e):

         dc = wx.PaintDC(self)
         dc.SetPen(wx.Pen('#d4d4d4'))

         dc.DrawRectangle(20, 20, 50, 50)
         dc.DrawRectangle(30, 40, 50, 50)

         dc.SetBrush(wx.Brush('#ffffff'))
         dc.DrawRectangle(100, 20, 50, 50)
         dc.DrawRectangle(110, 40, 50, 50)

         region1 = wx.Region(100, 20, 50, 50)
         region2 = wx.Region(110, 40, 50, 50)
         region1.Intersect(region2)

         rect = region1.GetBox()
         dc.SetDeviceClippingRegion(region1)
         dc.SetBrush(wx.Brush('#ff0000'))
         dc.DrawRectangle(rect)
         dc.DestroyClippingRegion()

         dc.SetBrush(wx.Brush('#ffffff'))
         dc.DrawRectangle(180, 20, 50, 50)
         dc.DrawRectangle(190, 40, 50, 50)

         region1 = wx.Region(180, 20, 50, 50)
         region2 = wx.Region(190, 40, 50, 50)
         region1.Union(region2)
         dc.SetDeviceClippingRegion(region1)

         rect = region1.GetBox()
         dc.SetBrush(wx.Brush('#fa8e00'))
         dc.DrawRectangle(rect)
         dc.DestroyClippingRegion()

         dc.SetBrush(wx.Brush('#ffffff'))
         dc.DrawRectangle(20, 120, 50, 50)
         dc.DrawRectangle(30, 140, 50, 50)
         region1 = wx.Region(20, 120, 50, 50)
         region2 = wx.Region(30, 140, 50, 50)
         region1.Xor(region2)

         rect = region1.GetBox()
         dc.SetDeviceClippingRegion(region1)
         dc.SetBrush(wx.Brush('#619e1b'))
         dc.DrawRectangle(rect)
         dc.DestroyClippingRegion()

         dc.SetBrush(wx.Brush('#ffffff'))
         dc.DrawRectangle(100, 120, 50, 50)
         dc.DrawRectangle(110, 140, 50, 50)
         region1 = wx.Region(100, 120, 50, 50)
         region2 = wx.Region(110, 140, 50, 50)
         region1.Subtract(region2)

         rect = region1.GetBox()
         dc.SetDeviceClippingRegion(region1)
         dc.SetBrush(wx.Brush('#715b33'))
         dc.DrawRectangle(rect)
         dc.DestroyClippingRegion()

         dc.SetBrush(wx.Brush('#ffffff'))
         dc.DrawRectangle(180, 120, 50, 50)
         dc.DrawRectangle(190, 140, 50, 50)
         region1 = wx.Region(180, 120, 50, 50)
         region2 = wx.Region(190, 140, 50, 50)
         region2.Subtract(region1)

         rect = region2.GetBox()
         dc.SetDeviceClippingRegion(region2)
         dc.SetBrush(wx.Brush('#0d0060'))
         dc.DrawRectangle(rect)
         dc.DestroyClippingRegion()


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101111519996.png” alt=”image-20201101111519996″ style=”zoom:50%;” />

In the example, we present six region set operations.

 region1 = wx.Region(100, 20, 50, 50)
 region2 = wx.Region(110, 40, 50, 50)
 region1.Intersect(region2)

这段代码对两个区域进行交加运算。

映射模式

映射模式定义了用于将页面空间单位转换为设施空间单位的度量单位,还定义了设施的 X 轴和 Y 轴的方向。

逻辑和设施单位

如果咱们在客户端区域上绘制文本或几何基元,咱们会应用逻辑单位来定位它们。

如果咱们要绘制一些文本,咱们提供文本参数和 x、y 地位。x、y 是以逻辑单位为单位。而后设施以设施单位绘制文本。逻辑单位和设施单位可能雷同,也可能不同。逻辑单位是人们应用的(毫米),设施单位是 “ 特定 “ 设施的本地单位。例如,一个屏幕的本地设施单位是像素。惠普 LaserJet 1022 的原生设施单位是 1200dpi(dots per inch)。

设施的 映射模式 是一种将逻辑单位转换为设施单位的办法。wxPython 有以下映射模式。

Mapping Mode Logical Unit
wx.MM_TEXT 1 pixel
wx.MM_METRIC 1 millimeter
wx.MM_LOMETRIC 1/10 of a millimeter
wx.MM_POINTS 1 point, 1/72 of an inch
wx.MM_TWIPS 1/20 of a point or 1/1440 of an inch

默认的映射模式是 wx.MM_TEXT。在这种模式下,逻辑单位和设施单位是一样的。当人们在屏幕上定位对象或设计网页时,他们通常以像素为单位进行思考。网页设计者创立三栏式网页,这些栏位的设置是以像素为单位的。一个页面的最低公分母通常是 800 px 等。这种思维很天然,因为咱们晓得咱们的显示器有如 1024×768 pxs。咱们不会进行换算,而是习惯于以像素为单位进行思考。如果咱们想以毫米为单位画一个构造,咱们能够应用两种公制映射模式。间接以毫米为单位绘制对屏幕来说太粗了,这就是为什么咱们有wx.MM_LOMETRIC 映射模式。

要设置不同的贴图模式,咱们应用 SetMapMode() 办法。

Ruler 例子

ruler 以像素为单位测量屏幕对象。

#ruler.py

import wx


RW = 701 # ruler width
RM = 10  # ruler margin
RH = 80  # ruler height


class Example(wx.Frame):

    def __init__(self, parent):
        wx.Frame.__init__(self, parent, size=(RW + 2*RM, RH),
            style=wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.STAY_ON_TOP)
        self.font = wx.Font(7, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL,
            wx.FONTWEIGHT_BOLD, False, 'Courier 10 Pitch')

        self.InitUI()

    def InitUI(self):

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
        self.Bind(wx.EVT_MOTION, self.OnMouseMove)

        self.Centre()
        self.Show(True)

    def OnPaint(self, e):

        dc = wx.PaintDC(self)

        brush = wx.Brush(wx.Bitmap('granite.png'))
        dc.SetBrush(brush)
        dc.DrawRectangle(0, 0, RW+2*RM, RH)
        dc.SetFont(self.font)

        dc.SetPen(wx.Pen('#F8FF25'))
        dc.SetTextForeground('#F8FF25')

        for i in range(RW):

            if not (i % 100):

                dc.DrawLine(i+RM, 0, i+RM, 10)
                w, h = dc.GetTextExtent(str(i))
                dc.DrawText(str(i), i+RM-w/2, 11)

            elif not (i % 20):

                dc.DrawLine(i+RM, 0, i+RM, 8)

            elif not (i % 2):

                dc.DrawLine(i+RM, 0, i+RM, 4)

    def OnLeftDown(self, e):

        x, y = self.ClientToScreen(e.GetPosition())
        ox, oy = self.GetPosition()

        dx = x - ox
        dy = y - oy

        self.delta = ((dx, dy))

    def OnMouseMove(self, e):

        if e.Dragging() and e.LeftIsDown():

            self.SetCursor(wx.Cursor(wx.CURSOR_HAND))

            x, y = self.ClientToScreen(e.GetPosition())
            fp = (x - self.delta[0], y - self.delta[1])
            self.Move(fp)

    def OnLeftUp(self, e):

        self.SetCursor(wx.Cursor(wx.CURSOR_ARROW))

    def OnRightDown(self, e):

        self.Close()


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

<img src=”https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201101112246816.png” alt=”image-20201101112246816″ style=”zoom:50%;” />

在这个例子中,咱们创立一个标尺。这个尺子以像素为单位测量屏幕对象。咱们保留了默认的映射模式,即wx.MM_TEXT。正如咱们曾经提到的,这种模式具备雷同的逻辑和设施单位。在咱们的例子中,这些单位是像素。

def __init__(self, parent):
    wx.Frame.__init__(self, parent, size=(RW + 2*RM, RH),
        style=wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.STAY_ON_TOP)

咱们曾经创立了一个无边框的窗口。尺子的宽度是 721 px。RW + 2RM = 701 + 20 = 721. 标尺上显示 700 个数字;0 … 700 是 701 像素。尺子两边都有边距,210 是 20 像素。合起来就是 721 个像素。

brush = wx.Brush(wx.Bitmap('granite.png'))
dc.SetBrush(brush)
dc.DrawRectangle(0, 0, RW+2*RM, RH)

这里咱们在窗口上绘制一个自定义的图案。咱们应用了 Gimp 中的一个预约义图案。它被称为花岗岩。

w, h = dc.GetTextExtent(str(i))
dc.DrawText(str(i), i+RM-w/2, 11)

这些行确保咱们正确地对齐文本。GetTextExtent()办法返回文本的宽度和高度。

咱们的窗口四周没有边框。所以咱们必须手动解决挪动。OnLeftDown()OnMouseMove() 办法使咱们可能挪动标尺。

def OnLeftDown(self, e):

    x, y = self.ClientToScreen(e.GetPosition())
    ox, oy = self.GetPosition()

    dx = x - ox
    dy = y - oy

    self.delta = ((dx, dy))

OnLeftDown() 办法中,咱们确定了窗口和鼠标光标的坐标;delta 值是鼠标指针离窗口左上角的间隔。咱们须要 delta 值来挪动窗口。

def OnMouseMove(self, e):

    if e.Dragging() and e.LeftIsDown():

        self.SetCursor(wx.Cursor(wx.CURSOR_HAND))

        x, y = self.ClientToScreen(e.GetPosition())
        fp = (x - self.delta[0], y - self.delta[1])
        self.Move(fp)

当咱们同时拖动窗口并按下鼠标左键时,该代码就会被执行。在代码块中,咱们用 SetCursor() 扭转鼠标光标,用 Move() 办法挪动窗口。用 delta 值来获取间隔。

def OnLeftUp(self, e):

    self.SetCursor(wx.Cursor(wx.CURSOR_ARROW))

当咱们开释鼠标左键时,咱们将光标变回箭头。

def OnRightDown(self, e):

    self.Close()

右键点击窗口区域,即可敞开窗口。

退出移动版