Ross Wan's World!

Python, Ajax, PHP and Linux.

wxPython:自定义控件

Posted by Ross Wan 于 2008/05/02

       wxPython 虽然提供了大量的控件,但并没有一些特别的控件,我们只能自行创建这些控件 ──── 修改、增强现有的控件,或者整合其它控件来创建一个全新的控件。

超级链接控件(A hyperlink widget)

       这个示例将会创建一个超级链接控件,它基于 wx.lib.stattext.GenStatic 文本控件。

#!/usr/bin/python
# link.py

import wx
from wx.lib.stattext import GenStaticText
import webbrowser

class Link(GenStaticText):
    def __init__(self, parent, id=-1, label=”, pos=(-1, -1),
        size=(-1, -1), style=0, name=’Link’, URL=”):

        GenStaticText.__init__(self, parent, id, label, pos, size, style, name)

        self.url = URL

        self.font1 = wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD, True, ‘Verdana’)
        self.font2 = wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD, False, ‘Verdana’)

        self.SetFont(self.font2)
        self.SetForegroundColour(‘#0000ff’)

        self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent)
        self.Bind(wx.EVT_MOTION, self.OnMouseEvent)

    def OnMouseEvent(self, event):
        if event.Moving():
            self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
            self.SetFont(self.font1)

        elif event.LeftUp():
            webbrowser.open_new(self.url)

        else:
            self.SetCursor(wx.NullCursor)
            self.SetFont(self.font2)

        event.Skip()

class HyperLink(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(220, 150))

        panel = wx.Panel(self, -1)
        Link(panel, -1, ‘ZetCode’, pos=(10, 60), URL=’http://www.zetcode.com’)
        motto = GenStaticText(panel, -1, ‘Knowledge only matters’, pos=(10, 30))
        motto.SetFont(wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD, False, ‘Verdana’))

        self.Centre()
        self.Show(True)

app = wx.App()
HyperLink(None, -1, ‘A Hyperlink’)
app.MainLoop()

       我们只需继承 wx.lib.statictext 控件,并作一点儿修改:

 from wx.lib.stattext import GenStaticText
 import webbrowser

       webborwser 是 Python 的一个标准模块,使得我们可以在默认的浏览器里打开一个链接。

 self.SetFont(self.font2)
 self.SetForegroundColour(‘#0000ff’)

       设置超级链接文本的字体颜色。

 if event.Moving():
     self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
     self.SetFont(self.font1)

       当鼠标停留在超级链接上时,链接的文本将会加上下划线,并且鼠标指针变成手形。

 elif event.LeftUp():
     webbrowser.open_new(self.url)

       点击超级链接的时候,会在系统默认的浏览器里打开。

刻录控件(Burning widget)

       下面的例子将演示如何彻底地创建一个控件,我们在底部放置一个 wx.Panel 控件,然后在面板上面手动地绘画出整个控件。如果曾经使用过 CD 或者 DVD 刻录工具时,我们可能已经看过这个控件。

       注意,在 windows 下,为了避免闪烁,我人使用了双缓冲。

#!/usr/bin/python
# burning.py

import wx

class Widget(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id, size=(-1, 30), style=wx.SUNKEN_BORDER)
        self.parent = parent
        self.font = wx.Font(9, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL,
            wx.FONTWEIGHT_NORMAL, False, ‘Courier 10 Pitch’)

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

    def OnPaint(self, event):
        num = range(75, 700, 75)
        dc = wx.PaintDC(self)
        dc.SetFont(self.font)
    w, h = self.GetSize()

        self.cw = self.parent.GetParent().cw

        step = int(round(w / 10.0))

        j = 0

        till = (w / 750.0) * self.cw
        full = (w / 750.0) * 700

        if self.cw >= 700:
            dc.SetPen(wx.Pen(‘#FFFFB8’))
            dc.SetBrush(wx.Brush(‘#FFFFB8’))
            dc.DrawRectangle(0, 0, full, 30)
            dc.SetPen(wx.Pen(‘#ffafaf’))
            dc.SetBrush(wx.Brush(‘#ffafaf’))
            dc.DrawRectangle(full, 0, till-full, 30)
        else:
            dc.SetPen(wx.Pen(‘#FFFFB8’))
            dc.SetBrush(wx.Brush(‘#FFFFB8’))
            dc.DrawRectangle(0, 0, till, 30)

        dc.SetPen(wx.Pen(‘#5C5142’))
        for i in range(step, 10*step, step):
            dc.DrawLine(i, 0, i, 6)
            width, height = dc.GetTextExtent(str(num[j]))
            dc.DrawText(str(num[j]), i-width/2, 8)
            j = j + 1

    def OnSize(self, event):
        self.Refresh()

class Burning(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(330, 200))

        self.cw = 75

        panel = wx.Panel(self, -1)
        CenterPanel = wx.Panel(panel, -1)
        self.sld = wx.Slider(CenterPanel, -1, 75, 0, 750, (-1, -1), (150, -1), wx.SL_LABELS)

        vbox = wx.BoxSizer(wx.VERTICAL)
        hbox = wx.BoxSizer(wx.HORIZONTAL)
        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        hbox3 = wx.BoxSizer(wx.HORIZONTAL)

        self.wid = Widget(panel, -1)
        hbox.Add(self.wid, 1, wx.EXPAND)

        hbox2.Add(CenterPanel, 1, wx.EXPAND)
        hbox3.Add(self.sld, 0, wx.TOP, 35)

        CenterPanel.SetSizer(hbox3)

        vbox.Add(hbox2, 1, wx.EXPAND)
        vbox.Add(hbox, 0, wx.EXPAND)

        self.Bind(wx.EVT_SCROLL, self.OnScroll)

        panel.SetSizer(vbox)

        self.sld.SetFocus()

        self.Centre()
        self.Show(True)

    def OnScroll(self, event):
        self.cw = self.sld.GetValue()
        self.wid.Refresh()

app = wx.App()
Burning(None, -1, ‘Burning widget’)
app.MainLoop()

       OnPaint() 方法内的代码是控件的关键部分。这个控件将会显示介质的可用空间容量 ──── 最少是0,最大是750。当我们使用量超过700时,超过部分会显示红色,这是刻录最常见的防过烧指示。

 w, h = self.GetSize()
 self.cw = self.parent.GetParent().cw
 …
 till = (w / 750.0) * self.cw
 full = (w / 750.0) * 700

       控件取用动态绘制 ──── 也即是窗口越大,控件也越大,反之越小。正因为动态绘制,我们必须计算出控件里的 wx.Panel  的大小。 till 变量决定了控件的绘制大小,full 变量决定了红色区域的绘制开始点。

       实质上的绘制工作由3个部分组成:绘制黄色或者红色的矩形;绘制垂直线将控件划分成多个部分;绘制数字指示介质的容量。

 def OnSize(self, event):
     self.Refresh()

       当窗口改变大小的时候,我们刷新控件,使其重画。

 def OnScroll(self, event):
     self.cw = self.sld.GetValue()
     self.wid.Refresh()

       当滑动条控件的滑块变动时,我们取得滑动条的值并保存在 self.cw 变量里,并重画刻录控件。

CPU 控件(CPU widget)

       有些系统应用程序可以测量系统资源:温度、内存、CPU 占用等等。如果仅仅使用文本,如 CPU 54% 来显示的话,一定不会给用户留下深刻的印象。我们将创建一个特殊的 CPU 控件。

       注意,在 windows 下,为了避免闪烁,我们使用双缓冲。

#!/usr/bin/python
# cpu.py

import wx

class CPU(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id, size=(80, 110))

        self.parent = parent

        self.SetBackgroundColour(‘#000000’)

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

    def OnPaint(self, event):

        dc = wx.PaintDC(self)

        dc.SetDeviceOrigin(0, 100)
        dc.SetAxisOrientation(True, True)

        pos = self.parent.GetParent().GetParent().sel
        rect = pos / 5

        for i in range(1, 21):
            if i > rect:
                dc.SetBrush(wx.Brush(‘#075100’))
                dc.DrawRectangle(10, i*4, 30, 5)
                dc.DrawRectangle(41, i*4, 30, 5)
            else:
                dc.SetBrush(wx.Brush(‘#36ff27’))
                dc.DrawRectangle(10, i*4, 30, 5)
                dc.DrawRectangle(41, i*4, 30, 5)

class CPUWidget(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(190, 140))

        self.sel = 0

        panel = wx.Panel(self, -1)
        centerPanel = wx.Panel(panel, -1)

        self.cpu = CPU(centerPanel, -1)

        hbox = wx.BoxSizer(wx.HORIZONTAL)
        self.slider = wx.Slider(panel, -1, self.sel, 0, 100, (-1, -1), (25, 90),
        wx.VERTICAL | wx.SL_LABELS | wx.SL_INVERSE)
        self.slider.SetFocus()

        hbox.Add(centerPanel, 0,  wx.LEFT | wx.TOP, 20)
        hbox.Add(self.slider, 0, wx.LEFT | wx.TOP, 23)

        self.Bind(wx.EVT_SCROLL, self.OnScroll)

        panel.SetSizer(hbox)

        self.Centre()
        self.Show(True)

    def OnScroll(self, event):
        self.sel = event.GetInt()
        self.cpu.Refresh()

app = wx.App()
CPUWidget(None, -1, ‘cpu’)
app.MainLoop()

       控件的创建过程是很简单的,我们先创建一个黑色的面板,然后在上面绘制一个小矩形,矩形的颜色依赖于滑动条的值 ──── 深绿色或者浅绿色。

 dc.SetDeviceOrigin(0, 100)
 dc.SetAxisOrientation(True, True)

       设置默认的坐标系统为笛卡尔坐标系统(cartesian coordinates),这样可以使得控件的绘制更直观。

 pos = self.parent.GetParent().GetParent().sel
 rect = pos / 5

       在每一列有20个矩形,滑块条的值为0~100。rect 变量是一个根据滑块的值而转换为矩形的数量值,这些矩形将为设置为浅绿色。

 for i in range(1, 21):
     if i > rect:
         dc.SetBrush(wx.Brush(‘#075100’))
         dc.DrawRectangle(10, i*4, 30, 5)
         dc.DrawRectangle(41, i*4, 30, 5)
     else:
         dc.SetBrush(wx.Brush(‘#36ff27’))
         dc.DrawRectangle(10, i*4, 30, 5)
         dc.DrawRectangle(41, i*4, 30, 5)

       绘制40上矩形,每列20个。对于大于 rect 的矩形,将会设置为深绿色,其它的为浅绿色。

Advertisements

一条回应 to “wxPython:自定义控件”

  1. Ross Wan said

    翻译自:The wxPython tutorial

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

 
%d 博主赞过: