wxPython筆記:TextCtrl 使用驗證器


原文鏈接

作者:月小水長

前言
TextCtrl 是 wxPython 框架里一個非常實用的文本輸入控件,我們經常需要對 TextCtrl 做這樣一個輸入上的約束:只允許輸入數字(比如允許 1.2、4.5、100 這些輸入而禁止諸如 .8、4t等輸入,方便我們在將輸入的 str 類型轉成 int、float 等其他類型時不需要額外加判斷來防止產生異常。今天我查閱 wxPython 的 API,發現了 Validator 這個類可以滿足我們的需求。事實上,不僅是滿足只允許輸入數字這個需要,掌握了 Validator 這個類的使用,我們可以滿足任何定制化的需求。

編碼

首先必須新建類繼承自 wx.Validator

import wx

class MyNumberValidator(wx.Validator):# 創建驗證器子類      
    def __init__(self):
        wx.Validator.__init__(self)
      
    def Clone(self):
        return MyNumberValidator()

    def Validate(self,win):#1 使用驗證器方法
        return True

    def TransferToWindow(self):
        return True

    def TransferFromWindow(self):
        return True   

同時,必須重寫 init()(完成初始化)、Clone()(返回當前類的一個實例)等五個方法,你只要把它們當成一個模板就行,然后在此基礎上加上我們自己的邏輯。

根據需求加入實現邏輯

import wx
# import wx.lib.imagebrowser


class MyNumberValidator(wx.Validator):# 創建驗證器子類      
    def __init__(self):
        wx.Validator.__init__(self)
        self.ValidInput = ['.','0','1','2','3','4','5','6','7','8','9']
        self.StringLength = 0
        self.Bind(wx.EVT_CHAR,self.OnCharChanged)  #  綁定字符改變事件

    def OnCharChanged(self,event):
        # 得到輸入字符的 ASCII 碼
        keycode = event.GetKeyCode()
        # 退格(ASCII 碼 為8),刪除一個字符。
        if keycode == 8:
            self.StringLength -= 1
            #事件繼續傳遞
            event.Skip()
            return

        # 把 ASII 碼 轉成字符
        InputChar = chr(keycode)

        if InputChar in self.ValidInput:
            # 第一個字符為 .,非法,攔截該事件,不會成功輸入
            if InputChar == '.' and self.StringLength == 0:
                return False
            # 在允許輸入的范圍,繼續傳遞該事件。
            else:
                event.Skip()
                self.StringLength += 1
                return True
        return False

    def Clone(self):
        return MyNumberValidator()

    def Validate(self,win):#1 使用驗證器方法
        return True

    def TransferToWindow(self):
        return True

    def TransferFromWindow(self):
        return True

注意這行代碼,self.Bind(wx.EVT_CHAR,self.OnCharChanged) # 綁定字符輸入事件,它的意思是,一旦用戶輸入了字符,該事件會首先交給OnCharChanged方法處理,在OnCharChanged中,特別注意event.Skip()這行代碼,它的意思是,過了合法性檢驗這一關,該事件可以繼續傳遞了,可以交給將該字符加入 textctrl.value 並顯示出來的函數處理;否則,事件就在OnCharChanged中被攔截了,不會顯示出來,輸入失敗。

給控件 textctrl 綁定驗證器子類。
很簡單,只需要在創建 textctrl 的時候加指定關鍵詞參數

wx.TextCtrl(self,validator=MyNumberValidator(),style=wx.TE_CENTER)

style=wx.TE_CENTER 使輸入字符居中

再說 Validate() 方法

我們發現,Validator 類中和類名最相似的方法Validate()一直沒有使用,其實這個方法是一般使用流程如下,先在 Validate() 方法中加上業務邏輯。

def Validate(self,win):#1 使用驗證器方法
        print(111)
        textCtrl = self.GetWindow()
        text = textCtrl.GetValue()
        valid_text = ''
        for i in text:
            if i in self.ValidInput:
                valid_text += i
        textCtrl.SetValue(valid_text)
        return True

然后在外部調用它驗證合法性

self.n1.GetValidator().Validate(self.n1)

Validate()也可以驗證合法性,只不過它不能處理輸入事件,必須在輸入完成后才能驗證合法性,相當於“馬后炮”的作用。

完整例子:

# -*- coding: utf-8 -*-
# author:           inspurer(月小水長)
# pc_type           lenovo
# create_time:      2019/4/12 13:37
# file_name:        validator.py
# github            https://github.com/inspurer
# qq郵箱            2391527690@qq.com
# 微信公眾號         月小水長(ID: inspurer)


import wx
# import wx.lib.imagebrowser


class MyNumberValidator(wx.Validator):# 創建驗證器子類      
    def __init__(self):
        wx.Validator.__init__(self)
        self.ValidInput = ['.','0','1','2','3','4','5','6','7','8','9']
        self.StringLength = 0
        self.Bind(wx.EVT_CHAR,self.OnCharChanged)  #  綁定字符輸入事件

    def OnCharChanged(self, event):
        # 得到輸入字符的 ASCII 碼
        keycode = event.GetKeyCode()
        # 退格(ASCII 碼 為8),刪除一個字符。
        if keycode == 8:
            self.StringLength -= 1
            # 事件繼續傳遞
            event.Skip()
            return

        # 把 ASII 碼 轉成字符
        InputChar = chr(keycode)

        if InputChar in self.ValidInput:
            # 第一個字符為 .,非法,攔截該事件,不會成功輸入
            if InputChar == '.' and self.StringLength == 0:
                return False
            # 在允許輸入的范圍,繼續傳遞該事件。
            else:
                event.Skip()
                self.StringLength += 1
                return True
        return False

    def Clone(self):
        return MyNumberValidator()

    def Validate(self,win):#1 使用驗證器方法
        print(111)
        textCtrl = self.GetWindow()
        text = textCtrl.GetValue()
        valid_text = ''
        for i in text:
            if i in self.ValidInput:
                valid_text += i
        textCtrl.SetValue(valid_text)
        return True

    def TransferToWindow(self):
        return True

    def TransferFromWindow(self):
        return True

class GUI(wx.Frame):
    def __init__(self,parent):
        wx.Frame.__init__(self, parent=parent, title="wxPython開發實戰",size=(400,300),style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER ^ wx.MAXIMIZE_BOX )
        self.Center()

        self.SetBackgroundColour('white')

        font = wx.Font(16,wx.DECORATIVE, wx.NORMAL, wx.NORMAL)
        self.n1 = wx.TextCtrl(self,validator=MyNumberValidator(),pos=(100,30),size=(180,45),style=wx.TE_CENTER)
        self.n1.SetFont(font)
        self.n1.SetBackgroundColour('#95ec69')
        self.n1.SetHint('請輸入第一個數字')

        self.n2 = wx.TextCtrl(self,validator=MyNumberValidator(),pos=(100,100),size=(180,45),style=wx.TE_CENTER)
        self.n2.SetFont(font)
        self.n2.SetBackgroundColour('#95ec69')
        self.n2.SetHint('請輸入第二個數字')


        self.config = wx.Button(self,label="驗證輸入框一的合法性",pos=(115,170),size=(150,40))
        self.config.SetBackgroundColour('#95ec69')

        self.Bind(wx.EVT_BUTTON,self.configClicked,self.config)

    def configClicked(self,event):
        self.n1.GetValidator().Validate(self.n1)
        pass

if __name__ == "__main__":
    app = wx.App()
    GUI(None).Show()
    app.MainLoop()


免責聲明!

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



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