[祖传代码] 我在python3下用wxpython作GUI(1)先来做一个有菜单栏的小应用

我想学些python GUI的编程,希望通过例子了解一下wxpython,于是就根据官方文档 https://wiki.wxpython.org/Getting Started 模仿写了下面的例子。如果还想查看更多官方文档,可以参考:https://wiki.wxpython.org/。

安装wxpython

:: windows 命令行下执行下面的命令,其中 U 表示安装并升级
pip install -U wxpython

检查wx的版本

import wx
wx.version()

我的环境:

  • win7
  • 4.0.6 msw (phoenix) wxWidgets 3.0.5’
  • python 3.7.1

第一个例子

什么都不做,就是展示一个空窗口

# coding = utf-8
# https://wiki.wxpython.org/Getting%20Started
import wx

if __name__=="__main__":
    # 所有用 wxpython 编写的小程序都需要一个wx.App作为载体。
    myApp = wx.App(False) 
    # The "False" parameter means "don't redirect stdout and stderr to a window".这个是什么意思,还要试一试。

    # 这里创建一个顶层(top-level)的框架,作为应用显示的框架。一般要自己根据自己需要的功能,添加组件实现一个Frame
    mainFrame = wx.Frame(parent= None, id = wx.ID_ANY, title="测试小程序")
    # 这里需要Show一下,是因为 Frame 里面没东西,默认不显示。
    mainFrame.Show(True)    # mainFrame.Show() 也可以,

    # 启动APP的事件循环系统,等待处理事件
    myApp.MainLoop()

在这里插入图片描述
官方文档说5句话就可以写一个完整的GUI小应用:
1、import wx :导入wxpython
2、myApp = wx.App(False) : 新建一个应用
3、mainFrame = wx.Frame(…):建立一个顶层框架
4、mainFrame.Show():展示这个顶层框架
5、myApp.MainLoop():进入应用循环,等待处理事件

第二个例子

第一个例子的应用太单调,给它加点料:菜单栏、状态栏,官方文档中还有加一个文本框,用来显示文本文件的内容,这里就跟着官方的节奏走下去。

先让它看起来像个应用

这个例子和第一个例子有一个很大的不同,我们自己定义一个继承自Frame的框架MyFrame类,并在框架中添加一些组件。

# coding = utf-8
# https://wiki.wxpython.org/Getting%20Started
import wx

class MyFrame(wx.Frame):
    # MyFrame 继承 wx.Frame类,传进来的参数,需要传递给父类进行初始化。
    def __init__(self, *args,**kw):
        super().__init__(*args,**kw) 
        self.Show(True)

        # 留一个框架的引用,方便后续使用(CreateMenuBar里就用到了)
        self.theFrame = self

        # 创建一个菜单栏
        self.menuBar = self.CreateMenuBar()

        # 创建一个文本编辑区
        self.textContent = wx.TextCtrl(self,style = wx.TE_MULTILINE) # 文本控制窗口,多行模式

        # 创建一个状态栏
        self.statusBar = self.CreateStatusBar()
        pass

    def CreateMenuBar(self):
    	# 创建一个菜单栏
        menuBar = wx.MenuBar()

        # 创建一个“文件”菜单
        fileMenu = wx.Menu()
        fileMenu.Append(wx.ID_ANY,  "打开",   "打开文件")
        fileMenu.Append(wx.ID_ANY,  "保存",   "保存文件")
        fileMenu.AppendSeparator()
        exitItem = fileMenu.Append(wx.ID_EXIT, "退出",   "退出")
        self.theFrame.Bind(wx.EVT_MENU, self.OnExit, exitItem) 
        # 上面这里:Bind 将一个对象和一个事件绑定在一起,当 exitItem 这个对象
        # 发生 wx.EVT_MENU 这个事件时,就会调用 self.OnExit 这个动作来响应。
        
        # 添加一条分割线
        fileMenu.AppendSeparator()
        
        ## 在“文件”菜单中创建一个二级菜单
        showMenu= wx.Menu()
        showMenu.Append(wx.ID_ANY,"新功能")
        fileMenu.AppendMenu(wx.ID_ANY,"二级菜单",showMenu) 
        
		# 创建一个“帮助”菜单
        helpMenu = wx.Menu()
        helpItem = helpMenu.Append(wx.ID_ANY,  "帮助信息", "")
        helpMenu.AppendSeparator()
        aboutItem = helpMenu.Append(wx.ID_ABOUT,  "应用信息", "")
        self.theFrame.Bind(wx.EVT_MENU,self.OnAbout,aboutItem)

		# 将两个菜单添加到菜单栏
        menuBar.Append(fileMenu, "文件")
        menuBar.Append(helpMenu, "帮助")
        # 这里用到了程序刚开始定义的顶层框架自身的引用。
        self.theFrame.SetMenuBar(menuBar)
        return menuBar
        pass

    def OnAbout(self,event):
        # 从文件读出软件信息,并显示
        message = '软件名称:测试软件\n联系方式: somebody@somesite.com\n版本:0.0.1'
        msgBox = wx.MessageBox(message,"关于此软件")
        pass

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

if __name__=="__main__":
    # 所有用 wxpython 编写的小程序都需要一个wx.App作为载体。
    myApp = wx.App(False)

    # 实例化一个自己的框架,窗口名称是“测试小程序”,窗口大小是600x400
    mainFrame = MyFrame(parent= None, title="测试小程序",size=(600,400))

    # 启动APP的事件循环系统,等待处理事件
    myApp.MainLoop()

在这里插入图片描述
上面的例子中创建了一个菜单栏、一个文本框,一个状态栏。菜单栏中创建了两个菜单、若干菜单项、将菜单项和响应事件函数进行了绑定、创建了一个二级菜单、将菜单对象和响应事件的函数进行了绑定、定义了响应函数。这个应用只是个样子,啥功能都没,继续扩充它的功能。

给菜单中的“打开”、“保存”添加响应函数

首先添加一个响应“打开”菜单的函数:OnOpen()

    def OnOpen(self,event):
        self.dirname = ""
        dlg = wx.FileDialog(self,"选择文件", self.dirname,"","*.*",wx.FD_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',encoding="utf-8")
            self.textContent.SetValue(f.read())
            f.close()
            self.theFrame.Title = self.AppName +" "+self.filename
        dlg.Destroy()

这里用到了一个 wx.FileDialog 对话框,可以比较方便选择文件。类似的,添加一个OnSave()函数

    def OnSave(self,event):
        if self.filename == "":
            # 这里是还没有打开文件,直接要保存。提示选择文件,并保存
            dlg = wx.FileDialog(self, "选择文件", self.dirname, "", "*.*", wx.FD_SAVE)
            if dlg.ShowModal() == wx.ID_OK:
                self.filename = dlg.GetFilename()
                self.dirname = dlg.GetDirectory()
                f = open(os.path.join(self.dirname, self.filename), 'w', encoding="utf-8")
                f.write(self.textContent.GetValue())
                f.close()
                self.theFrame.Title = self.AppName + " " + self.filename
            dlg.Destroy()
        else:
            # 已经打开了文件,提示是否保存
            dlg = wx.MessageDialog(self,"是否保存文件到 "+os.path.join(self.dirname,self.filename)+" ?", \
                                   "保存文件", style= wx.CANCEL|wx.OK)
            if dlg.ShowModal() == wx.OK:
                f = open(os.path.join(self.dirname,self.filename),'w',encoding="utf-8")
                f.write(self.textContent.GetValue())
                f.close()
            dlg.Destroy()

由于要保存的文件并不是一个已经打开的文件,对于这种情况,就让用户选择(创建)要保存的文件,再进行报存。如果是已经打开的文件,则提示用户是否确认要保存。对于第二种情况,如果能知道文件内容是否有修改,如果有修改在提示保存,这样更好。(看看有啥办法可以知道文本内容和文本编辑区的内容是否一致?)

因为要保存文件的时候要分情况判断,要使用到一个 self.filename 成员变量,所以再添加一个初始化类似参数的函数:

    def __initMembers(self):
        self.dirname = ""
        self.filename = ""
        self.AppName=self.Title
        # 留一个框架的索引,方便后续引用,也可以不用这样,直接用self
        self.theFrame = self

保存文件
在这里插入图片描述
其他类似“新建”,“另存为”的功能和“打开”,“保存”类似。下面这段参考代码的意义不大:

# coding = gbk
# https://wiki.wxpython.org/Getting%20Started
import wx
import os

class MyFrame(wx.Frame):
    # MyFrame 继承 wx.Frame类,传进来的参数,需要传递给父类进行初始化。
    def __init__(self, *args,**kw):
        super().__init__(*args,**kw) # 窗口大小600x400,
        self.Show(True)

        # 初始化一些成员变量
        self.__initMembers()

        # 创建一个菜单栏
        self.menuBar = self.CreateMenuBar()

        # 创建一个文本编辑区
        self.textContent = wx.TextCtrl(self,style = wx.TE_MULTILINE) # 文本控制窗口,多行模式

        # 创建一个状态栏
        self.statusBar = self.CreateStatusBar()


    def __initMembers(self):
        self.dirname = ""
        self.filename = ""
        self.AppName=self.Title
        # 留一个框架的索引,方便后续引用,也可以不用这样,直接用self
        self.theFrame = self


    def CreateMenuBar(self):
        menuBar = wx.MenuBar()

        # 创建一个菜单
        fileMenu = wx.Menu()
        newfileItem = fileMenu.Append(wx.ID_ANY,"新建","新建文件")
        self.Bind(wx.EVT_MENU,self.OnNewFile,newfileItem)
        openItem = fileMenu.Append(wx.ID_ANY,  "打开",   "打开文件")
        self.theFrame.Bind(wx.EVT_MENU,self.OnOpen,openItem)
        saveItem = fileMenu.Append(wx.ID_ANY,  "保存",   "保存文件")
        self.theFrame.Bind(wx.EVT_MENU, self.OnSave, saveItem)
        saveasItem = fileMenu.Append(wx.ID_ANY, "另存为", "另存文件")
        self.theFrame.Bind(wx.EVT_MENU, self.OnSaveAs, saveasItem)
        fileMenu.AppendSeparator()
        exitItem = fileMenu.Append(wx.ID_EXIT, "退出",   "退出")
        self.theFrame.Bind(wx.EVT_MENU, self.OnExit, exitItem)
        fileMenu.AppendSeparator()

        ## 在“文件”菜单中创建一个二级菜单
        showMenu= wx.Menu()
        showMenu.Append(wx.ID_ANY,"新功能")
        fileMenu.AppendMenu(wx.ID_ANY,"二级菜单",showMenu) # Todo:这有一个警告,要看一下怎么解决。

        helpMenu = wx.Menu()
        helpItem = helpMenu.Append(wx.ID_ANY,  "帮助信息", "")
        helpMenu.AppendSeparator()
        aboutItem = helpMenu.Append(wx.ID_ABOUT,  "应用信息", "")
        self.theFrame.Bind(wx.EVT_MENU,self.OnAbout,aboutItem)

        menuBar.Append(fileMenu, "文件")
        menuBar.Append(helpMenu, "帮助")
        self.theFrame.SetMenuBar(menuBar)
        return menuBar
        pass

    def OnAbout(self,event):
        # 从文件读出软件信息,并显示
        message = '软件名称:测试软件\n联系方式: somebody@somesite.com\n版本:0.0.1'
        msgBox = wx.MessageBox(message,"关于此软件")

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

    def OnNewFile(self,event):
        # 文件名清空,因为还没保存
        self.filename=""
        # 编辑区清空
        self.textContent.SetValue("")
        self.theFrame.Title = self.AppName

    def OnOpen(self,event):
        self.dirname = ""
        dlg = wx.FileDialog(self,"选择文件", self.dirname,"","*.*",wx.FD_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',encoding="utf-8")
            self.textContent.SetValue(f.read())
            f.close()
            self.theFrame.Title = self.AppName +" "+self.filename
        dlg.Destroy()

    def OnSave(self,event):
        if self.filename == "":
            # 这里是还没有打开文件,直接要保存。提示选择文件,并保存
            dlg = wx.FileDialog(self, "选择文件", self.dirname, "", "*.*", wx.FD_SAVE)
            if dlg.ShowModal() == wx.ID_OK:
                self.filename = dlg.GetFilename()
                self.dirname = dlg.GetDirectory()
                f = open(os.path.join(self.dirname, self.filename), 'w', encoding="utf-8")
                f.write(self.textContent.GetValue())
                f.close()
                self.theFrame.Title = self.AppName + " " + self.filename
            dlg.Destroy()
        else:
            # 已经打开了文件,提示是否保存
            dlg = wx.MessageDialog(self,"是否保存文件到 "+os.path.join(self.dirname,self.filename)+" ?", \
                                   "保存文件", style= wx.CANCEL|wx.OK)
            if dlg.ShowModal() == wx.OK:
                f = open(os.path.join(self.dirname,self.filename),'w',encoding="utf-8")
                f.write(self.textContent.GetValue())
                f.close()
            dlg.Destroy()

    def OnSaveAs(self,event):
        # 清空文件名,调用
        self.filename= ""
        self.OnSave(event=None)

if __name__=="__main__":
    # 所有用 wxpython 编写的小程序都需要一个wx.App作为载体。
    myApp = wx.App(False) # The "False" parameter means "don't redirect stdout and stderr to a window". 这个是什么意思,还要试一试。

    # 实例化一个自己的框架
    mainFrame = MyFrame(parent= None, title="测试小程序",size=(600,400))

    # 启动APP的事件循环系统,等待处理事件
    myApp.MainLoop()
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值