【wxPython】wxPython创建一个简单的记事本

时间:2020-12-18 07:11:07

创建一个简单的记本
现在我们来写一个简单的记事本。在这个例子中,我们会用到几个组件(Widgets),来理解一些特性或功能,例如事件处理(events)和回调函数(callbacks)。
首先,我们需要创建1个框架(frame),并且这个框架(frame)包含1个可编辑的文本框(text box)。文本框需要用wx.TextCtrl来创建。默认情况下,文本框只能编辑1行文字——无论文字有多长,都不会换行。所以,我们需要用wx.TE_MULTILINE参数来允许多行编辑。

import wx 
class MainWindow(wx.Frame):
"""We simply derive a new class of Frame."""
def __init__(self,parent,title):
wx.Frame.__init__(self,parent,title=title,size=(400,300))
self.contrl= wx.TextCtrl(self,style=wx.TE_MULTILINE)
self.Show(show=True)

app = wx.App(False)
frame = MainWindow(None,"MyTextEditor")
#frame.Show(show=True)
app.MainLoop()

在这个例子中,我们生成一个wx.Frame的子类,并重写它的__init__方法。我们用wx.TextCtrl来声明一个简单的文本编辑器。注意,因为在MyFrame.__init__中已经运行了self.Show(),所以在创建MyFrame的实例之后,就不用再调用frame.Show()了。

#-*- coding: utf-8 -*-
import wx
class MainWindow(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent=parent,title=title,size=(400,300))
self.contrl = wx.TextCtrl(self,style=wx.TE_MULTILINE)
#self.Show(show=True)
#self.CreateStatusBar() #状态栏设置
self.statusbar = self.CreateStatusBar() #窗口底部状态栏设置
self.statusbar.SetFieldsCount(3) #将状态栏分割为3个区域
self.statusbar.SetStatusWidths([-1, -2, -3]) #将状态栏分割比例为1:2:3
#self.SetStatusBarPane(1)
#self.SetBackgroundColour('Green')
self.statusbar.SetStatusText("Area0!!!",0) #状态栏区域0信息文本信息
self.statusbar.SetStatusText("Area1!!!",1) #状态栏区域1信息文本信息
self.statusbar.SetStatusText("Area2!!!",2) #状态栏区域1信息文本信息

#设置菜单1:
filemenu = wx.Menu()
#wx.ID_ABOUT和wx.ID_EXIT是wxWidgets提供的ID
filemenu.Append(wx.ID_NEW,u"新建",u"新建1") #添加子菜单
filemenu.AppendSeparator() #添加分割线
filemenu.Append(wx.ID_CLOSE,u"关闭",u"关闭1")
filemenu.Append(wx.ID_SAVEAS,u"另存为",u"另存为1")
#filemenu.Append(wx.ID_NEW,u"授权管理",u"授权管理")
filemenu.Append(wx.ID_ABOUT,u"关于",u"关于1")

#设置菜单2:
EditMenu = wx.Menu()
EditMenu.Append(wx.ID_ABOUT,u"关于",u"关于程序的信息")
#filemenu.AppendSeparator()
EditMenu.Append(wx.ID_EXIT, u"退出",u"终止应用程序")
EditMenu.Append(wx.ID_SAVE, u"保存",u"保存应用程序")

#创建菜单栏
menuBar = wx.MenuBar() #创建菜单栏
menuBar.Append(filemenu,u"文件(F)")
menuBar.Append(EditMenu,u"编辑(E)")
self.SetMenuBar(menuBar)

self.Show(True)

app = wx.App(False)
frame = MainWindow(None,title=u"记事本")
app.MainLoop()

【wxPython】wxPython创建一个简单的记事本

建议:wx.ID_NEWwx.ID_CLOSE等等,这些是wxWidgets提供的标准ID(查看全部标准ID)。如果有一个现成的标准ID,最好还是使用它,而不要自定义。因为这样可以让wxWidgets知道,在不同的平台怎样去显示这个组件,使它看起来更美观。

事件处理event handling
我们已经创建了1个记事本,虽然它有菜单,但是什么都做不了。我们希望点击菜单之后,程序能够做出反应,例如退出,或者保存文件。在Python中,点击菜单,点击按钮,输入文本,鼠标移动等等,都被称为事件event,而对event做出反应,则被称为event handling。对不同的event做出不同的响应,这是GUI程序的根本。我们可以使用Bind()方法,将1个对象Object1个时间event建立绑定关系。

class MainWindow(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self,parent, title=title, size=(200,100))
...
menuItem = filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
self.Bind(wx.EVT_MENU, self.OnAbout, menuItem)

这段代码意味着:从现在开始,一旦用户点击了菜单中的About项目,self.OnAbout就会被执行。
wx.EVT_MENU指代“选择菜单中的项目”这个事件。wxWidgets提供了很多的事件,可以点这里查看不完整的列表,也可以使用下面的代码打印完整的列表。所有的事件都是wx.Event的子类。

# -*- coding: utf-8 -*-
import wx
for x in dir(wx):
if x.startswith('EVT_'):
print (x)

打印结果:

EVT_ACTIVATE
EVT_ACTIVATE_APP
EVT_BOOKCTRL_PAGE_CHANGED
EVT_BOOKCTRL_PAGE_CHANGING
EVT_BUTTON
EVT_CATEGORY_ALL
EVT_CATEGORY_SOCKET
EVT_CATEGORY_THREAD
EVT_CATEGORY_TIMER
EVT_CATEGORY_UI
EVT_CATEGORY_USER_INPUT
EVT_CHAR
EVT_CHAR_HOOK
EVT_CHECKBOX
EVT_CHECKLISTBOX
EVT_CHILD_FOCUS
EVT_CHOICE
EVT_CHOICEBOOK_PAGE_CHANGED
EVT_CHOICEBOOK_PAGE_CHANGING
EVT_CLOSE
EVT_COLLAPSIBLEPANE_CHANGED
EVT_COLOURPICKER_CHANGED
EVT_COMBOBOX
EVT_COMBOBOX_CLOSEUP
EVT_COMBOBOX_DROPDOWN
EVT_COMMAND_ENTER
EVT_COMMAND_KILL_FOCUS
EVT_COMMAND_LEFT_CLICK
EVT_COMMAND_LEFT_DCLICK
EVT_COMMAND_RIGHT_CLICK
EVT_COMMAND_RIGHT_DCLICK
EVT_COMMAND_SCROLL
EVT_COMMAND_SCROLL_BOTTOM
EVT_COMMAND_SCROLL_CHANGED
EVT_COMMAND_SCROLL_ENDSCROLL
EVT_COMMAND_SCROLL_LINEDOWN
EVT_COMMAND_SCROLL_LINEUP
EVT_COMMAND_SCROLL_PAGEDOWN
EVT_COMMAND_SCROLL_PAGEUP
EVT_COMMAND_SCROLL_THUMBRELEASE
EVT_COMMAND_SCROLL_THUMBTRACK
EVT_COMMAND_SCROLL_TOP
EVT_COMMAND_SET_FOCUS
EVT_CONTEXT_MENU
EVT_DETAILED_HELP
EVT_DETAILED_HELP_RANGE
EVT_DIRCTRL_FILEACTIVATED
EVT_DIRCTRL_SELECTIONCHANGED
EVT_DIRPICKER_CHANGED
EVT_DISPLAY_CHANGED
EVT_DROP_FILES
EVT_END_PROCESS
EVT_END_SESSION
EVT_ENTER_WINDOW
EVT_ERASE_BACKGROUND
EVT_FILECTRL_FILEACTIVATED
EVT_FILECTRL_FILTERCHANGED
EVT_FILECTRL_FOLDERCHANGED
EVT_FILECTRL_SELECTIONCHANGED
EVT_FILEPICKER_CHANGED
EVT_FIND
EVT_FIND_CLOSE
EVT_FIND_NEXT
EVT_FIND_REPLACE
EVT_FIND_REPLACE_ALL
EVT_FONTPICKER_CHANGED
EVT_FSWATCHER
EVT_HEADER_BEGIN_REORDER
EVT_HEADER_BEGIN_RESIZE
EVT_HEADER_CLICK
EVT_HEADER_DCLICK
EVT_HEADER_DRAGGING_CANCELLED
EVT_HEADER_END_REORDER
EVT_HEADER_END_RESIZE
EVT_HEADER_MIDDLE_CLICK
EVT_HEADER_MIDDLE_DCLICK
EVT_HEADER_RESIZING
EVT_HEADER_RIGHT_CLICK
EVT_HEADER_RIGHT_DCLICK
EVT_HEADER_SEPARATOR_DCLICK
EVT_HELP
EVT_HELP_RANGE
EVT_HIBERNATE
EVT_HOTKEY
EVT_ICONIZE
EVT_IDLE
EVT_INIT_DIALOG
EVT_JOYSTICK_EVENTS
EVT_JOY_BUTTON_DOWN
EVT_JOY_BUTTON_UP
EVT_JOY_MOVE
EVT_JOY_ZMOVE
EVT_KEY_DOWN
EVT_KEY_UP
EVT_KILL_FOCUS
EVT_LEAVE_WINDOW
EVT_LEFT_DCLICK
EVT_LEFT_DOWN
EVT_LEFT_UP
EVT_LISTBOOK_PAGE_CHANGED
EVT_LISTBOOK_PAGE_CHANGING
EVT_LISTBOX
EVT_LISTBOX_DCLICK
EVT_LIST_BEGIN_DRAG
EVT_LIST_BEGIN_LABEL_EDIT
EVT_LIST_BEGIN_RDRAG
EVT_LIST_CACHE_HINT
EVT_LIST_COL_BEGIN_DRAG
EVT_LIST_COL_CLICK
EVT_LIST_COL_DRAGGING
EVT_LIST_COL_END_DRAG
EVT_LIST_COL_RIGHT_CLICK
EVT_LIST_DELETE_ALL_ITEMS
EVT_LIST_DELETE_ITEM
EVT_LIST_END_LABEL_EDIT
EVT_LIST_INSERT_ITEM
EVT_LIST_ITEM_ACTIVATED
EVT_LIST_ITEM_DESELECTED
EVT_LIST_ITEM_FOCUSED
EVT_LIST_ITEM_MIDDLE_CLICK
EVT_LIST_ITEM_RIGHT_CLICK
EVT_LIST_ITEM_SELECTED
EVT_LIST_KEY_DOWN
EVT_MAXIMIZE
EVT_MENU
EVT_MENU_CLOSE
EVT_MENU_HIGHLIGHT
EVT_MENU_HIGHLIGHT_ALL
EVT_MENU_OPEN
EVT_MENU_RANGE
EVT_MIDDLE_DCLICK
EVT_MIDDLE_DOWN
EVT_MIDDLE_UP
EVT_MOTION
EVT_MOUSEWHEEL
EVT_MOUSE_AUX1_DCLICK
EVT_MOUSE_AUX1_DOWN
EVT_MOUSE_AUX1_UP
EVT_MOUSE_AUX2_DCLICK
EVT_MOUSE_AUX2_DOWN
EVT_MOUSE_AUX2_UP
EVT_MOUSE_CAPTURE_CHANGED
EVT_MOUSE_CAPTURE_LOST
EVT_MOUSE_EVENTS
EVT_MOVE
EVT_MOVE_END
EVT_MOVE_START
EVT_MOVING
EVT_NAVIGATION_KEY
EVT_NC_PAINT
EVT_NOTEBOOK_PAGE_CHANGED
EVT_NOTEBOOK_PAGE_CHANGING
EVT_PAINT
EVT_PALETTE_CHANGED
EVT_POWER_RESUME
EVT_POWER_SUSPENDED
EVT_POWER_SUSPENDING
EVT_POWER_SUSPEND_CANCEL
EVT_QUERY_END_SESSION
EVT_QUERY_NEW_PALETTE
EVT_RADIOBOX
EVT_RADIOBUTTON
EVT_RIGHT_DCLICK
EVT_RIGHT_DOWN
EVT_RIGHT_UP
EVT_SCROLL
EVT_SCROLLBAR
EVT_SCROLLWIN
EVT_SCROLLWIN_BOTTOM
EVT_SCROLLWIN_LINEDOWN
EVT_SCROLLWIN_LINEUP
EVT_SCROLLWIN_PAGEDOWN
EVT_SCROLLWIN_PAGEUP
EVT_SCROLLWIN_THUMBRELEASE
EVT_SCROLLWIN_THUMBTRACK
EVT_SCROLLWIN_TOP
EVT_SCROLL_BOTTOM
EVT_SCROLL_CHANGED
EVT_SCROLL_ENDSCROLL
EVT_SCROLL_LINEDOWN
EVT_SCROLL_LINEUP
EVT_SCROLL_PAGEDOWN
EVT_SCROLL_PAGEUP
EVT_SCROLL_THUMBRELEASE
EVT_SCROLL_THUMBTRACK
EVT_SCROLL_TOP
EVT_SEARCHCTRL_CANCEL_BTN
EVT_SEARCHCTRL_SEARCH_BTN
EVT_SET_CURSOR
EVT_SET_FOCUS
EVT_SHOW
EVT_SIZE
EVT_SIZING
EVT_SLIDER
EVT_SPIN
EVT_SPINCTRL
EVT_SPINCTRLDOUBLE
EVT_SPIN_DOWN
EVT_SPIN_UP
EVT_SPLITTER_DCLICK
EVT_SPLITTER_DOUBLECLICKED
EVT_SPLITTER_SASH_POS_CHANGED
EVT_SPLITTER_SASH_POS_CHANGING
EVT_SPLITTER_UNSPLIT
EVT_SYS_COLOUR_CHANGED
EVT_TEXT
EVT_TEXT_COPY
EVT_TEXT_CUT
EVT_TEXT_ENTER
EVT_TEXT_MAXLEN
EVT_TEXT_PASTE
EVT_TEXT_URL
EVT_THREAD
EVT_TIMER
EVT_TOGGLEBUTTON
EVT_TOOL
EVT_TOOLBOOK_PAGE_CHANGED
EVT_TOOLBOOK_PAGE_CHANGING
EVT_TOOL_DROPDOWN
EVT_TOOL_ENTER
EVT_TOOL_RANGE
EVT_TOOL_RCLICKED
EVT_TOOL_RCLICKED_RANGE
EVT_TREEBOOK_NODE_COLLAPSED
EVT_TREEBOOK_NODE_EXPANDED
EVT_TREEBOOK_PAGE_CHANGED
EVT_TREEBOOK_PAGE_CHANGING
EVT_TREE_BEGIN_DRAG
EVT_TREE_BEGIN_LABEL_EDIT
EVT_TREE_BEGIN_RDRAG
EVT_TREE_DELETE_ITEM
EVT_TREE_END_DRAG
EVT_TREE_END_LABEL_EDIT
EVT_TREE_GET_INFO
EVT_TREE_ITEM_ACTIVATED
EVT_TREE_ITEM_COLLAPSED
EVT_TREE_ITEM_COLLAPSING
EVT_TREE_ITEM_EXPANDED
EVT_TREE_ITEM_EXPANDING
EVT_TREE_ITEM_GETTOOLTIP
EVT_TREE_ITEM_MENU
EVT_TREE_ITEM_MIDDLE_CLICK
EVT_TREE_ITEM_RIGHT_CLICK
EVT_TREE_KEY_DOWN
EVT_TREE_SEL_CHANGED
EVT_TREE_SEL_CHANGING
EVT_TREE_SET_INFO
EVT_TREE_STATE_IMAGE_CLICK
EVT_UPDATE_UI
EVT_UPDATE_UI_RANGE
EVT_VLBOX
EVT_WINDOW_CREATE
EVT_WINDOW_DESTROY
EVT_WINDOW_MODAL_DIALOG_CLOSED

如果直接运行上面的Bind程序,会提示不存在OnAbout这个attribute。还需要在Class中声明self.OnAbout方法:

def OnAbout(self, event):  
...

这里的event参数是wx.Event的子类的一个实例。

event发生的时候,method就会被执行。默认情况下,这个method会处理event,并且当callback完成之后,event也会停止。但是在一些结构化的事件处理器event handlers中,我们可以使用event.Skip()来跳过一个event。例如:

def OnButtonClick(self, event):  
if (some_condition):
do_something()
else:
event.Skip()

def OnEvent(self, event):
...

当一个点击按钮的事件发生时,OnButtonClick会被调用。如果some_condition为真,我们就会do_something()。否则我们就会让其它的event handler来处理这个事件。
现在来看看我们的程序:

#-*- coding: utf-8 -*-
import wx

class MainWindow(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent,title= title,size=(400,300))
self.contrl = wx.TextCtrl(self,style=wx.TE_MULTILINE)
self.CreateStatusBar()

#设置菜单
filemenu = wx.Menu()
#wx.ID_ABOUT 和 wx.ID_EXIT 是wxWidgets提供标准ID
#menuAbout = filemenu.Append(wx.ID_ABOUT,"&About","Information about this program")
menuAbout = filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
filemenu.AppendSeparator()
#menuExit = filemenu.Append(wx.ID_EXIT,"E&xit","Terminate the program")
menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
#创见菜单栏
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File")
self.SetMenuBar(menuBar)

#设置events
self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
self.Bind(wx.EVT_MENU, self.OnExit, menuExit)

self.Show(True)

def OnAbout(self,e):
#创建一个自带"OK"按钮的对话框。wx.OK是wxWidgets提供的标准ID
dlg = wx.MessageDialog(self,"A Small text Edior","About Sample Editor",wx.OK)
dlg.ShowModal()#显示对话框
dlg.Destroy() #当结束之后关闭对话框

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

app = wx.App(False)
frame = MainWindow(None,title="A Small Editor")
app.MainLoop()

注意:

wx.MessageDialog( self, "A small editor in wxPython", "About Sample Editor", wx.OK)

在这个例子中,我们可以忽略IDwxWidget会自动使用一个默认的ID(就像我们指定了wx.ID_ANY一样)。

wx.MessageDialog( self, "A small editor in wxPython", "About Sample Editor")  

对话Dialogs
当然,一个文本编辑器不能够没有打开或保存文档的功能——这些功能是由对话来实现的。一般对话由底层平台提供,这样你的应用程序看上去就像是一个原生程序。在本例中,对话由MainWindowOnOpen方法来实施:

     def OnOpen(self,e):
""" Open a file"""
self.dirname = ''
dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN)
if dlg.ShowModal() == wx.ID_OK:
self.filename = dlg.GetFilename()
self.dirname = dlg.GetDirectory()
f = open(os.path.join(self.dirname, self.filename), 'r')
self.control.SetValue(f.read())
f.close()
dlg.Destroy()

解释:

  • 首先,我们通过调用适当的构造函数来创建对话
  • 然后,我们调用ShowModal打开对话框-Modal的意思是,在用户点击OKCancel之前,不能做任何的操作。
  • ShowModal的返回值是一个被点击按钮的ID, 如果用户点击了OK按钮,程序就读取文件

现在,你可以向菜单中添加相应的条目,并把它链接到OnOpen方法。如果你遇到了问题,请向下滚动页面,查阅下文的完整代码。
扩展功能
当然,目前这个程序还远不是一个合格的文本编辑器。但是,添加其它的功能并不比我们刚才所完成的内容更难,你可以从wxPython提供的Demo获取灵感(点此下载Demo,选择版本后,下载wxPython-demo-x.x.x文件):

  • Drag and Drop.(拖放)
  • MDI
  • Tab view/multiple files(选项卡视图/多文件)
  • Find/Replace dialog(查找/替换对话框)
  • Print dialog (Printing)(打印对话框(印刷))
  • Macro-commands in python( using the eval function)(Python中的宏命令(使用eval函数))
  • etc …(等等…)