python圖形化界面設計(wxpython)四wxPython庫


本篇內容來自https://hekaiyou.blog.csdn.net/article/details/107360100

 

 

Python3 wxPython庫

這個第三方庫用於開發跨平台的 GUI 應用程序,可以輕松地創建健壯、功能強大的 GUI 程序。通過 pip install wxPython 命令下載 wxPython 庫。

Hello World

下面是業余版本的 Hello World:

wxpython_helloworld

# 導入wxPython庫
import wx

# 創建一個應用程序對象
app = wx.App()
# 創建一個框架
frm = wx.Frame(None, title="Hello World")
# 展示框架
frm.Show()
# 啟動事件循環
app.MainLoop()

下面是專業版本的 Hello World Pro:

wxpython_helloworldpro

import wx

class HelloWorldPro(wx.Frame):
    """
    Hello World Pro
    """

    def __init__(self, *args, **kw):
        # 確保父類的 __init__ 被調用
        super(HelloWorldPro, self).__init__(*args, **kw)
        # 在框架中創建一個面板
        pnl = wx.Panel(self)
        # 在上面放一個大號的靜態文本
        st = wx.StaticText(pnl, label="Hello World Pro!")
        font = st.GetFont()
        font.PointSize += 10
        font = font.Bold()
        st.SetFont(font)
        # 創建一個大小調整器來管理子控件的布局
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(st, wx.SizerFlags().Border(wx.TOP | wx.LEFT, 25))
        pnl.SetSizer(sizer)
        # 創建菜單欄
        self.make_menu_bar()
        # 創建狀態欄
        self.CreateStatusBar()
        self.SetStatusText("狀態欄")

    def make_menu_bar(self):
        """
        菜單欄由菜單組成,菜單由菜單項組成。此方法將構建一組菜單,並綁定選擇菜單項時要調用的處理函數。
        """

        # 使用 "Hello" 和 "退出" 項目創建 "文件" 菜單
        file_menu = wx.Menu()
        # 語法 "\t..." 定義了一個快捷鍵
        hello_item = file_menu.Append(-1, "&Hello...\tCtrl-H", "此菜單項在狀態欄中顯示的幫助信息")
        file_menu.AppendSeparator()
        # 使用 Stock ID 時,無需指定菜單項的標簽
        # https://docs.wxpython.org/stock_items.html
        exit_item = file_menu.Append(wx.ID_EXIT)
        # 只有一個 "關於" 項目的 "幫助" 菜單
        help_menu = wx.Menu()
        about_item = help_menu.Append(wx.ID_ABOUT)
        # 制作菜單欄,然后向其中添加兩個菜單
        menu_bar = wx.MenuBar()
        menu_bar.Append(file_menu, "&文件")
        menu_bar.Append(help_menu, "&幫助")
        # 將菜單欄移至框架
        self.SetMenuBar(menu_bar)
        # 將每個菜單項的處理函數與 EVT_MENU 事件關聯
        self.Bind(wx.EVT_MENU, self.on_hello, hello_item)
        self.Bind(wx.EVT_MENU, self.on_exit, exit_item)
        self.Bind(wx.EVT_MENU, self.on_about, about_item)

    def on_exit(self, event):
        """關閉框架,終止應用程序。"""
        self.Close(True)

    def on_hello(self, event):
        """顯示Hello對話框。"""
        wx.MessageBox("Hello World Pro!")

    def on_about(self, event):
        """顯示關於對話框"""
        wx.MessageBox("這是一個wxPython的演示Demo", "關於Hello World Pro", wx.OK | wx.ICON_INFORMATION)

if __name__ == '__main__':
    # 創建應用和框架
    app = wx.App()
    frm = HelloWorldPro(None, title='Hello World Pro')
    # 顯示框架並啟動事件循環
    frm.Show()
    app.MainLoop()
View Code

布局管理

絕對定位

該定位是以像素為單位對控件進行定位,但是該定位方式在整窗口大小時,控件的尺寸和位置不會隨之改變,不推薦使用。

wxpython_possize

class Example(wx.Frame):
    def __init__(self, parent):
        super(Example, self).__init__(parent, title='絕對定位', size=(260, 180))
        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):
        panel = wx.Panel(self, -1)
        # 使用絕對定位,x=3、y=3,寬度250px、高度150px
        wx.TextCtrl(panel, pos=(3, 3), size=(250, 150))

Sizers

該定位比使用絕對定位更通用更靈活,可供選擇的 Sizers 類型有:wx.BoxSizerwx.StaticBoxSizerwx.GridSizerwx.FlexGridSizerwx.GridBagSizer

wxpython_sizers

class Example(wx.Frame):
    """
    把 wx.TextCtrl 放入 wx.Frame,它有一個內置的 sizer,但是只允許放置一個控件,多於一個的話會得到混亂的布局,
    放入的子控件占用了所有剩余空間,除去邊框、菜單、工具欄和狀態欄
    """
    def __init__(self, parent):
        super(Example, self).__init__(parent, title='內置的Sizer', size=(260, 180))
        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):
        menubar = wx.MenuBar()
        filem = wx.Menu()
        editm = wx.Menu()
        helpm = wx.Menu()
        menubar.Append(filem, '&文件')
        menubar.Append(editm, '&編輯')
        menubar.Append(helpm, '&幫助')
        self.SetMenuBar(menubar)
        # 沒有顯式的 sizer 定義
        wx.TextCtrl(self)

BoxSizer

該定位按行或者列來排列多個控件,同時也允許 Sizer 的嵌套,這時可以構造出非常復雜的布局。

box = wx.BoxSizer(integer orient)

參數 orient 代表方向:

  • wx.VERTICAL – 豎直
  • wx.HORIZONTAL – 水平
    box.Add(wx.Window window, integer proportion=0, integer flag=0, integer border=0)

參數 proportion 表示在給定的方向中,控件按照什么比例來調整大小:

  • 0 – 表示默認,不改變控件大小
  • 1 – 表示控件以1倍調整大小
  • 大於1 – 表示控件以1的N倍調整大小

參數 flag 更具體的定義控件在 wx.BoxSizer 中的行為,通過它可以控制控件之間的距離,因而需要對不同方向的邊界進行定義,不同方向之間可以通過豎線符號 | 組合,可選的方向為:

  • wx.LEFT – 左
  • wx.RIGHT – 右
  • wx.BOTTOM – 底部
  • wx.TOP – 頂部
  • wx.ALL – 周圍

如果使用 wx.EXPAND 標記,控件將使用所有剩余的空間。同樣也可以定義控件的對齊方式,可選以下選項:

  • wx.ALIGN_LEFT – 左對齊
  • wx.ALIGN_RIGHT – 右對齊
  • wx.ALIGN_TOP – 頂部對齊
  • wx.ALIGN_BOTTOM – 底部對齊
  • wx.ALIGN_CENTER_VERTICAL – 豎直居中對齊
  • wx.ALIGN_CENTER_HORIZONTAL – 水平居中對齊
  • wx.ALIGN_CENTER – 居中對齊
Demo 0

wxpython_boxsizer

class Example(wx.Frame):
    """在 Panel(面板)四周設置一些空間"""
    def __init__(self, parent):
        super(Example, self).__init__(parent, title='wx.BoxSizer', size=(260, 180))
        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):
        panel = wx.Panel(self)
        panel.SetBackgroundColour('#4f5049')
        vbox = wx.BoxSizer(wx.VERTICAL)
        midPan = wx.Panel(panel)
        midPan.SetBackgroundColour('#ededed')
        # 使用 wx.EXPAND 標記,控件將使用所有剩余的空間
        vbox.Add(midPan, 1, wx.EXPAND | wx.ALL, 20)
        panel.SetSizer(vbox)
Demo 1

wxpython_boxsizer_1

class Example(wx.Frame):
    """創建豎直的 Sizer,並將5個水平 Sizer 放置其中"""
    def __init__(self, parent):
        super(Example, self).__init__(parent, title='wx.BoxSizer Pro', size=(390, 350))
        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):
        panel = wx.Panel(self)
        # 系統默認的字體大小是10,這里顯示會過大,將其設置為9
        font = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT)
        font.SetPointSize(9)
        vbox = wx.BoxSizer(wx.VERTICAL)
        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        st1 = wx.StaticText(panel, label='類名')
        st1.SetFont(font)
        hbox1.Add(st1, flag=wx.RIGHT, border=8)
        tc = wx.TextCtrl(panel)
        hbox1.Add(tc, proportion=1)
        vbox.Add(hbox1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border=10)
        vbox.Add((-1, 10))
        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        st2 = wx.StaticText(panel, label='匹配類')
        st2.SetFont(font)
        hbox2.Add(st2)
        vbox.Add(hbox2, flag=wx.LEFT | wx.TOP, border=10)
        vbox.Add((-1, 10))
        hbox3 = wx.BoxSizer(wx.HORIZONTAL)
        tc2 = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        hbox3.Add(tc2, proportion=1, flag=wx.EXPAND)
        # 雖然可以通過結合邊框相關的 flag 參數來控制控件之間的距離,但問題是 Add() 函數只允許設置一個邊框數值,
        # 這意味着只能給幾個方向一樣大小的邊框,這種方法是無法做到左右邊框設置為 10px,而底部設置為 25px 的情況
        vbox.Add(hbox3, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=10)
        # 如果需要不同的邊框值,可以增加額外的占位空間,如 vbox.Add((-1, 25)) 即是插入占位空間的語句,
        # (-1,25) 分別代表寬度和長度,如果某個數值為 -1 則表明不關注該方向
        vbox.Add((-1, 25))
        hbox4 = wx.BoxSizer(wx.HORIZONTAL)
        cb1 = wx.CheckBox(panel, label='區分大小寫')
        cb1.SetFont(font)
        hbox4.Add(cb1)
        cb2 = wx.CheckBox(panel, label='嵌套類')
        cb2.SetFont(font)
        hbox4.Add(cb2, flag=wx.LEFT, border=10)
        cb3 = wx.CheckBox(panel, label='非項目類')
        cb3.SetFont(font)
        hbox4.Add(cb3, flag=wx.LEFT, border=10)
        vbox.Add(hbox4, flag=wx.LEFT, border=10)
        vbox.Add((-1, 25))
        hbox5 = wx.BoxSizer(wx.HORIZONTAL)
        btn1 = wx.Button(panel, label='確定', size=(70, 30))
        hbox5.Add(btn1)
        btn2 = wx.Button(panel, label='關閉', size=(70, 30))
        hbox5.Add(btn2, flag=wx.LEFT | wx.BOTTOM, border=5)
        # 在窗口的右側放置了兩個 Button,實現這個需求要三個參數:proportion、align flag 和 wx.EXPAND 標記,
        # proportion 必須設置為 0 ,表示在通過鼠標調整窗口大小時,Button 不允許更改大小,
        # 一定不能設置 wx.EXPAND 標記,因為 Button 只允許出現在被分配的位置上,
        # 最后必須設置 wx.ALIGN_RIGHT 標記,水平 Sizer 中的右對齊可以滿足要求
        vbox.Add(hbox5, flag=wx.ALIGN_RIGHT | wx.RIGHT, border=10)
        panel.SetSizer(vbox)

GridSizer

該定位即網格布局,它可以在兩維的表格中放置控件。

wxpython_gridsizer

class Example(wx.Frame):
    # 創建一個計算器的框架
    def __init__(self, parent):
        super(Example, self).__init__(parent, title='wx.GridSizer', size=(300, 250))
        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):
        vbox = wx.BoxSizer(wx.VERTICAL)
        self.display = wx.TextCtrl(self, style=wx.TE_RIGHT)
        vbox.Add(self.display, flag=wx.EXPAND | wx.TOP | wx.BOTTOM, border=4)
        # 網格布局的構造函數中,我們可以定義表格的行列數,以及單元格之間的橫豎間距
        # wx.GridSizer(int rows=1, int cols=0, int vgap=0, int hgap=0)
        gs = wx.GridSizer(5, 4, 5, 5)
        # 使用 AddMany() 方法,便於一次性插入多個控件
        gs.AddMany([(wx.Button(self, label='Cls'), 0, wx.EXPAND),
                    (wx.Button(self, label='Bck'), 0, wx.EXPAND),
                    # 在 Bck 和 Close 兩個按鈕之間放了一個空的 wx.StaticText,來達到分隔的目的
                    (wx.StaticText(self), wx.EXPAND),
                    (wx.Button(self, label='Close'), 0, wx.EXPAND),
                    (wx.Button(self, label='7'), 0, wx.EXPAND),
                    (wx.Button(self, label='8'), 0, wx.EXPAND),
                    (wx.Button(self, label='9'), 0, wx.EXPAND),
                    (wx.Button(self, label='/'), 0, wx.EXPAND),
                    (wx.Button(self, label='4'), 0, wx.EXPAND),
                    (wx.Button(self, label='5'), 0, wx.EXPAND),
                    (wx.Button(self, label='6'), 0, wx.EXPAND),
                    (wx.Button(self, label='*'), 0, wx.EXPAND),
                    (wx.Button(self, label='1'), 0, wx.EXPAND),
                    (wx.Button(self, label='2'), 0, wx.EXPAND),
                    (wx.Button(self, label='3'), 0, wx.EXPAND),
                    (wx.Button(self, label='-'), 0, wx.EXPAND),
                    (wx.Button(self, label='0'), 0, wx.EXPAND),
                    (wx.Button(self, label='.'), 0, wx.EXPAND),
                    (wx.Button(self, label='='), 0, wx.EXPAND),
                    (wx.Button(self, label='+'), 0, wx.EXPAND)])
        vbox.Add(gs, proportion=1, flag=wx.EXPAND)
        self.SetSizer(vbox)

FlexGridSizer

該定位與網格布局(wx.GridSizer)類似,同樣以兩維的表格方式放置控件,但 wx.FlexGridSizer 更靈活一些。wx.GridSizer 的單元格大小都一樣,wx.FlexGridSizer 的單元格僅限制每行的單元格高度一致、每列的單元格寬度一致,不需要所有行列的寬高一致。

wxpython_flexgridsizer

class Example(wx.Frame):
    """創建一個評論窗口"""
    def __init__(self, parent):
        super(Example, self).__init__(parent, title='wx.FlexGridSizer', size=(300, 250))
        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):
        panel = wx.Panel(self)
        # 創建一個水平的 Sizer
        hbox = wx.BoxSizer(wx.HORIZONTAL)
        # wx.FlexGridSizer(int rows=1, int cols=0, int vgap=0, int hgap=0)
        # rows 和 cols 定義行數和列數,vgap 和 hgap 定義兩個方向的控件的間距
        fgs = wx.FlexGridSizer(3, 2, 9, 25)
        title = wx.StaticText(panel, label="標題")
        author = wx.StaticText(panel, label="作者")
        review = wx.StaticText(panel, label="評論")
        tc1 = wx.TextCtrl(panel)
        tc2 = wx.TextCtrl(panel)
        tc3 = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        # 使用 AddMany() 添加控件到 Sizer 中,wx.FlexGridSizer 和 wx.GridSizer 都有這個方法
        fgs.AddMany(
            [(title), (tc1, 1, wx.EXPAND), (author), (tc2, 1, wx.EXPAND), (review, 1, wx.EXPAND), (tc3, 1, wx.EXPAND)])
        # 讓第三行和第二列為可增長的,這使得窗口變化大小時,TextCtrl 也會跟着增長,
        # 前兩個 TextCtrl 的寬度會增長,第三個會在兩個方向都增長(注意:需要添加 wx.EXPAND 標記)
        fgs.AddGrowableRow(2, 1)
        fgs.AddGrowableCol(1, 1)
        # 在控件表格周圍放置 15px 的空間
        hbox.Add(fgs, proportion=1, flag=wx.ALL | wx.EXPAND, border=15)
        panel.SetSizer(hbox)

GridBagSizer

該定位是 Sizer 布局中最復雜的,可實現精確定位,還可以跨行或者跨列。

wx.GridBagSizer(integer vgap, integer hgap)

豎直和水平的 gap 參數定義了所有子控件之間的間隔,使用 Add() 添加元素。

Add(self, item, tuple pos, tuple span=wx.DefaultSpan, integer flag=0, integer border=0, userData=None)
  • pos – 定義了位置,左上角的位置為 (0,0)
  • span – 表示跨幾行或者列,比如 (3,2) 表示讓一個控件跨3行和2列
  • flag – 更具體的定義控件在 Sizer 中的行為(參考 BoxSizer)
  • border – 在控件周圍的空間
    AddGrowableRow(integer row)
    AddGrowableCol(integer col)

在窗口大小改變時,Grid 中的控件可以保持大小不變,也可以隨窗口改變,如果想讓它增長或者收縮,可以使用上面的兩個方法。

Demo 0

wxpython_gridbagsizer_0

class Example(wx.Frame):
    """創建一個大的 Grid 表"""
    def __init__(self, parent):
        super(Example, self).__init__(parent, title='wx.GridBagSizer', size=(320, 130))
        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):
        panel = wx.Panel(self)
        sizer = wx.GridBagSizer(4, 4)
        # "重命名為" 文本將被放置在左上角,所以設置了 (0,0) 位置,另外在頂部、左邊和底部增加了 5px 的間隔空間
        text = wx.StaticText(panel, label="重命名為")
        sizer.Add(text, pos=(0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)
        # wx.TextCtrl 從第二行開始,從0開始計數,它占據了1行和5列:(1,5),放置了 5px 的左右邊框空間
        tc = wx.TextCtrl(panel)
        sizer.Add(tc, pos=(1, 0), span=(1, 5), flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5)
        buttonOk = wx.Button(panel, label="Ok", size=(90, 28))
        buttonClose = wx.Button(panel, label="Close", size=(90, 28))
        # 在第四行放置了2個 Button,第三行是空的,所以 wx.TextCtrl 和 Button 之間留有間隔,
        # 把 OK 按鈕放在第四列,close 按鈕放在第五列。需要注意,一旦給一個控件應用了邊框,整行都會受到影響,
        # 這是沒有為 OK 按鈕設置底部邊框空間的原因。因為在 wx.GridBagSizer 的構造函數中,已經設置了所有控件之間的間隔,
        # 所以在兩個按鈕之間沒有放置任何空間。
        sizer.Add(buttonOk, pos=(3, 3))
        sizer.Add(buttonClose, pos=(3, 4), flag=wx.RIGHT | wx.BOTTOM, border=5)
        # 最后需要讓對話框可增長,讓第二列和第三行可增長,現在可以放大或者縮小窗口,注釋掉則不能自動縮放
        sizer.AddGrowableCol(1)
        sizer.AddGrowableRow(2)
        panel.SetSizerAndFit(sizer)
Demo 1

wxpython_gridbagsizer_1

class Example(wx.Frame):
    """創建一個更復雜的布局,同時使用了 wx.GridBagSizer 和 wx.StaticBoxSizer"""
    def __init__(self, parent):
        super(Example, self).__init__(parent, title='wx.GridBagSizer Pro', size=(450, 350))
        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):
        panel = wx.Panel(self)
        sizer = wx.GridBagSizer(5, 5)
        text1 = wx.StaticText(panel, label="Java 類")
        sizer.Add(text1, pos=(0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=15)
        # 在第一行右側放了一個 wx.StaticBitmap
        icon = wx.StaticBitmap(panel, bitmap=wx.Bitmap('exec.png'))
        sizer.Add(icon, pos=(0, 4), flag=wx.TOP | wx.RIGHT | wx.ALIGN_RIGHT, border=5)
        # 創建一條分隔線,來分隔布局中不同組的控件
        line = wx.StaticLine(panel)
        sizer.Add(line, pos=(1, 0), span=(1, 5), flag=wx.EXPAND | wx.BOTTOM, border=10)
        text2 = wx.StaticText(panel, label="名稱")
        sizer.Add(text2, pos=(2, 0), flag=wx.LEFT, border=10)
        tc1 = wx.TextCtrl(panel)
        sizer.Add(tc1, pos=(2, 1), span=(1, 3), flag=wx.TOP | wx.EXPAND)
        text3 = wx.StaticText(panel, label="")
        sizer.Add(text3, pos=(3, 0), flag=wx.LEFT | wx.TOP, border=10)
        tc2 = wx.TextCtrl(panel)
        sizer.Add(tc2, pos=(3, 1), span=(1, 3), flag=wx.TOP | wx.EXPAND, border=5)
        button1 = wx.Button(panel, label="瀏覽...")
        sizer.Add(button1, pos=(3, 4), flag=wx.TOP | wx.RIGHT, border=5)
        text4 = wx.StaticText(panel, label="繼承")
        sizer.Add(text4, pos=(4, 0), flag=wx.TOP | wx.LEFT, border=10)
        combo = wx.ComboBox(panel)
        sizer.Add(combo, pos=(4, 1), span=(1, 3), flag=wx.TOP | wx.EXPAND, border=5)
        button2 = wx.Button(panel, label="瀏覽...")
        sizer.Add(button2, pos=(4, 4), flag=wx.TOP | wx.RIGHT, border=5)
        # wxStaticBoxSizer 和 wx.BoxSizer 類似,但它在 Sizer 周圍添加了一個靜態的盒子,在盒子中放入了 Check 選項
        sb = wx.StaticBox(panel, label="可選屬性")
        boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
        boxsizer.Add(wx.CheckBox(panel, label="公有"), flag=wx.LEFT | wx.TOP, border=5)
        boxsizer.Add(wx.CheckBox(panel, label="生成默認構造函數"), flag=wx.LEFT, border=5)
        boxsizer.Add(wx.CheckBox(panel, label="生成 Main 方法"), flag=wx.LEFT | wx.BOTTOM, border=5)
        sizer.Add(boxsizer, pos=(5, 0), span=(1, 5), flag=wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border=10)
        button3 = wx.Button(panel, label='幫助')
        sizer.Add(button3, pos=(7, 0), flag=wx.LEFT, border=10)
        button4 = wx.Button(panel, label="確定")
        sizer.Add(button4, pos=(7, 3))
        button5 = wx.Button(panel, label="取消")
        sizer.Add(button5, pos=(7, 4), span=(1, 1), flag=wx.BOTTOM | wx.RIGHT, border=5)
        sizer.AddGrowableCol(2)
        panel.SetSizer(sizer)

控件

Button

該控件僅包含一個文本字符串,用來觸發某個動作。

wxpython_button

class Example(wx.Frame):
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        pnl = wx.Panel(self)
        # 創建一個 Close 按鍵,點擊 Close 即可關閉應用
        cbtn = wx.Button(pnl, label='Close', pos=(20, 30))
        # 按鈕的文本標簽以及它在面板上的位置
        cbtn.Bind(wx.EVT_BUTTON, self.OnClose)
        self.SetSize((250, 200))
        self.SetTitle('wx.Button')
        self.Centre()
        self.Show(True)

    def OnClose(self, e):
        # 調用 Close() 函數來關閉應用
        self.Close(True)

ToggleButton

該控件也是一種按鈕,但它有兩個狀態:點擊和非點擊狀態。通過點擊按鍵可以在兩種狀態中切換,在特定場景中,這一功能將非常適用。

wxpython_togglebutton

class Example(wx.Frame):
    """
    創建了紅色、綠色和藍色的 Toggle button 和一個 Panel,
    點擊 toggle button的時候,可以改變 Panel 的顏色。
    """
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        pnl = wx.Panel(self)
        self.col = wx.Colour(0, 0, 0)
        # 創建一個 wx.ToggleButton 控件
        rtb = wx.ToggleButton(pnl, label='red', pos=(20, 25))
        gtb = wx.ToggleButton(pnl, label='green', pos=(20, 60))
        btb = wx.ToggleButton(pnl, label='blue', pos=(20, 100))
        # 創建一個 Panel,顏色設置為 self.col
        self.cpnl = wx.Panel(pnl, pos=(150, 20), size=(110, 110))
        self.cpnl.SetBackgroundColour(self.col)
        # 點擊 rtb 觸發這個 button 的時候 ToggleRed() 會被調用
        rtb.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleRed)
        gtb.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleGreen)
        btb.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleBlue)
        self.SetSize((300, 200))
        self.SetTitle('Toggle buttons')
        self.Centre()
        self.Show(True)

    def ToggleRed(self, e):
        """對 rtb 按鈕是否被按下做出反應,來改變特定面板的顏色"""
        obj = e.GetEventObject()
        isPressed = obj.GetValue()
        green = self.col.Green()
        blue = self.col.Blue()
        if isPressed:
            self.col.Set(255, green, blue)
        else:
            self.col.Set(0, green, blue)
        self.cpnl.SetBackgroundColour(self.col)
        self.cpnl.Refresh()

    def ToggleGreen(self, e):
        obj = e.GetEventObject()
        isPressed = obj.GetValue()
        red = self.col.Red()
        blue = self.col.Blue()
        if isPressed:
            self.col.Set(red, 255, blue)
        else:
            self.col.Set(red, 0, blue)
        self.cpnl.SetBackgroundColour(self.col)
        self.cpnl.Refresh()

    def ToggleBlue(self, e):
        obj = e.GetEventObject()
        isPressed = obj.GetValue()
        red = self.col.Red()
        green = self.col.Green()
        if isPressed:
            self.col.Set(red, green, 255)
        else:
            self.col.Set(red, green, 0)
        self.cpnl.SetBackgroundColour(self.col)
        self.cpnl.Refresh()

StaticLine

該控件在窗口上展示一個簡單的直線,可以是豎直或水平的。

wxpython_staticline

class Example(wx.Frame):
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)
        heading = wx.StaticText(self, label='The Central Europe', pos=(130, 15))
        heading.SetFont(font)
        wx.StaticLine(self, pos=(25, 50), size=(300, 1))
        wx.StaticText(self, label='Slovakia', pos=(25, 80))
        wx.StaticText(self, label='Hungary', pos=(25, 100))
        wx.StaticText(self, label='Poland', pos=(25, 120))
        wx.StaticText(self, label='5 445 000', pos=(250, 80))
        wx.StaticText(self, label='10 014 000', pos=(250, 100))
        wx.StaticText(self, label='38 186 000', pos=(250, 120))
        wx.StaticLine(self, pos=(25, 160), size=(300, 1))
        tsum = wx.StaticText(self, label='164 336 000', pos=(240, 180))
        sum_font = tsum.GetFont()
        sum_font.SetWeight(wx.BOLD)
        tsum.SetFont(sum_font)
        btn = wx.Button(self, label='Close', pos=(140, 210))
        btn.Bind(wx.EVT_BUTTON, self.OnClose)
        self.SetSize((360, 280))
        self.SetTitle('wx.StaticLine')
        self.Centre()
        self.Show(True)

    def OnClose(self, e):
        self.Close(True)

StaticText

該控件在窗口上展示展示一行或多行的只讀文本。

wxpython_statictext

class Example(wx.Frame):
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        # 要在 wx.StaticText 展示的字符串
        txt1 = '''第一段第1行
第一段第2行 體現居中效果
第一段第3行'''
        txt2 = '''第二段第1行
第二段第2行
第二段第3行 體現居中效果'''
        pnl = wx.Panel(self)
        vbox = wx.BoxSizer(wx.VERTICAL)
        # 創建 wx.StaticText 控件,文字居中展示
        st1 = wx.StaticText(pnl, label=txt1, style=wx.ALIGN_CENTRE)
        st2 = wx.StaticText(pnl, label=txt2, style=wx.ALIGN_CENTRE)
        vbox.Add(st1, flag=wx.ALL, border=5)
        vbox.Add(st2, flag=wx.ALL, border=5)
        pnl.SetSizer(vbox)
        self.SetSize((220, 180))
        self.SetTitle('wx.StaticText')
        self.Centre()
        self.Show(True)

StaticBox

該控件是一個裝飾控件,被用來邏輯上將一組控件包括起來。必須在它所包含的控件創建之前創建,且那些被包含的控件是 wx.StaticBox 的兄弟控件而非子控件。

wxpython_staticbox

class Example(wx.Frame):
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        pnl = wx.Panel(self)
        wx.StaticBox(pnl, label='個人信息', pos=(5, 5), size=(240, 170))
        wx.CheckBox(pnl, label='', pos=(15, 30))
        wx.CheckBox(pnl, label='已婚', pos=(15, 55))
        wx.StaticText(pnl, label='年齡', pos=(15, 95))
        wx.SpinCtrl(pnl, value='1', pos=(55, 90), size=(60, -1), min=1, max=120)
        btn = wx.Button(pnl, label='Ok', pos=(90, 185), size=(60, -1))
        btn.Bind(wx.EVT_BUTTON, self.OnClose)
        self.SetSize((270, 250))
        self.SetTitle('Static box')
        self.Centre()
        self.Show(True)

    def OnClose(self, e):
        self.Close(True)

ComboBox

該控件是由一行文本域、一個帶有下拉箭頭圖標的按鈕和一個列表框所構成的。當你按下按鈕時,將出現一個列表框,用戶只可選擇其中的一個選項。

wxpython_combobox

class Example(wx.Frame):
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        pnl = wx.Panel(self)
        # 被選擇的選項將會顯示在文本標簽上
        distros = ['Ubuntu', 'Arch', 'Fedora', 'Debian', 'Mint']
        # 單選框將包含以上列表的字符串
        # 創建 wx.ComboBox,通過 choices 參數傳入一個字符串列表,wx.CB_READONLY 使得列表的字符串只讀,即不可編輯
        cb = wx.ComboBox(pnl, pos=(50, 30), choices=distros, style=wx.CB_READONLY)
        self.st = wx.StaticText(pnl, label='', pos=(50, 140))
        # 當從單選框選擇一個選項時,wx.EVT_COMBOBOX 事件將被觸發,綁定 OnSelect() 來處理該事件
        cb.Bind(wx.EVT_COMBOBOX, self.OnSelect)
        self.SetSize((250, 230))
        self.SetTitle('wx.ComboBox')
        self.Centre()
        self.Show(True)

    def OnSelect(self, e):
        i = e.GetString()
        self.st.SetLabel(i)

CheckBox

該控件只有兩個狀態:打開或關閉,它有一個框和文本標簽組成,文本標簽可以設置為放在框的左邊或者右邊。當 wx.CheckBox 被選擇之后,框里將出現一個對號√。

wxpython_checkbox

class Example(wx.Frame):
    """通過一個 wx.CheckBox 控件來決定是否顯示或隱藏窗口的標題"""
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        pnl = wx.Panel(self)
        # wx.CheckBox 控件的構造函數
        cb = wx.CheckBox(pnl, label='顯示標題', pos=(20, 20))
        # 由於窗口的標題應該是被默認顯示的,所以通過 SetValue() 方法默認選擇 wx.CheckBox
        cb.SetValue(True)
        # 當點擊 wx.CheckBox 控件時,wx.EVT_CHECKBOX 事件將被觸發,將其綁定至事件處理器 ShowOrHideTitle() 函數
        cb.Bind(wx.EVT_CHECKBOX, self.ShowOrHideTitle)
        self.SetSize((270, 120))
        self.SetTitle('wx.CheckBox')
        self.Centre()
        self.Show(True)

    def ShowOrHideTitle(self, e):
        """通過 wx.CheckBox 的狀態來決定是否隱藏或顯示窗口的標題"""
        sender = e.GetEventObject()
        isChecked = sender.GetValue()
        if isChecked:
            self.SetTitle('wx.CheckBox')
        else:
            self.SetTitle('')

StatusBar

該控件展示應用的狀態信息,可以被分成不同的部分來展示不同的信息。也可以把其他控件插入到 wx.StatusBar 中,它可以作為對話框的替代選擇,預防對話框被濫用。可以通過兩種方式新建 wx.StatusBar,可以直接創建 wx.StatusBar 然后調用 SetStatusBar() 函數,也可以簡單的調用 CreateStatusBar() 函數即可,第二種方法創建了一個默認的 wx.StatusBar

wxpython_statusbar

class Example(wx.Frame):
    """
    創建 wx.Frame 和5個其他的控件,
    如果把鼠標懸停在控件上面,控件的名字將會被顯示在 wx.StatusBar 上
    """
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        pnl = wx.Panel(self)
        button = wx.Button(pnl, label='Button', pos=(20, 20))
        text = wx.CheckBox(pnl, label='CheckBox', pos=(20, 90))
        combo = wx.ComboBox(pnl, pos=(120, 22), choices=['Python', 'Ruby'])
        slider = wx.Slider(pnl, 5, 6, 1, 10, (120, 90), (110, -1))
        # 當鼠標進入到控件的區域時,EVT_ENTER_WINDOW 事件將被觸發
        pnl.Bind(wx.EVT_ENTER_WINDOW, self.OnWidgetEnter)
        button.Bind(wx.EVT_ENTER_WINDOW, self.OnWidgetEnter)
        text.Bind(wx.EVT_ENTER_WINDOW, self.OnWidgetEnter)
        combo.Bind(wx.EVT_ENTER_WINDOW, self.OnWidgetEnter)
        slider.Bind(wx.EVT_ENTER_WINDOW, self.OnWidgetEnter)
        self.sb = self.CreateStatusBar()
        self.SetSize((250, 230))
        self.SetTitle('wx.Statusbar')
        self.Centre()
        self.Show(True)

    def OnWidgetEnter(self, e):
        # 得到鼠標進入的控件的名字
        name = e.GetEventObject().GetClassName()
        # 使用 SetStatusText() 方法設置狀態欄的文字
        self.sb.SetStatusText(name + ' widget')
        e.Skip()

RadioButton

該控件讓用戶從一組選項中選擇一個唯一選項,通過對第一個 RadioButton 設置 wx.RB_GROUP 樣式標記,可以將緊隨其后的其他 RadioButton 囊括為一組,隨后的 RadioButton 如果也被設置了 wx.RB_GROUP 樣式標記,那表明將開始新的一組選擇框。

wxpython_radiobutton

class Example(wx.Frame):
    """創建一組3個 RadioButton,每個按鈕的狀態被顯示在狀態欄上"""
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        pnl = wx.Panel(self)
        # 創建3個 RadioButton,其中第一個被設置了 wx.RB_GROUP 樣式,表明接下來的 RadioButton 都是同一組
        self.rb1 = wx.RadioButton(pnl, label='Value A', pos=(10, 10), style=wx.RB_GROUP)
        self.rb2 = wx.RadioButton(pnl, label='Value B', pos=(10, 30))
        self.rb3 = wx.RadioButton(pnl, label='Value C', pos=(10, 50))
        # 將 wx.EVT_RADIOBUTTON 事件綁定至 SetVal() 事件處理函數上
        self.rb1.Bind(wx.EVT_RADIOBUTTON, self.SetVal)
        self.rb2.Bind(wx.EVT_RADIOBUTTON, self.SetVal)
        self.rb3.Bind(wx.EVT_RADIOBUTTON, self.SetVal)
        # 創建分三部分的 狀態欄,並根據對應 RadioButton 的狀態設置了初始文字
        self.sb = self.CreateStatusBar(3)
        self.sb.SetStatusText("True", 0)
        self.sb.SetStatusText("False", 1)
        self.sb.SetStatusText("False", 2)
        self.SetSize((210, 210))
        self.SetTitle('wx.RadioButton')
        self.Centre()
        self.Show(True)

    def SetVal(self, e):
        """對狀態欄的文本進行了更新"""
        state1 = str(self.rb1.GetValue())
        state2 = str(self.rb2.GetValue())
        state3 = str(self.rb3.GetValue())
        self.sb.SetStatusText(state1, 0)
        self.sb.SetStatusText(state2, 1)
        self.sb.SetStatusText(state3, 2)

Gauge

該控件用在時間較長的任務場景,用來顯示當前任務的狀態。

wxpython_gauge

TASK_RANGE = 50

class Example(wx.Frame):
    """創建一個 進度條(Gauge)和兩個按鈕,一個按鈕開始走進度條,一個按鈕停止走進度條。"""

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

    def InitUI(self):
        # 使用了 wx.Timer 來在特定的時間區間來執行代碼,我們將在定義好的時間來更新進度條
        self.timer = wx.Timer(self, 1)
        # count 變量用來決定目前任務已經完成的比例
        self.count = 0
        self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
        pnl = wx.Panel(self)
        vbox = wx.BoxSizer(wx.VERTICAL)
        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        hbox3 = wx.BoxSizer(wx.HORIZONTAL)
        # wx.Gauge 控件的構造函數,range 參數定義了該控件最大的整數區間
        self.gauge = wx.Gauge(pnl, range=TASK_RANGE, size=(250, 25))
        self.btn1 = wx.Button(pnl, wx.ID_OK)
        self.btn2 = wx.Button(pnl, wx.ID_STOP)
        self.text = wx.StaticText(pnl, label='Task to be done')
        self.Bind(wx.EVT_BUTTON, self.OnOk, self.btn1)
        self.Bind(wx.EVT_BUTTON, self.OnStop, self.btn2)
        hbox1.Add(self.gauge, proportion=1, flag=wx.ALIGN_CENTRE)
        hbox2.Add(self.btn1, proportion=1, flag=wx.RIGHT, border=10)
        hbox2.Add(self.btn2, proportion=1)
        hbox3.Add(self.text, proportion=1)
        vbox.Add((0, 30))
        vbox.Add(hbox1, flag=wx.ALIGN_CENTRE)
        vbox.Add((0, 20))
        vbox.Add(hbox2, proportion=1, flag=wx.ALIGN_CENTRE)
        vbox.Add(hbox3, proportion=1, flag=wx.ALIGN_CENTRE)
        pnl.SetSizer(vbox)
        self.SetSize((300, 200))
        self.SetTitle('wx.Gauge')
        self.Centre()
        self.Show(True)

    def OnOk(self, e):
        # 檢查 count 變量是否還在任務的整數區間內,如果不在,我們直接返回
        if self.count == TASK_RANGE:
            return
        # 如果還在,表明任務還在繼續,我們開始 timer 定時器並更新靜態文本
        self.timer.Start(100)
        self.text.SetLabel('Task in Progress')

    def OnStop(self, e):
        # 檢查各種條件
        if self.count == 0 or self.count == TASK_RANGE or not self.timer.IsRunning():
            return
        # 符合的話停止定時器並更新靜態文本
        self.timer.Stop()
        self.text.SetLabel('Task Interrupted')

    def OnTimer(self, e):
        """
        在 timer 開始后被周期調用,在該方法內,更新 count 參數和進度條部件,
        如果 count 等於 TASK_RANGE,停止 timer 並更新靜態文本
        """
        self.count = self.count + 1
        self.gauge.SetValue(self.count)
        if self.count == TASK_RANGE:
            self.timer.Stop()
            self.text.SetLabel('Task Completed')

Slider

該控件有一個簡單的操作柄,可以向前或向后滑動,可以使用它完成特定的任務。

wxpython_slider

class Example(wx.Frame):
    """在 Slider 中選擇的值將被顯示在下面的靜態文本中。"""
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        pnl = wx.Panel(self)
        # 創建了 wx.Slider,在構造函數中,提供了它的初始位置,以及最大、最小的滑動位置,還有設定了它的水平方向
        sld = wx.Slider(pnl, value=200, minValue=150, maxValue=500, pos=(20, 20), size=(250, -1),
                        style=wx.SL_HORIZONTAL)
        #  wx.EVT_SCROLL 事件被觸發的時候,將調用 OnSliderScroll() 函數
        sld.Bind(wx.EVT_SCROLL, self.OnSliderScroll)
        # 當前 Slider 的值將被顯示在下方的靜態文本中
        self.txt = wx.StaticText(pnl, label='200', pos=(20, 90))
        self.SetSize((290, 200))
        self.SetTitle('wx.Slider')
        self.Centre()
        self.Show(True)

    def OnSliderScroll(self, e):
        # 得到了事件的發送者並得到其當前被選擇的值
        obj = e.GetEventObject()
        val = obj.GetValue()
        # 將其值設置到靜態文本中
        self.txt.SetLabel(str(val))

SpinCtrl

該控件對一個值進行增加或減少,它有兩個按鈕,一個帶向上箭頭,一個帶向下箭頭。用戶可以直接輸入數值,也可以通過兩個箭頭來對數值進行上下增減。

wxpython_spinctrl

class Example(wx.Frame):
    """將華氏溫度轉變為攝氏度,使用 wx.SpinCtrl 控件供用戶來選擇華氏溫度的值。"""
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        wx.StaticText(self, label='將華氏度轉換為攝氏度', pos=(20, 20))
        wx.StaticText(self, label='華氏度: ', pos=(20, 80))
        wx.StaticText(self, label='攝氏度: ', pos=(20, 150))
        self.celsius = wx.StaticText(self, label='', pos=(150, 150))
        # 創建一個初始值為0的 wx.SpinCtrl 控件,並通過 SetRange() 方法設置了該控件的取值范圍
        self.sc = wx.SpinCtrl(self, value='0', pos=(150, 75), size=(60, -1))
        self.sc.SetRange(-459, 1000)
        btn = wx.Button(self, label='計算', pos=(70, 230))
        btn.SetFocus()
        cbtn = wx.Button(self, label='Close', pos=(185, 230))
        btn.Bind(wx.EVT_BUTTON, self.OnCompute)
        cbtn.Bind(wx.EVT_BUTTON, self.OnClose)
        self.SetSize((350, 310))
        self.SetTitle('wx.SpinCtrl')
        self.Centre()
        self.Show(True)

    def OnClose(self, e):
        self.Close(True)

    def OnCompute(self, e):
        """獲取用戶設定的華氏溫度值,並計算對應的攝氏溫度值,將其更新在靜態文本上。"""
        fahr = self.sc.GetValue()
        cels = round((fahr - 32) * 5 / 9.0, 2)
        self.celsius.SetLabel(str(cels))

ScrolledWindow

該控件用來設置窗口可視面積的大小,單位是像素,帶有縱向、橫向的滾動條。

在這里插入圖片描述

class Example(wx.Frame):
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        # 創建一個滾動條控件
        scroller = wx.ScrolledWindow(self, -1)
        # 設置滾動條控件的大小
        scroller.SetScrollbars(pixelsPerUnitX=1, pixelsPerUnitY=1, noUnitsX=1000, noUnitsY=800)
        pnl = wx.Panel(scroller)
        ms = wx.BoxSizer(wx.VERTICAL)
        pnl.SetSizer(ms)
        self.SetSize((270, 250))
        self.SetTitle('wx.ScrolledWindow')
        self.Centre()
        self.Show(True)

對話框

常用對話框類和函數封裝了常用對話框的需求,它們都是 模態 的,抓住了控制流,直到用戶關閉對話框。

MessageDialog

該對話框顯示單行或多行消息,並帶有 OKCancelYes 和 No 按鈕的選擇。在 Windows 下,可以顯示可選圖標,例如感嘆號或問號。

Demo 0

wxpython_messagedialog_0

dlg = wx.MessageDialog(None, '消息對話框內容', '標題信息', wx.OK)
dlg.ShowModal()
dlg.Destroy()
Demo 1

wxpython_messagedialog_1

dlg = wx.MessageDialog(None, '消息對話框內容', '標題信息', wx.YES_NO | wx.ICON_QUESTION)
if dlg.ShowModal() == wx.ID_YES:
    print('')
dlg.Destroy()

ColourDialog

該對話框向用戶顯示顏色選擇器,並返回顏色信息。

wxpython_colourdialog

dlg = wx.ColourDialog(self)
dlg.GetColourData().SetChooseFull(True)
if dlg.ShowModal() == wx.ID_OK:
    print(dlg.GetColourData().GetColour())
dlg.Destroy()

FontDialog

該對話框向用戶顯示字體選擇器,並返回字體和顏色信息。

wxpython_fontdialog

dlg = wx.FontDialog(self, wx.FontData())
if dlg.ShowModal() == wx.ID_OK:
    print(dlg.GetFontData().GetChosenFont())
dlg.Destroy()

FileDialog

該對話框向用戶彈出文件選擇器框,在 Windows 和 GTK 2.4+ 上,這是公共文件選擇器對話框,在 MacOS 中,這是一個文件選擇器框,功能有所減少。

wxpython_filedialog_0

Demo 0
filesFilter = "Dicom (*.dcm)|*.dcm|" "All files (*.*)|*.*"
dlg = wx.FileDialog(self, message="選擇單個文件", wildcard=filesFilter, style=wx.FD_OPEN)
if dlg.ShowModal() == wx.ID_OK:
    print(dlg.GetPath())
dlg.Destroy()

Demo 1

filesFilter = "Dicom (*.dcm)|*.dcm|" "All files (*.*)|*.*"
dlg = wx.FileDialog(self, message="多文件選擇", wildcard=filesFilter, style=wx.FD_OPEN | wx.FD_MULTIPLE)
if dlg.ShowModal() == wx.ID_OK:
    print(dlg.GetPaths())
dlg.Destroy()

Demo 2

filesFilter = "Dicom (*.dcm)|*.dcm|" "All files (*.*)|*.*"
dlg = wx.FileDialog(self, message="保存文件", wildcard=filesFilter, style=wx.FD_SAVE)
if dlg.ShowModal() == wx.ID_OK:
    print(dlg.GetPath())
dlg.Destroy()

DirDialog

該對話框向用戶顯示一個目錄選擇器對話框,允許用戶選擇一個目錄。

wxpython_dirdialog

dlg = wx.DirDialog(None, "選擇一個目錄:", style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
if dlg.ShowModal() == wx.ID_OK:
    print(dlg.GetPath())
dlg.Destroy()

TextEntryDialog

該對話框是一個帶有文本輸入字段的對話框,使用 wx.TextEntryDialog.GetValue() 獲得用戶輸入的值。

wxpython_textentrydialog

dlg = wx.TextEntryDialog(None, "請在下面文本框中輸入內容:", "文本輸入框標題", "默認內容")
if dlg.ShowModal() == wx.ID_OK:
    print(dlg.GetValue())
dlg.Destroy()

PasswordEntryDialog

該對話框是是一個帶有密碼輸入字段的對話框,使用 wx.TextEntryDialog.GetValue() 獲得用戶輸入的值。

wxpython_passwordentrydialog

dlg = wx.PasswordEntryDialog(None, "請輸入密碼:", "密碼輸入框標題", "默認密碼")
if dlg.ShowModal() == wx.ID_OK:
    print(dlg.GetValue())
dlg.Destroy()

SingleChoiceDialog

該對話框顯示選項列表,以及 OK 和(可選)Cancel,用戶可以選擇其中之一,可以從對話框中獲得索引,字符串或客戶數據的選擇。

wxpython_singlechoicedialog

dlg = wx.SingleChoiceDialog(None, "請選擇你喜歡的水果:", "列表選擇框標題", ["蘋果", "西瓜", "草莓"])
if dlg.ShowModal() == wx.ID_OK:
    print(dlg.GetStringSelection())
dlg.Destroy()

MultiChoiceDialog

該對話框顯示選項列表,以及 OK 和(可選)Cancel,用戶可以選擇其中一個或多個。

wxpython_multichoicedialog

dlg = wx.MultiChoiceDialog(None, "請選擇幾種你喜歡的水果:", "列表多選框標題", ["蘋果", "西瓜", "草莓"])
if dlg.ShowModal() == wx.ID_OK:
    print(dlg.GetSelections())
dlg.Destroy()

表格

使用 Grid 及其相關類可以顯示和編輯表格數據,而且支持表單元格的自定義屬性,從而可以完全自定義其外觀,並使用單獨的網格表(GridTableBase 派生)類進行數據管理,這意味着它可用於顯示任意數量的數據。

wxpython_grid

import wx
import wx.grid

class GridFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent)
        # 創建一個 wxGrid 對象
        grid = wx.grid.Grid(self, -1)
        # 調用 CreateGrid 設置網格的尺寸(在此示例中為50行和8列)
        grid.CreateGrid(100, 10)
        # 設置單個行和列的大小(以像素為單位)
        grid.SetRowSize(0, 60)
        grid.SetColSize(0, 120)
        # 將網格單元格內容設置為字符串
        grid.SetCellValue(0, 0, 'wxGrid很好')
        # 指定某些單元格為只讀
        grid.SetCellValue(0, 3, '這是只讀的')
        grid.SetReadOnly(0, 3)
        # 為網格單元格內容指定顏色
        grid.SetCellValue(3, 3, '灰綠色')
        grid.SetCellTextColour(3, 3, wx.GREEN)
        grid.SetCellBackgroundColour(3, 3, wx.LIGHT_GREY)
        # 指定一些單元格將存儲數字值而不是字符串,
        # 在這里,將網格列5設置為保留以6的寬度和2的精度顯示的浮點值
        grid.SetColFormatFloat(5, 6, 2)
        grid.SetCellValue(0, 6, '3.1415')
        self.Show()

if __name__ == '__main__':
    app = wx.App(0)
    frame = GridFrame(None)
    app.MainLoop()
View Code

菜單

菜單是 GUI 應用中的通用部件,菜單欄由多項菜單組成,頂級菜單在菜單欄上顯示標簽,菜單包含菜單項,菜單項在應用中執行特定的命令,菜單也可以包含子菜單,子菜單自身又包含菜單項。

圖標與快捷鍵

wxpython_menuitem

class Example(wx.Frame):
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs)
        self.InitUI()

    def InitUI(self):
        # 新建一個 MenuBar 對象
        menubar = wx.MenuBar()
        # 新建一個 Menu 對象
        fileMenu = wx.Menu()
        # 創建一個 wx.MenuItem 對象,"&" 符號申明了快捷鍵,但是真正的快捷鍵由 "\t" 后面的字母組合定義,
        # 這里定義了 Ctrl+Q,如果用戶按下這一快捷鍵,應用就會退出
        qmi = wx.MenuItem(fileMenu, id=1, text='&退出\tCtrl+Q')
        # 使用 SetBitmap() 函數,為菜單項提供圖標
        qmi.SetBitmap(wx.Bitmap('exit.png'))
        # AppendItem 則將菜單項添加到菜單中
        fileMenu.Append(qmi)
        # 綁定了菜單項的 wx.EVT_MENU 事件到自定義的 OnQuit() 函數(這里通過 id 來綁定,也可以通過菜單項對象來綁定)
        self.Bind(wx.EVT_MENU, self.OnQuit, id=1)
        # 將菜單加入到菜單欄中,"&" 符號創建了一個快捷鍵
        menubar.Append(fileMenu, '&文件')
        # 調用 SetMenuBar() 方法,這一方法屬於 wx.Frame,它為 Frame 設定菜單欄
        self.SetMenuBar(menubar)
        self.SetSize((250, 200))
        self.SetTitle('圖標和快捷鍵')
        self.Centre()
        self.Show(True)

    def OnQuit(self, e):
        self.Close()

子菜單與分隔符

每個菜單可以包含子菜單,這樣可以把相似的命令放到同一組中,還可以通過分隔符來分割不同的命令,其實就是簡單的一條線。

wxpython_appendsubmenu

class Example(wx.Frame):
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs)
        self.InitUI()

    def InitUI(self):
        menubar = wx.MenuBar()
        fileMenu = wx.Menu()
        # 創建 新建 菜單項
        new = wx.MenuItem(fileMenu, wx.ID_NEW, '&新建\tCtrl+N')
        new.SetBitmap(wx.Bitmap('folder_new.png'))
        fileMenu.Append(new)
        # 創建 打開 菜單項
        open = wx.MenuItem(fileMenu, wx.ID_OPEN, '&打開\tCtrl+O')
        open.SetBitmap(wx.Bitmap('fileopen.png'))
        fileMenu.Append(open)
        # 創建 保存 菜單項
        save = wx.MenuItem(fileMenu, wx.ID_SAVE, '&保存\tCtrl+S')
        save.SetBitmap(wx.Bitmap('save_all.png'))
        fileMenu.Append(save)
        # AppendSeparator() 函數添加了分隔符
        fileMenu.AppendSeparator()
        # 子菜單同樣也是 wx.Menu 對象,三個菜單項被添加到該菜單對象
        imp = wx.Menu()
        # wx.ID_ANY 是獲取id的一種方法
        imp.Append(wx.ID_ANY, '導入RSS源列表...')
        imp.Append(wx.ID_ANY, '導入書簽...')
        imp.Append(wx.ID_ANY, '導入郵件...')
        # 子菜單通過 AppendSubMenu() 方法被添加到文件菜單中
        fileMenu.AppendSubMenu(imp, '導入')
        qmi = wx.MenuItem(fileMenu, wx.ID_EXIT, '&退出\tCtrl+Q')
        qmi.SetBitmap(wx.Bitmap('exit.png'))
        fileMenu.Append(qmi)
        self.Bind(wx.EVT_MENU, self.OnQuit, qmi)
        menubar.Append(fileMenu, '&文件')
        self.SetMenuBar(menubar)
        self.SetSize((350, 250))
        self.SetTitle('子菜單和分隔符')
        self.Centre()
        self.Show(True)

    def OnQuit(self, e):
        self.Close()

Check菜單項

wxpython_checkmenu

class Example(wx.Frame):
    """創建一個view菜單,它包括兩個 Check 菜單項,這兩個菜單項可以控制顯示或隱藏狀態欄和工具欄"""
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs)
        self.InitUI()

    def InitUI(self):
        menubar = wx.MenuBar()
        fileMenu = wx.Menu()
        viewMenu = wx.Menu()
        # 如果要添加一個 Check 菜單項,可以設定 kind 參數為 wx.ITEM_CHECK,該參數默認為 wx.ITEM_NORMAL,
        # Append()方法返回一個 wx.MenuItem
        self.shst = viewMenu.Append(wx.ID_ANY, '顯示狀態欄', '幫助:顯示狀態欄', kind=wx.ITEM_CHECK)
        self.shtl = viewMenu.Append(wx.ID_ANY, '顯示工具欄', '幫助:顯示工具欄', kind=wx.ITEM_CHECK)
        # 當應用開始的時候,狀態欄和工具欄都應可見,所以使用 Check() 方法勾選 Check 菜單項
        viewMenu.Check(self.shst.GetId(), True)
        viewMenu.Check(self.shtl.GetId(), True)
        self.Bind(wx.EVT_MENU, self.ToggleStatusBar, self.shst)
        self.Bind(wx.EVT_MENU, self.ToggleToolBar, self.shtl)
        menubar.Append(fileMenu, '&文件')
        menubar.Append(viewMenu, '&視圖')
        self.SetMenuBar(menubar)
        self.toolbar = self.CreateToolBar()
        self.toolbar.AddTool(1, '', wx.Bitmap('folder_new.png'))
        self.toolbar.Realize()
        self.statusbar = self.CreateStatusBar()
        self.statusbar.SetStatusText('狀態欄')
        self.SetSize((350, 250))
        self.SetTitle('Check菜單項')
        self.Centre()
        self.Show(True)

    def ToggleStatusBar(self, e):
        """通過 Check 菜單項的狀態來顯示或隱藏狀態欄"""
        # 通過 ISChecked() 函數來獲取check菜單項的狀態
        if self.shst.IsChecked():
            self.statusbar.Show()
        else:
            self.statusbar.Hide()

    def ToggleToolBar(self, e):
        if self.shtl.IsChecked():
            self.toolbar.Show()
        else:
            self.toolbar.Hide()

Radio菜單項

在這里插入圖片描述

class Example(wx.Frame):
    """創建一個view菜單,它包括兩個 Radio 菜單項,並只能選擇其中一個"""
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs)
        self.InitUI()

    def InitUI(self):
        menubar = wx.MenuBar()
        viewMenu = wx.Menu()
        # 如果要添加一個 Radio 菜單項,可以設定 kind 參數為 wx.ITEM_RADIO,該參數默認為 wx.ITEM_NORMAL
        self.shst = viewMenu.Append(wx.ID_ANY, '夜間視圖', kind=wx.ITEM_RADIO)
        self.shtl = viewMenu.Append(wx.ID_ANY, '日間視圖', kind=wx.ITEM_RADIO)
        menubar.Append(viewMenu, '&視圖')
        self.SetMenuBar(menubar)
        self.SetSize((350, 250))
        self.SetTitle('Radio菜單項')
        self.Centre()
        self.Show(True)

上下文菜單

wxpython_mypopupmenu

class MyPopupMenu(wx.Menu):
    """為主窗口創建上下文菜單,有兩個菜單項,一個用來最小化應用,另一個結束應用"""
    def __init__(self, parent):
        # 創建一個單獨的類叫做MyPopupMenu,它繼承自wx.Menu
        super(MyPopupMenu, self).__init__()
        self.parent = parent
        # 創建菜單項、添加到上下文菜單並綁定了事件處理函數
        mmi = wx.MenuItem(self, wx.NewIdRef(), '最小化')
        self.Append(mmi)
        self.Bind(wx.EVT_MENU, self.OnMinimize, mmi)
        cmi = wx.MenuItem(self, wx.NewIdRef(), '關閉')
        self.Append(cmi)
        self.Bind(wx.EVT_MENU, self.OnClose, cmi)

    def OnMinimize(self, e):
        self.parent.Iconize()

    def OnClose(self, e):
        self.parent.Close()


class Example(wx.Frame):
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs)
        self.InitUI()

    def InitUI(self):
        # 如果用戶在 Frame 中點擊右鍵,將調用 OnRightDown() 方法,這是通過綁定 wx.EVT_RIGHT_DOWN 事件來實現的
        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
        self.SetSize((250, 200))
        self.SetTitle('上下文菜單')
        self.Centre()
        self.Show(True)

    def OnRightDown(self, e):
        # 調用了 PopupMenu() 方法,這個方法來自於 wx.Frame,第一個參數是要顯示的菜單,第二個參數為顯示的位置,
        # 為了讓上下文菜單顯示在鼠標光標處,這里需要得到鼠標位置,事件對象的 GetPosition() 方法可以得到這一信息
        self.PopupMenu(MyPopupMenu(self), e.GetPosition())

工具欄

單行工具欄

在這里插入圖片描述

class Example(wx.Frame):
    """創建一個工具的工具欄,當用戶點擊這一工具時,程序將退出"""
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs)
        self.InitUI()

    def InitUI(self):
        # 創建 ToolBar,默認情況下,工具欄是水平、無邊框且顯示圖標的
        toolbar = self.CreateToolBar()
        # 調用 AddTool() 方法來創建工具欄的工具。第一個參數為ID,第二個參數為工具的標簽,第三個為工具的圖標
        qtool = toolbar.AddTool(wx.ID_ANY, '退出', wx.Bitmap('undo.png'))
        # 把工具項放到工具欄之后,調用 Realize() 方法。在 Linux 中,該方法的調用不是必須的,但在 Windows 卻是必須的
        toolbar.Realize()
        # 使用 wx.EVT_TOOL 事件綁定器
        self.Bind(wx.EVT_TOOL, self.OnQuit, qtool)
        self.SetSize((250, 200))
        self.SetTitle('單行工具欄')
        self.Centre()
        self.Show(True)

    def OnQuit(self, e):
        self.Close()

多行工具欄

在這里插入圖片描述

class Example(wx.Frame):
    """創建兩個水平的工具欄"""
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs)
        self.InitUI()

    def InitUI(self):
        vbox = wx.BoxSizer(wx.VERTICAL)
        # 第一個工具欄對象
        toolbar1 = wx.ToolBar(self)
        toolbar1.AddTool(wx.ID_ANY, '', wx.Bitmap('folder.png'))
        toolbar1.AddTool(wx.ID_ANY, '', wx.Bitmap('folder_new.png'))
        toolbar1.AddTool(wx.ID_ANY, '', wx.Bitmap('folder_sent_mail.png'))
        toolbar1.Realize()
        # 第二個工具欄對象
        toolbar2 = wx.ToolBar(self)
        qtool = toolbar2.AddTool(wx.ID_EXIT, '', wx.Bitmap('undo.png'))
        toolbar2.Realize()
        vbox.Add(toolbar1, 0, wx.EXPAND)
        vbox.Add(toolbar2, 0, wx.EXPAND)
        self.Bind(wx.EVT_TOOL, self.OnQuit, qtool)
        self.SetSizer(vbox)
        self.SetSize((300, 250))
        self.SetTitle('多行工具欄')
        self.Centre()
        self.Show(True)

    def OnQuit(self, e):
        self.Close()

禁用工具欄

在這里插入圖片描述

class Example(wx.Frame):
    """有三個工具欄按鈕,一個按鈕用來退出應用,其余兩個按鈕的功能為撤銷和反撤銷,在程序中模擬了4次改變,撤銷和反撤銷時對應的啟用或禁用"""
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs)
        self.InitUI()

    def InitUI(self):
        self.count = 5
        self.toolbar = self.CreateToolBar()
        tundo = self.toolbar.AddTool(wx.ID_UNDO, '', wx.Bitmap('previous.png'))
        tredo = self.toolbar.AddTool(wx.ID_REDO, '', wx.Bitmap('next.png'))
        # 程序開始時,撤銷按鈕是禁用的,調用 EnableTool() 函數,並傳遞 False 參數來實現
        self.toolbar.EnableTool(wx.ID_REDO, False)
        # 調用 AddSeparator() 函數來分隔不同的工具項
        self.toolbar.AddSeparator()
        texit = self.toolbar.AddTool(wx.ID_EXIT, '', wx.Bitmap('undo.png'))
        self.toolbar.Realize()
        self.Bind(wx.EVT_TOOL, self.OnQuit, texit)
        self.Bind(wx.EVT_TOOL, self.OnUndo, tundo)
        self.Bind(wx.EVT_TOOL, self.OnRedo, tredo)
        self.SetSize((250, 200))
        self.SetTitle('禁用工具欄')
        self.Centre()
        self.Show(True)

    def OnUndo(self, e):
        """模擬了撤銷和反撤銷的功能,如果沒有什么可以撤銷的,撤銷按鈕就會禁用"""
        if self.count > 1 and self.count <= 5:
            self.count = self.count - 1
        if self.count == 1:
            self.toolbar.EnableTool(wx.ID_UNDO, False)
        if self.count == 4:
            self.toolbar.EnableTool(wx.ID_REDO, True)

    def OnRedo(self, e):
        if self.count < 5 and self.count >= 1:
            self.count = self.count + 1
        if self.count == 5:
            self.toolbar.EnableTool(wx.ID_REDO, False)
        if self.count == 2:
            self.toolbar.EnableTool(wx.ID_UNDO, True)

    def OnQuit(self, e):
        self.Close()

高級控件

ListBox

該控件用來展示和操作一組列表項,它有一個矩形框,里面有一組字符串,通過它,可以展示一列 MP3文件、書名或者一堆朋友的名字。wx.ListBox 可以有兩種形式,單選和多選,默認為單選。該控件有兩個可觸發事件。

  • wx.EVT_COMMAND_LISTBOX_SELECTED – 當用戶單擊一個條目時觸發
  • wx.EVT_COMMAND_LISTBOX_DOUBLE_CLICKED – 當用戶雙擊一個條目時觸發

根據文檔,wx.ListBox 中條目的個數在 GTK 平台上限制為 2000 個,需要滾動時會自動展示滾動條。

在這里插入圖片描述

class Example(wx.Frame):
    """創建1個 ListBox 和4個 Button,每個 Button 對應一個不同的方法,即增刪改查"""
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, 'wx.ListBox', size=(350, 220))
        panel = wx.Panel(self, -1)
        hbox = wx.BoxSizer(wx.HORIZONTAL)
        # 創建一個空的 wx.ListBox,邊框是 20px
        self.listbox = wx.ListBox(panel, -1)
        hbox.Add(self.listbox, 1, wx.EXPAND | wx.ALL, 20)
        btnPanel = wx.Panel(panel, -1)
        vbox = wx.BoxSizer(wx.VERTICAL)
        new = wx.Button(btnPanel, id=1, label='增加', size=(90, 30))
        ren = wx.Button(btnPanel, id=2, label='修改', size=(90, 30))
        dlt = wx.Button(btnPanel, id=4, label='刪除', size=(90, 30))
        clr = wx.Button(btnPanel, id=3, label='清空', size=(90, 30))
        self.Bind(wx.EVT_BUTTON, self.NewItem, id=1)
        self.Bind(wx.EVT_BUTTON, self.OnRename, id=2)
        self.Bind(wx.EVT_BUTTON, self.OnDelete, id=4)
        self.Bind(wx.EVT_BUTTON, self.OnClear, id=3)
        # 使用 wx.EVT_LISTBOX_DCLICK 綁定器將 wx.EVT_COMMAND_LISTBOX_DOUBLE_CLICKED 事件綁定至 OnRename(),
        # 當用戶雙擊特定元素時將彈出一個重命名對話框
        self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnRename)
        vbox.Add((-1, 20))
        vbox.Add(new)
        vbox.Add(ren, 0, wx.TOP, 5)
        vbox.Add(dlt, 0, wx.TOP, 5)
        vbox.Add(clr, 0, wx.TOP, 5)
        btnPanel.SetSizer(vbox)
        hbox.Add(btnPanel, 0.6, wx.EXPAND | wx.RIGHT, 20)
        panel.SetSizer(hbox)
        self.Centre()
        self.Show(True)

    def NewItem(self, event):
        """點擊 增加 按鈕時,NewItem() 被調用,將展示一個 wx.GetTextFromUser 對話框,該對話框返回用戶的輸入"""
        text = wx.GetTextFromUser('輸入一個新條目', '插入對話框')
        # 如果輸入非空,使用 Append() 將其添加至 ListBox
        if text != '':
            self.listbox.Append(text)

    def OnRename(self, event):
        """wx.ListBox 控件沒有 Rename() 方法,只能刪除之前選擇的條目,然后在原來的地方插入一個新的條目"""
        sel = self.listbox.GetSelection()
        text = self.listbox.GetString(sel)
        renamed = wx.GetTextFromUser('重命名條目', '重命名對話框', text)
        if renamed != '':
            self.listbox.Delete(sel)
            self.listbox.Insert(renamed, sel)

    def OnDelete(self, event):
        """分兩步刪除一個 Item"""
        # 使用 GetSelection() 獲取被選擇條目的 index
        sel = self.listbox.GetSelection()
        if sel != -1:
            # 將 index 作為參數傳入 Delete() 方法刪除該元素
            self.listbox.Delete(sel)

    def OnClear(self, event):
        """調用 Clear() 清空 ListBox"""
        self.listbox.Clear()

ListCtrl

該控件是展示多列條目的圖形展示控件,常用於文件管理器、CD刻錄的文件等。它有三種不同的使用格式:列表視圖、報告視圖和圖標視圖,分別通過 style 參數:wx.LC_REPORTwx.LC_LIST 和 wx.LC_ICON 來控制。

在這里插入圖片描述

packages = [('1', '2012', '1054.74'), ('2', '2013', '1062.89'), ('3', '2014', '1077.89'), ('4', '2015', '1137.87'),
            ('5', '2016', '1190.84'), ('6', '2017', '1252.83'), ('7', '2018', '1302.66'), ('8', '2019', '1343.88')]

class Example(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, '深圳市年末常住人口', size=(380, 230))
        hbox = wx.BoxSizer(wx.HORIZONTAL)
        panel = wx.Panel(self, -1)
        # 使用 wx.LC_REPORT style 創建一個 wx.ListCtrl
        self.list = wx.ListCtrl(panel, -1, style=wx.LC_REPORT)
        # 插入 3 列,可以單獨控制每一列的寬度和格式,默認的格式是 wx.LIST_FORMAT_LEFT
        self.list.InsertColumn(0, '序號', width=140)
        self.list.InsertColumn(1, '統計時間', width=130)
        self.list.InsertColumn(2, '年末常住人口(萬人)', wx.LIST_FORMAT_RIGHT, 90)
        # 使用兩種方法將數據插入到 wx.ListCtrl 中去
        for i in packages:
            # 對每一行,調用 InsertItem() 方法,第一個參數為行號,使用2000保證每次調用時插入的行在上次插入行之后,該方法返回行的索引值
            index = self.list.InsertItem(index=2000, label=i[0])
            # 通過 SetItem() 方法在當前行的后續列中插入數據
            self.list.SetItem(index, 1, i[1])
            self.list.SetItem(index, 2, i[2])
        hbox.Add(self.list, 1, wx.EXPAND)
        panel.SetSizer(hbox)
        self.Centre()
        self.Show(True)

Mixins

該控件增強了 wx.ListCtrl 的功能,位於 wx.lib.mixins.listctrl 模塊,必須繼承這些類才可使用它們。

  • wx.ColumnSorterMixin – 允許排序
  • wx.ListCtrlAutoWidthMixin – 自動調整最后一列的寬度(占滿)
  • wx.ListCtrlSelectionManagerMix – 定義獨立於平台的選擇策略
  • wx.TextEditMixin – 允許文本編輯
  • wx.CheckListCtrlMixin – 為每一行添加一個選擇框

wx.ListCtrlAutoWidthMixin

在這里插入圖片描述

import wx
# 導入 Mixins 的 wx.ListCtrlAutoWidthMixin
from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin

actresses = [('1', '2012', '1054.74'), ('2', '2013', '1062.89'), ('3', '2014', '1077.89'), ('4', '2015', '1137.87'),
             ('5', '2016', '1190.84'), ('6', '2017', '1252.83'), ('7', '2018', '1302.66'), ('8', '2019', '1343.88')]


class AutoWidthListCtrl(wx.ListCtrl, ListCtrlAutoWidthMixin):
    """
    創建一個新的 AutoWidthListCtrl 類,該類繼承自 wx.ListCtrl 和 ListCtrlAutoWidthMixin(多重繼承),
    最后一列會自動改變寬度來占用剩余的全部空間。
    """
    def __init__(self, parent):
        wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT)
        ListCtrlAutoWidthMixin.__init__(self)


class Example(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, 'wx.ListCtrlAutoWidthMixin', size=(380, 230))
        hbox = wx.BoxSizer(wx.HORIZONTAL)
        panel = wx.Panel(self, -1)
        self.list = AutoWidthListCtrl(panel)
        self.list.InsertColumn(0, '序號', width=140)
        self.list.InsertColumn(1, '統計時間', width=130)
        self.list.InsertColumn(2, '年末常住人口(萬人)', wx.LIST_FORMAT_RIGHT, 90)
        for i in actresses:
            index = self.list.InsertItem(2000, i[0])
            self.list.SetItem(index, 1, i[1])
            self.list.SetItem(index, 2, i[2])
        hbox.Add(self.list, 1, wx.EXPAND)
        panel.SetSizer(hbox)
        self.Centre()
        self.Show(True)

wx.ColumnSorterMixin

在這里插入圖片描述

import wx
from wx.lib.mixins.listctrl import ColumnSorterMixin

actresses = {
    1: ('2012', '1054.74'), 2: ('2013', '1062.89'), 3: ('2014', '1077.89'), 4: ('2015', '1137.87'),
    5: ('2016', '1190.84'), 6: ('2017', '1252.83'), 7: ('2018', '1302.66'), 8: ('2019', '1343.88')
}


class SortedListCtrl(wx.ListCtrl, ColumnSorterMixin):
    def __init__(self, parent):
        wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT)
        # ColumnSorterMixin 接受一個參數,即要排序的列的個數
        ColumnSorterMixin.__init__(self, len(actresses))
        # 必須將數據匹配到 itemDataMap 屬性中,且數據類型為字典
        self.itemDataMap = actresses

    def GetListCtrl(self):
        """必須創建一個 GetListCtrl() 方法,它會返回一個將被排序的 wx.ListCtrl 控件"""
        return self


class Example(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, 'wx.ColumnSorterMixin', size=(380, 230))
        hbox = wx.BoxSizer(wx.HORIZONTAL)
        panel = wx.Panel(self, -1)
        self.list = SortedListCtrl(panel)
        self.list.InsertColumn(0, '統計時間', width=130)
        self.list.InsertColumn(1, '年末常住人口(萬人)', wx.LIST_FORMAT_RIGHT, 90)
        items = actresses.items()
        for key, data in items:
            index = self.list.InsertItem(2000, data[0])
            self.list.SetItem(index, 1, data[1])
            # 需要使用 SetItemData() 方法將每一行與一個 index 關聯起來
            self.list.SetItemData(index, key)
        hbox.Add(self.list, 1, wx.EXPAND)
        panel.SetSizer(hbox)
        self.Centre()
        self.Show(True)

HtmlWindow

該控件可以展示HTML頁面,但是它不是一個完整的瀏覽器,只能展示一些基本的標簽。

在這里插入圖片描述

import wx
import wx.html as html

page = """<html><body bgcolor="#8e8e95"><table cellspacing="5" border="0" width="250">
<tr width="200" align="left"><td bgcolor="#e7e7e7">最大值</td><td bgcolor="#F0FFFF"><b>9000</b></td></tr>
<tr align="left"><td bgcolor="#e7e7e7">平均值</td><td bgcolor="#F0F8FF"><b>6076</b></td></tr>
<tr align="left"><td bgcolor="#e7e7e7">最小值</td><td bgcolor="#E6E6FA"><b>3800</b></td></tr>
<tr align="left"><td bgcolor="#e7e7e7">中位數</td><td bgcolor="#FFF0F5"><b>6000</b></td></tr>
<tr align="left"><td bgcolor="#e7e7e7">標准偏差</td><td bgcolor="#FFE4E1"><b>6076</b></td></tr>
</table></body></html>"""

class Example(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, 'html.HtmlWindow', size=(400, 290))
        panel = wx.Panel(self, -1)
        v_box = wx.BoxSizer(wx.HORIZONTAL)
        # 創建一個HTML窗口
        html_win = html.HtmlWindow(panel, -1, style=wx.NO_BORDER)
        html_win.SetBackgroundColour(wx.RED)
        html_win.SetStandardFonts()
        html_win.SetPage(page)
        v_box.Add(html_win, 1, wx.EXPAND | wx.ALL, 9)
        panel.SetSizer(v_box)
        self.Centre()
        self.Show(True)

拖拽

拖拽操作將一些數據從一個源位置移動到目標位置,實現拖拽需要有:一些數據、一個數據來源和一個數據目標。

TextDropTarget

在這里插入圖片描述

import wx
import os


class MyTextDropTarget(wx.TextDropTarget):
    """繼承wx.TextDropTarget類,這是 wxPython 中兩個預定義的數據目標之一"""
    def __init__(self, object):
        wx.TextDropTarget.__init__(self)
        self.object = object

    def OnDropText(self, x, y, data):
        self.object.InsertItem(0, data)
        return True


class Example(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, 'wx.TextDropTarget', size=(750, 450))
        # 創建兩個分隔窗口(wx.SplitterWindow)控件
        splitter1 = wx.SplitterWindow(self, -1, style=wx.SP_3D)
        splitter2 = wx.SplitterWindow(splitter1, -1, style=wx.SP_3D)
        # 創建一個目錄樹(wx.GenericDirCtrl)控件
        self.dir = wx.GenericDirCtrl(splitter1, -1, dir='C:/Users/hekaiyou/Downloads', style=wx.DIRCTRL_DIR_ONLY)
        # 分別創建數據來源(lc1)列表與數據目標(lc2)列表
        self.lc1 = wx.ListCtrl(splitter2, -1, style=wx.LC_LIST)
        self.lc2 = wx.ListCtrl(splitter2, -1, style=wx.LC_LIST)
        # 綁定數據目標列表的數據
        dt = MyTextDropTarget(self.lc2)
        self.lc2.SetDropTarget(dt)
        self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.OnDragInit, id=self.lc1.GetId())
        # 獲取樹控件的節點
        tree = self.dir.GetTreeCtrl()
        # 設置上下布局的分隔窗口,window1為上窗口,window2為下窗口,sashPosition是窗口的位置
        splitter2.SplitHorizontally(window1=self.lc1, window2=self.lc2)
        # 設置最小窗口尺寸,上下布局是指上窗口的最小尺寸
        splitter2.SetMinimumPaneSize(200)
        # 設置左右布局的分隔窗口,window1為左窗口,window2為右窗口,sashPosition是窗口的位置
        splitter1.SplitVertically(window1=self.dir, window2=splitter2)
        # 設置最小窗口尺寸,左右布局是指左窗口的最小尺寸
        splitter1.SetMinimumPaneSize(320)
        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelect, id=tree.GetId())
        self.OnSelect(0)
        self.Centre()
        self.Show(True)

    def OnSelect(self, event):
        list = os.listdir(self.dir.GetPath())
        self.lc1.ClearAll()
        self.lc2.ClearAll()
        for i in range(len(list)):
            if list[i][0] != '.':
                self.lc1.InsertItem(0, list[i])

    def OnDragInit(self, event):
        text = self.lc1.GetItemText(event.GetIndex())
        tdo = wx.TextDataObject(text)
        tds = wx.DropSource(self.lc1)
        tds.SetData(tdo)
        tds.DoDragDrop(True)

FileDropTarget

在這里插入圖片描述

class FileDrop(wx.FileDropTarget):
    def __init__(self, window):
        wx.FileDropTarget.__init__(self)
        self.window = window

    def OnDropFiles(self, x, y, filenames):
        for name in filenames:
            try:
                file = open(name, 'r')
                text = file.read()
                self.window.WriteText(text)
                file.close()
            except IOError as error:
                dlg = wx.MessageDialog(None, '打開文件時出錯', str(error))
                dlg.ShowModal()
            except UnicodeDecodeError as error:
                dlg = wx.MessageDialog(None, '無法打開非ASCII文件', str(error))
                dlg.ShowModal()
        return True


class Example(wx.Frame):
    """可以將文件拖至編輯器,編輯器將顯示其內容"""
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, 'wx.FileDropTarget', size=(450, 400))
        self.text = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE)
        dt = FileDrop(self.text)
        self.text.SetDropTarget(dt)
        self.Centre()
        self.Show(True)

事件

事件是來源於底層框的應用層信息,事件循環主要用來分發事件和等待信息。事件分配器將事件匹配到對應的事件處理器,事件處理器即用來對響應事件做出特定反應的函數。

移動事件

當移動窗口到一個新位置時,會產生一個移動事件,它的類型是 wx.MoveEvent,該事件的綁定器是 wx.EVT_MOVE

在這里插入圖片描述

class Example(wx.Frame):
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        wx.StaticText(self, label='x:', pos=(10, 10))
        wx.StaticText(self, label='y:', pos=(10, 30))
        self.st1 = wx.StaticText(self, label='', pos=(30, 10))
        self.st2 = wx.StaticText(self, label='', pos=(30, 30))
        # 將 wx.EVT_MOVE 事件綁定到 OnMove() 方法上
        self.Bind(wx.EVT_MOVE, self.OnMove)
        self.SetSize((250, 180))
        self.SetTitle('窗口移動事件')
        self.Centre()
        self.Show(True)

    def OnMove(self, e):
        """這里的 e 是 wx.MoveEvent 類的一個實例,它包含了該 event 的一些信息,包括事件對象和窗口位置等"""
        # 通過事件(即是 wx.Frame 控件)的 GetPosition() 函數來得到當前位置
        x, y = e.GetPosition()
        self.st1.SetLabel(str(x))
        self.st2.SetLabel(str(y))

停止事件

有時需要停止某個事件的繼續處理,這時可以調用 Veto() 方法。

在這里插入圖片描述

class Example(wx.Frame):
    """處理了一個 wx.CloseEvent 事件,當點擊窗口的 X關閉按鈕、按下 Alt+F4 或者從菜單選擇退出應用時,這個事件會被觸發"""
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        # 綁定 wx.EVT_CLOSE 事件處理
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
        self.SetTitle('wx.EVT_CLOSE')
        self.Centre()
        self.Show(True)

    def OnCloseWindow(self, e):
        """在處理關閉事件時,顯示一個消息對話框"""
        dial = wx.MessageDialog(None, '你確定要退出嗎?', '提示',
                                wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
        ret = dial.ShowModal()
        # 根據對話框的返回值,可以銷毀窗口或者停止這一事件
        if ret == wx.ID_YES:
            # 必須使用 Destroy() 來關閉窗口,如果調用 Close() 函數,程序將陷入死循環
            self.Destroy()
        else:
            e.Veto()

事件傳播

事件分兩種:基礎事件與命令事件,兩者在事件傳播上存在不同,事件傳播是指將事件從子控件傳播至父控件乃至更上層控件,基礎事件不傳播,而命令事件會傳播。例如:wx.CloseEvent 是一個基礎事件,這意味着它不會向上傳播。默認情況下,如果事件被事件處理函數捕獲,那么就會停止后續的傳播,如果要讓它繼續傳播,需要調用 Skip() 函數。

在這里插入圖片描述

class MyPanel(wx.Panel):
    def __init__(self, *args, **kw):
        super(MyPanel, self).__init__(*args, **kw)
        self.Bind(wx.EVT_BUTTON, self.OnButtonClicked)

    def OnButtonClicked(self, e):
        print('事件抵達 Panel 類')
        e.Skip()


class MyButton(wx.Button):
    """處理了按鈕點擊事件,Skip() 函數使得事件繼續向上層傳播"""
    def __init__(self, *args, **kw):
        super(MyButton, self).__init__(*args, **kw)
        self.Bind(wx.EVT_BUTTON, self.OnButtonClicked)

    def OnButtonClicked(self, e):
        print('事件抵達 Button 類')
        e.Skip()


class Example(wx.Frame):
    """在 Frame 上的 Panel 中放置了一個 Button,並對所有的控件定義了事件處理函數"""
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        mpnl = MyPanel(self)
        MyButton(mpnl, label='Ok', pos=(15, 15))
        self.Bind(wx.EVT_BUTTON, self.OnButtonClicked)
        self.SetTitle('傳播事件')
        self.Centre()
        self.Show(True)

    def OnButtonClicked(self, e):
        print('事件抵達 Frame 類')
        e.Skip()

控件標識符

控件標識符是指在事件系統中,找到控件的唯一整數標記,創建窗口標識符的方法有三種:系統自動創建ID、使用標准標識符、創建自定義ID。

自動創建ID

在不需要修改控件狀態的時候,一般選擇由系統自動創建ID,可以將 -1 或者 wx.ID_ANY 賦值給 id 參數,但是系統自動創建的ID總是負值(用戶創建的必須是正值),可以通過 GetId() 來獲取ID。

class Example(wx.Frame):
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        pnl = wx.Panel(self)
        exitButton = wx.Button(pnl, wx.ID_ANY, '退出', (10, 10))
        # 通過 GetId() 函數直接獲取自動生成的ID
        self.Bind(wx.EVT_BUTTON, self.OnExit, id=exitButton.GetId())
        self.SetTitle("系統自動創建ID")
        self.Centre()
        self.Show(True)

    def OnExit(self, event):
        self.Close()

標准標識符

使用標准標識符可以在不同平台提供標准的圖形或行為。

在這里插入圖片描述

class Example(wx.Frame):
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        pnl = wx.Panel(self)
        grid = wx.GridSizer(cols=2)
        # 將6個按鈕加入到一個網格布局中
        grid.AddMany([
            (wx.Button(pnl, wx.ID_CANCEL), 0, wx.TOP | wx.LEFT, 9),  # 標准標識符-取消
            (wx.Button(pnl, wx.ID_DELETE), 0, wx.TOP, 9),  # 標准標識符-刪除
            (wx.Button(pnl, wx.ID_SAVE), 0, wx.LEFT, 9),  # 標准標識符-保存
            (wx.Button(pnl, wx.ID_EXIT)),  # 標准標識符-退出
            (wx.Button(pnl, wx.ID_STOP), 0, wx.LEFT, 9),  # 標准標識符-停止
            (wx.Button(pnl, wx.ID_NEW))  # 標准標識符-新建
        ])
        # 將事件綁定到 OnQuitAPP() 處理函數,使用 id 參數來區分不同的 Button,並唯一標識事件的來源
        self.Bind(wx.EVT_BUTTON, self.OnQuitApp, id=wx.ID_EXIT)
        pnl.SetSizer(grid)
        self.SetSize((220, 180))
        self.SetTitle("使用標准標識符")
        self.Centre()
        self.Show(True)

    def OnQuitApp(self, event):
        self.Close()

自定義標識符

# 定義全局的自定義的唯一ID
ID_MENU_NEW = 1
ID_MENU_OPEN = 2
ID_MENU_SAVE = 3


class Example(wx.Frame):
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        self.CreateMenuBar()
        self.CreateStatusBar()
        self.SetSize((250, 180))
        self.SetTitle('自定義控件標識符')
        self.Centre()
        self.Show(True)

    def CreateMenuBar(self):
        mb = wx.MenuBar()
        fMenu = wx.Menu()
        fMenu.Append(ID_MENU_NEW, '新建')
        fMenu.Append(ID_MENU_OPEN, '打開')
        fMenu.Append(ID_MENU_SAVE, '保存')
        mb.Append(fMenu, '文件')
        self.SetMenuBar(mb)
        # 通過唯一ID可以識別前面創建的三個菜單項
        self.Bind(wx.EVT_MENU, self.DisplayMessage, id=ID_MENU_NEW)
        self.Bind(wx.EVT_MENU, self.DisplayMessage, id=ID_MENU_OPEN)
        self.Bind(wx.EVT_MENU, self.DisplayMessage, id=ID_MENU_SAVE)

    def DisplayMessage(self, e):
        sb = self.GetStatusBar()
        # 從 e(事件對象)中得到ID,根據ID的不同,准備不同的信息,並輸出在狀態欄
        eid = e.GetId()
        if eid == ID_MENU_NEW:
            msg = '選擇 新建 菜單項'
        elif eid == ID_MENU_OPEN:
            msg = '選擇 打開 菜單項'
        elif eid == ID_MENU_SAVE:
            msg = '選擇 保存 菜單項'
        else:
            msg = ''
        sb.SetStatusText(msg)

繪制事件

當窗口重繪時會觸發繪制事件,比如調整窗口大小或者最大化的時候。也可以程序化的觸發繪制事件,比如,調用 SetLabel() 函數來修改 wx.StaticText 組件的文字時,就會觸發繪制事件。

class Example(wx.Frame):
    """對繪制事件進行計數,並將當前數目設置為 Frame 窗口的標題"""
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        self.count = 0
        # 將 wx.EVT_PAINT 事件綁定至 OnPaint 函數
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.SetSize((250, 180))
        self.Centre()
        self.Show(True)

    def OnPaint(self, e):
        """增加計數器,並設置新的窗口標題"""
        self.count += 1
        self.SetTitle(str(self.count))

焦點事件

焦點是指當前應用中被選擇的控件,從鍵盤輸入或剪切板拷入的文本將被發送到該控件,有兩個事件與焦點有關:wx.EVT_SET_FOCUS 和 wx.EVT_KILL_FOCUS。當一個控件獲得焦點時,會觸發 wx.EVT_SET_FOCUS,當控件丟失焦點時,會觸發 wx.EVT_KILL_FOCUS。通過點擊或者鍵盤按鍵,比如 Tab 鍵或 Shift+Tab 鍵可以改變焦點。

在這里插入圖片描述

class MyPanel(wx.Panel):
    def __init__(self, parent):
        super(MyPanel, self).__init__(parent)
        self.color = '#b3b3b3'
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        # 把兩個焦點事件綁定至事件處理函數
        self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)

    def OnPaint(self, e):
        """在面板上進行了繪制,外框的顏色取決於面板是否獲得焦點,如果獲得焦點,則使用藍色"""
        dc = wx.PaintDC(self)
        dc.SetPen(wx.Pen(self.color))
        x, y = self.GetSize()
        dc.DrawRectangle(0, 0, x, y)

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

    def OnSetFocus(self, e):
        # 設置 self.color 為藍色
        self.color = '#0099f7'
        # 刷新 Frame 窗口,這會觸發所有子控件的繪制事件,面板會被重繪,獲取焦點的面板將得到一個藍色外框
        self.Refresh()

    def OnKillFocus(self, e):
        self.color = '#b3b3b3'
        self.Refresh()


class Example(wx.Frame):
    """創建4個 Panel,獲得當前焦點的 Panel 會被高亮顯示"""
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        grid = wx.GridSizer(2, 2, 10, 10)
        grid.AddMany([
            (MyPanel(self), 0, wx.EXPAND | wx.TOP | wx.LEFT, 9),
            (MyPanel(self), 0, wx.EXPAND | wx.TOP | wx.RIGHT, 9),
            (MyPanel(self), 0, wx.EXPAND | wx.BOTTOM | wx.LEFT, 9),
            (MyPanel(self), 0, wx.EXPAND | wx.BOTTOM | wx.RIGHT, 9)
        ])
        self.SetSizer(grid)
        self.SetSize((350, 250))
        self.SetTitle('焦點事件')
        self.Centre()
        self.Show(True)

鍵盤事件

在鍵盤上按下按鈕時,一個鍵盤事件會被觸發,並被發送到當前焦點控件,有三種不同的鍵盤事件:wx.EVT_KEY_DOWNwx.EVT_KEY_UP 和 wx.EVT_CHAR

在這里插入圖片描述

class Example(wx.Frame):
    """當按下 Esc 時,會彈出對話框詢問,是否關閉應用"""
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        pnl = wx.Panel(self)
        # 將 wx.EVT_KEY_DOWN 事件綁定至 self.OnKeyDown() 函數
        pnl.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        pnl.SetFocus()
        self.SetSize((250, 180))
        self.SetTitle('鍵盤事件')
        self.Centre()
        self.Show(True)

    def OnKeyDown(self, e):
        # 通過 e(事件對象)得到按下鍵的編號
        key = e.GetKeyCode()
        # 檢查鍵編號,判斷按下的鍵是否是 Esc,它的鍵編號是 wx.WXK_ESCAPE
        if key == wx.WXK_ESCAPE:
            ret = wx.MessageBox('你確定要關閉應用嗎?', '提醒',
                                wx.YES_NO | wx.NO_DEFAULT, self)
            if ret == wx.YES:
                self.Close()

自定義控件

一般通過兩種方式創建自定義控件:修改或增強已有控件、從零開始創建。

在這里插入圖片描述

import wx
# 導入 wx.lib.stattext.GenStaticText 控件
from wx.lib.stattext import GenStaticText
# 導入 webbrowser 標准模塊
import webbrowser


class Link(GenStaticText):
    """基於 wx.lib.stattext.GenStaticText 控件構建 超鏈接控件"""
    def __init__(self, *args, **kw):
        super(Link, self).__init__(*args, **kw)
        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 SetUrl(self, url):
        self.url = url

    def OnMouseEvent(self, e):
        # 如果鼠標移到鏈接上方時,顯示文本下划線,並將鼠標設置為手型
        if e.Moving():
            self.SetCursor(wx.Cursor(wx.CURSOR_HAND))
            self.SetFont(self.font1)
        # 如果點擊鏈接,在默認瀏覽器打開它
        elif e.LeftUp():
            webbrowser.open_new(self.url)
        else:
            self.SetCursor(wx.NullCursor)
            self.SetFont(self.font2)
        e.Skip()


class Example(wx.Frame):
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)
        self.InitUI()

    def InitUI(self):
        panel = wx.Panel(self)
        lnk = Link(panel, label='百度', pos=(10, 60))
        lnk.SetUrl('https://www.baidu.com')
        motto = GenStaticText(panel, label='通過系統默認瀏覽器打開', pos=(10, 30))
        motto.SetFont(wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD, False, 'Verdana'))
        self.SetSize((220, 150))
        self.SetTitle('超鏈接控件')
        self.Centre()
        self.Show(True)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM