`
sillycat
  • 浏览: 2541811 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

wxpython入门(三)重构、类

阅读更多
wxpython入门(三)重构、类

参考书籍
http://wiki.woodpecker.org.cn/moin/WxPythonInAction

第四章 用PyCrust使得wxPython更易处理
如何与wxPython程序交互

例4.1 简单的Python交互式会话
C:\Documents and Settings\sillycat>python
ActivePython 2.6.4.10 (ActiveState Software Inc.) based on
Python 2.6.4 (r264:75706, Jan 22 2010, 16:41:54) [MSC v.1500 32 bit (Intel)] on
win32Type "help", "copyright", "credits" or "license" for more information.
>>> 2 + 2
4
>>> 7 * 6
42

PyCrust配置了标准的Python shell
图形化的python工具,如IDLE看起来很像命令行Python shell,但是它有额外的特性如调用提示。PyCrust的目的之一就是提供所有现存的Python shell的特性。

如何将PyCrust应用于wxPython应用程序
在我的测试目录下,新建py文件WxPythonWindow.py,建立一个空的窗口:
import wx

class Frame(wx.Frame):
    pass

class App(wx.App):

    def OnInit(self):
        self.frame = Frame(parent=None, id=-1, title='Spare')
        self.frame.Show()
        self.SetTopWindow(self.frame)
        return True

if __name__ == '__main__':
    app = App()
    app.MainLoop()

在相同目录下,建立PyWrap.py文件:
__author__ = "Patrick K. O'Brien  pobrien@orbtech.com "
__cvsid__ = "$Id: PyCrust.txt,v 1.15 2005/03/29 23:39:27 robind Exp $"
__revision__ = "$Revision: 1.15 $"[11:-2]

import os
import sys
import wx
from wx.py.crust import CrustFrame

def wrap(app):
    wx.InitAllImageHandlers()
    frame = CrustFrame()
    frame.SetSize((750, 525))
    frame.Show(True)
    frame.shell.interp.locals['app'] = app
    app.MainLoop()
def main(modulename=None):
    sys.path.insert(0, os.curdir)
    if not modulename:
        if len(sys.argv) < 2:
            print "Please specify a module name."
            raise SystemExit
        modulename = sys.argv[1]
        if modulename.endswith('.py'):
            modulename = modulename[:-3]
    module = __import__(modulename)
    # Find the App class.
    App = None
    d = module.__dict__
    for item in d.keys():
        try:
            if issubclass(d[item], wx.App):
                App = d[item]
        except (NameError, TypeError):
            pass
    if App is None:
        print "No App class was found."
        raise SystemExit
    app = App()
    wrap(app)
if __name__ == '__main__':
    main()

执行命令:
D:\work\easyfinance\finance\com\sillycat\finance>python PyWrap.py WxPythonWindow.py
打开了,本来的Spare窗口,和PyCrust窗口,然后在PyCrust窗口输入如下命令,改变spare的属性和状态,在PyCrust的命令行下执行的过程如下:
import wx
app.frame.panel = wx.Panel(parent=app.frame)
app.frame.panel.SetBackgroundColour('White')
True
app.frame.panel.Refresh()
#改变了背景为白色
app.frame.StatusBar = app.frame.CreateStatusBar(number=3)
app.frame.StatusBar.SetStatusText("left",0)
app.frame.StatusBar.SetStatusText("center",1)
app.frame.StatusBar.SetStatusText("right",2)
#增加了状态栏
app.frame.MenuBar = wx.MenuBar()
menu = wx.Menu()
app.frame.MenuBar.Append(menu,"Primary")
True
app.frame.SetMenuBar(app.frame.MenuBar)
menu.Append(wx.NewId(),"One","first menu item")
<wx._core.MenuItem; proxy of <Swig Object of type 'wxMenuItem *' at 0x1ca1b28> >
menu.Append(wx.NewId(),"Two","second menu item")
<wx._core.MenuItem; proxy of <Swig Object of type 'wxMenuItem *' at 0x1d08de8> >
#增加了菜单

在平时我们编写程序时,我们可以利用到PyCrust里面的模块,比如shell,filling等,但是我目前用不到。

第五章 绘制蓝图

重构帮助我们改进代码

examples:

import wx
class RefactorExample(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, 'Refactor Example',size=(340, 200))
        panel = wx.Panel(self, -1)
        panel.SetBackgroundColour("White")
        prevButton = wx.Button(panel, -1, "PREV", pos=(80, 0))
        self.Bind(wx.EVT_BUTTON, self.OnPrev, prevButton)
        nextButton = wx.Button(panel, -1, "NEXT", pos=(160, 0))
        self.Bind(wx.EVT_BUTTON, self.OnNext, nextButton)
       
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

        menuBar = wx.MenuBar()
       
        menu1 = wx.Menu()
        openMenuItem = menu1.Append(-1, "open", "Open")
        self.Bind(wx.EVT_MENU, self.OnOpen, openMenuItem)
        quitMenuItem = menu1.Append(-1, "quit", "Quit")
        self.Bind(wx.EVT_MENU, self.OnCloseWindow, quitMenuItem)
        menuBar.Append(menu1, "menu1")
       
        menu2 = wx.Menu()
        copyItem = menu2.Append(-1, "copy", "Copy")
        self.Bind(wx.EVT_MENU, self.OnCopy, copyItem)
        cutItem = menu2.Append(-1, "cut", "Cut")
        self.Bind(wx.EVT_MENU, self.OnCut, cutItem)
        pasteItem = menu2.Append(-1, "Paste", "Paste")
        self.Bind(wx.EVT_MENU, self.OnPaste, pasteItem)
        menuBar.Append(menu2, "menu2")
       
        self.SetMenuBar(menuBar)

        static = wx.StaticText(panel,wx.NewId(),"First Name",pos=(10, 50))
        static.SetBackgroundColour("White")
        text = wx.TextCtrl(panel, wx.NewId(),"",size=(100, -1),pos=(80, 50))

        static2 = wx.StaticText(panel, wx.NewId(), "Last Name",pos=(10, 80))
        static2.SetBackgroundColour("White")
        text2 = wx.TextCtrl(panel, wx.NewId(), "", size=(100, -1),pos=(80, 80))

        firstButton = wx.Button(panel, -1, "FIRST")
        self.Bind(wx.EVT_BUTTON,self.OnFirst, firstButton)

        menu2.AppendSeparator()
        optItem = menu2.Append(-1, "display", "Display Options")
        self.Bind(wx.EVT_MENU, self.OnOptions, optItem)

        lastButton = wx.Button(panel, -1, "LAST", pos=(240, 0))
        self.Bind(wx.EVT_BUTTON, self.OnLast, lastButton)
    # Just grouping the empty event handlers together
    def OnPrev(self, event): pass
    def OnNext(self, event): pass
    def OnLast(self, event): pass
    def OnFirst(self, event): pass
    def OnOpen(self, event): pass
    def OnCopy(self, event): pass
    def OnCut(self, event): pass
    def OnPaste(self, event): pass
    def OnOptions(self, event): pass

    def OnCloseWindow(self, event):
        self.Destroy()

if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = RefactorExample(parent=None, id=-1)
    frame.Show()
    app.MainLoop()

重构注意
example 按钮栏作为一个单独的方法:
def createButtonBar(self):
        firstButton = wx.Button(panel, -1, "FIRST")
        self.Bind(wx.EVT_BUTTON, self.OnFirst, firstButton)

        prevButton = wx.Button(panel, -1, "PREV", pos=(80, 0))
        self.Bind(wx.EVT_BUTTON, , self.OnPrev, prevButton)

        nextButton = wx.Button(panel, -1, "NEXT", pos=(160, 0))
        self.Bind(wx.EVT_BUTTON, self.OnNext, nextButton)

        lastButton = wx.Button(panel, -1, "LAST", pos=(240, 0))
        self.Bind(wx.EVT_BUTTON, self.OnLast, lastButton)

提炼公用方法,examples:
def createButtonBar(self, panel):
        self.buildOneButton(panel, "First", self.OnFirst)
        self.buildOneButton(panel, "PREV", self.OnPrev, (80, 0))
        self.buildOneButton(panel, "NEXT", self.OnNext, (160, 0))
        self.buildOneButton(panel, "Last", self.OnLast, (240, 0))

def buildOneButton(self, parent, label, handler, pos=(0,0)):
        button = wx.Button(parent, -1, label, pos)
        self.Bind(wx.EVT_BUTTON, handler, button)
        return button

让方法和数据分离,example:
def buttonData(self):
        return (("First", self.OnFirst),
                ("   PREV", self.OnPrev),
                ("NEXT   ", self.OnNext),
                ("Last", self.OnLast))

def createButtonBar(self, panel, yPos=0):
        xPos = 0
        for eachLabel, eachHandler in self.buttonData():
                pos = (xPos, yPos)
                button = self.buildOneButton(panel, eachLabel, eachHandler, pos)
                xPos += button.GetSize().width

def buildOneButton(self, parent, label, handler, pos=(0,0)):
        button = wx.Button(parent, -1, label, pos)
        self.Bind(wx.EVT_BUTTON, handler, button)
        return button

最后优化完成的代码,的确不同凡响examples:
import wx
class RefactorExample(wx.Frame):
        def __init__(self, parent, id):
                wx.Frame.__init__(self, parent, id, 'Refactor Example',size=(340, 200))
                panel = wx.Panel(self, -1)
                panel.SetBackgroundColour("White")
                self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
                self.createMenuBar() #简化的init方法
                self.createButtonBar(panel)
                self.createTextFields(panel)

        def menuData(self): #菜单数据
                return (("&File",
                        ("&Open", "Open in status bar", self.OnOpen),
                        ("&Quit", "Quit", self.OnCloseWindow)),
                        ("&Edit",
                        ("&Copy", "Copy", self.OnCopy),
                        ("&Cut", "Cut", self.OnCut),
                        ("&Paste", "Paste", self.OnPaste),
                        ("", "", ""), #横线
                        ("&Options", "DisplayOptions", self.OnOptions)))
               
        def createMenuBar(self): #创建菜单
                menuBar = wx.MenuBar()
                for eachMenuData in self.menuData():
                        menuLabel = eachMenuData[0]
                        menuItems = eachMenuData[1:]
                        menuBar.Append(self.createMenu(menuItems), menuLabel)
                self.SetMenuBar(menuBar)

        def createMenu(self, menuData):
                menu = wx.Menu()
                for eachLabel, eachStatus, eachHandler in menuData:
                        if not eachLabel:
                                menu.AppendSeparator() #间隔横线
                                continue
                        menuItem = menu.Append(-1, eachLabel, eachStatus)
                        self.Bind(wx.EVT_MENU, eachHandler, menuItem)
                return menu

        def buttonData(self): #按钮栏数据
                return (("First", self.OnFirst),
                        ("<<PREV", self.OnPrev),
                        ("NEXT>>", self.OnNext),
                        ("Last", self.OnLast))
       
        def createButtonBar(self, panel, yPos = 0):#创建按钮
                xPos = 0
                for eachLabel, eachHandler in self.buttonData():
                        pos = (xPos, yPos)
                        button = self.buildOneButton(panel, eachLabel,eachHandler, pos)
                        xPos += button.GetSize().width

        def buildOneButton(self, parent, label, handler, pos=(0,0)):
                button = wx.Button(parent, -1, label, pos)
                self.Bind(wx.EVT_BUTTON, handler, button)
                return button

        def textFieldData(self): #文本数据
                return (("First Name", (10, 50)),
                        ("Last Name", (10, 80)))
       
        def createTextFields(self, panel):#创建文本
                for eachLabel, eachPos in self.textFieldData():
                        self.createCaptionedText(panel, eachLabel, eachPos)

        def createCaptionedText(self, panel, label, pos):
                static = wx.StaticText(panel, wx.NewId(), label, pos)
                static.SetBackgroundColour("White")
                textPos = (pos[0] + 75, pos[1])
                wx.TextCtrl(panel, wx.NewId(), "", size=(100, -1), pos=textPos)

        # 空的事件处理器放在一起
        def OnPrev(self, event): pass
        def OnNext(self, event): pass
        def OnLast(self, event): pass
        def OnFirst(self, event): pass
        def OnOpen(self, event): pass
        def OnCopy(self, event): pass
        def OnCut(self, event): pass
        def OnPaste(self, event): pass
        def OnOptions(self, event): pass
        def OnCloseWindow(self, event):
            self.Destroy()

if __name__ == '__main__':
        app = wx.PySimpleApp()
        frame = RefactorExample(parent=None, id=-1)
        frame.Show()
        app.MainLoop()

一个wxPython模型:PyGridTableBase
填充网格(没有使用模型),examples:

import wx
import wx.grid

class SimpleGrid(wx.grid.Grid):
        def __init__(self, parent):
                wx.grid.Grid.__init__(self, parent, -1)
                self.CreateGrid(9, 2)
                self.SetColLabelValue(0, "First")
                self.SetColLabelValue(1, "Last")
               
                self.SetRowLabelValue(0, "CF")
                self.SetCellValue(0, 0, "Bob")
                self.SetCellValue(0, 1, "Dernier")
               
                self.SetRowLabelValue(1, "2B")
                self.SetCellValue(1, 0, "Ryne")
                self.SetCellValue(1, 1, "Sandberg")
               
                self.SetRowLabelValue(2, "LF")
                self.SetCellValue(2, 0, "Gary")
                self.SetCellValue(2, 1, "Matthews")
               
                self.SetRowLabelValue(3, "1B")
                self.SetCellValue(3, 0, "Leon")
                self.SetCellValue(3, 1, "Durham")
               
                self.SetRowLabelValue(4, "RF")
                self.SetCellValue(4, 0, "Keith")
                self.SetCellValue(4, 1, "Moreland")
               
                self.SetRowLabelValue(5, "3B")
                self.SetCellValue(5, 0, "Ron")
                self.SetCellValue(5, 1, "Cey")
               
                self.SetRowLabelValue(6, "C")
                self.SetCellValue(6, 0, "Jody")
                self.SetCellValue(6, 1, "Davis")
               
                self.SetRowLabelValue(7, "SS")
                self.SetCellValue(7, 0, "Larry")
                self.SetCellValue(7, 1, "Bowa")
               
                self.SetRowLabelValue(8, "P")
                self.SetCellValue(8, 0, "Rick")
                self.SetCellValue(8, 1, "Sutcliffe")

class TestFrame(wx.Frame):
        def __init__(self, parent):
                wx.Frame.__init__(self, parent, -1, "A Grid",size=(275, 275))
                grid = SimpleGrid(self)

if __name__ == '__main__':
        app = wx.PySimpleApp()
        frame = TestFrame(None)
        frame.Show(True)
        app.MainLoop()

PyGridTableBase的方法
wx.grid.PyGridTableBase的必须的方法
1.GetNumberRows():返回一个表明grid中行数的整数
2.GetNumberCols():返回一个表明grid中列数的整数
3.IsEmptyCell(row, col):如果索引(row,col)所表示的单元是空的话,返回True
4.GetValue(row, col):返回显示在单元(row,col)中的值
5.SetValue(row, col,value):设置单元(row,col)中的值。如果你想要只读模式,你仍必须包含这个方法,但是你可以在该函数中使用pass

生成自PyGridTableBase模型的一个表,examples:
import wx
import wx.grid

class LineupTable(wx.grid.PyGridTableBase):
        data = (("CF", "Bob", "Dernier"), ("2B", "Ryne", "Sandberg"),
                ("LF", "Gary", "Matthews"), ("1B", "Leon", "Durham"),
                ("RF", "Keith", "Moreland"), ("3B", "Ron", "Cey"),
                ("C", "Jody", "Davis"), ("SS", "Larry", "Bowa"),
                ("P", "Rick", "Sutcliffe"))
        colLabels = ("Last", "First")
       
        def __init__(self):
                wx.grid.PyGridTableBase.__init__(self)
        def GetNumberRows(self):
                return len(self.data)
        def GetNumberCols(self):
                return len(self.data[0]) - 1
        def GetColLabelValue(self, col):
                return self.colLabels[col]
        def GetRowLabelValue(self, row):
                return self.data[row][0]
        def IsEmptyCell(self, row, col):
                return False
        def GetValue(self, row, col):
                return self.data[row][col + 1]
        def SetValue(self, row, col, value):
                pass
class SimpleGrid(wx.grid.Grid):
        def __init__(self, parent):
                wx.grid.Grid.__init__(self, parent, -1)
                self.SetTable(LineupTable()) #设置表
class TestFrame(wx.Frame):
        def __init__(self, parent):
                wx.Frame.__init__(self, parent, -1, "A Grid",size=(275, 275))
                grid = SimpleGrid(self)
if __name__ == '__main__':
        app = wx.PySimpleApp()
        frame = TestFrame(None)
        frame.Show(True)
        app.MainLoop()

二维表通用表
建立一个通用表文件generictable.py,同时在右键项目-----》Properties----->External Libraries里面,Add source folder,把当前py文件的路径加上,generictable.py文件内容如下:

import wx
import wx.grid

class GenericTable(wx.grid.PyGridTableBase):

    def __init__(self, data, rowLabels=None, colLabels=None):
        wx.grid.PyGridTableBase.__init__(self)
        self.data = data
        self.rowLabels = rowLabels
        self.colLabels = colLabels

    def GetNumberRows(self):
        return len(self.data)

    def GetNumberCols(self):
        return len(self.data[0])

    def GetColLabelValue(self, col):
        if self.colLabels:
            return self.colLabels[col]

    def GetRowLabelValue(self, row):
        if self.rowLabels:
            return self.rowLabels[row]

    def IsEmptyCell(self, row, col):
        return False

    def GetValue(self, row, col):
        return self.data[row][col]

    def SetValue(self, row, col, value):
        pass
显示表单的例子如下,examples:

import wx
import wx.grid
import generictable

data = (("Bob", "Dernier"), ("Ryne", "Sandberg"),
        ("Gary", "Matthews"), ("Leon", "Durham"),
        ("Keith", "Moreland"), ("Ron", "Cey"),
        ("Jody", "Davis"), ("Larry", "Bowa"),
        ("Rick", "Sutcliffe"))

colLabels = ("Last", "First")
rowLabels = ("CF", "2B", "LF", "1B", "RF", "3B", "C", "SS", "P")

class SimpleGrid(wx.grid.Grid):
    def __init__(self, parent):
        wx.grid.Grid.__init__(self, parent, -1)
        tableBase = generictable.GenericTable(data, rowLabels,
                colLabels)
        self.SetTable(tableBase)

class TestFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "A Grid",size=(275, 275))
        grid = SimpleGrid(self)

if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = TestFrame(None)
    frame.Show(True)
    app.MainLoop()

自定义模型
抽象的对象abstractmodel.py:
class AbstractModel(object):
        def __init__(self):
                self.listeners = []
        def addListener(self, listenerFunc):
                self.listeners.append(listenerFunc)
        def removeListener(self, listenerFunc):
                self.listeners.remove(listenerFunc)
        def update(self):
                for eachFunc in self.listeners:
                        eachFunc(self)
使用自定义对象的类examples:

import wx
import abstractmodel

class SimpleName(abstractmodel.AbstractModel):
    def __init__(self, first="", last=""):
        abstractmodel.AbstractModel.__init__(self)
        self.set(first, last)
    def set(self, first, last):
        self.first = first
        self.last = last
        self.update()   #1 更新
class ModelExample(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, 'Flintstones',size=(340, 200))
        panel = wx.Panel(self)
        panel.SetBackgroundColour("White")
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
        self.textFields = {}
        self.createTextFields(panel)
        #2 创建模型
        self.model = SimpleName()
        self.model.addListener(self.OnUpdate)
        self.createButtonBar(panel)
    def buttonData(self):
        return (("Fredify", self.OnFred),
                ("Wilmafy", self.OnWilma),
                ("Barnify", self.OnBarney),
                ("Bettify", self.OnBetty))
    def createButtonBar(self, panel, yPos = 0):
        xPos = 0
        for eachLabel, eachHandler in self.buttonData():
            pos = (xPos, yPos)
            button = self.buildOneButton(panel, eachLabel, eachHandler, pos)
            xPos += button.GetSize().width
    def buildOneButton(self, parent, label, handler, pos=(0,0)):
        button = wx.Button(parent, -1, label, pos)
        self.Bind(wx.EVT_BUTTON, handler, button)
        return button
    def textFieldData(self):
        return (("First Name", (10, 50)),("Last Name", (10, 80)))

    def createTextFields(self, panel):
        for eachLabel, eachPos in self.textFieldData():
            self.createCaptionedText(panel, eachLabel, eachPos)

    def createCaptionedText(self, panel, label, pos):
        static = wx.StaticText(panel, wx.NewId(), label, pos)
        static.SetBackgroundColour("White")
        textPos = (pos[0] + 75, pos[1])
        self.textFields[label] = wx.TextCtrl(panel, wx.NewId(),
                "", size=(100, -1), pos=textPos,style=wx.TE_READONLY)

    def OnUpdate(self, model): #3 设置文本域
        self.textFields["First Name"].SetValue(model.first)
        self.textFields["Last Name"].SetValue(model.last)
    #-------------------------------------------
    #4 响应按钮敲击的处理器
    def OnFred(self, event):
        self.model.set("Fred", "Flintstone")

    def OnBarney(self, event):
        self.model.set("Barney", "Rubble")

    def OnWilma(self, event):
        self.model.set("Wilma", "Flintstone")

    def OnBetty(self, event):
        self.model.set("Betty", "Rubble")
    #---------------------------------------------
    def OnCloseWindow(self, event):
        self.Destroy()

if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = ModelExample(parent=None, id=-1)
    frame.Show()
    app.MainLoop()

对GUI程序进行单元测试
暂时先略过
分享到:
评论

相关推荐

    Part1 wxPython入门

    ### wxPython入门知识点详解 #### 1. 欢迎来到wxPython - **简介**:wxPython是一种广泛使用的Python库,它允许开发者利用wxWidgets C++库来创建跨平台的图形用户界面(GUI)。wxPython是免费且开源的,支持...

    wxPython in Action 中文版

    第1部分“wxPython入门”中,通过“欢迎来到wxPython”章节,引导读者了解如何开始使用wxPython。最简单的空程序示例展示了如何导入wxPython库,创建应用程序和框架,并进入主事件循环。接着,逐步扩展这个基础程序...

    wxPython_GUI编程

    ### wxPython_GUI编程 #### 一、wxPython简介与入门 ...以上就是wxPython入门和一些基础知识的详细介绍。通过学习这些概念,开发者可以更好地掌握如何使用wxPython构建高效且用户友好的GUI应用程序。

    wxpython实战

    #### 一、wxPython入门概览 **1.1 开始wxPython** - **wxPython简介:** wxPython是一个用于Python的GUI开发工具包,它基于wxWidgets C++库,提供了丰富的组件来创建跨平台的应用程序。 - **目标读者:** 本书适合...

    wxpython-in-action-zh.pdf

    1. wxPython入门 - 开始wxPython:文档介绍了如何开始使用wxPython,包括导入wxPython库,了解应用程序和框架的工作方式。 - 创建最小的空的wxPython程序:这是入门wxPython的简单示例,通过创建wx.App的子类,...

    wxpython中文版

    ### wxPython基础入门 - **wxPython简介**:wxPython是一个开源的GUI工具包,它为Python提供了丰富的接口,用于开发跨平台的应用程序。它允许开发者使用Python语言,创建标准的GUI组件,如窗口、按钮、菜单等。 - *...

    wxPython实战(中文版)

    通过上述知识点,我们了解了从入门到进阶的各种方面,包括如何开始wxPython编程、构建基础应用程序、理解和使用事件机制以及如何利用PyCrust提高开发效率。这对于想要深入学习wxPython的开发者来说是非常宝贵的资源...

    Driscoll -- wxPython Recipes -- 2018.pdf

    通过以上内容可以看出,《wxPython Recipes》是一本非常实用的书籍,不仅适合初学者快速入门wxPython开发,也适合有一定经验的开发者深入研究高级主题。书中通过具体的案例来解决实际开发过程中遇到的问题,非常适合...

    Python+Qt5+Pycharm 界面设计指导.docx

    在GUI应用开发中,Python提供了多种库,如Tkinter、PyQt、wxPython等,其中PyQt5是基于Qt5库的Python绑定,允许Python开发者利用Qt5的强大功能来创建界面。 2. **PyCharm**:PyCharm是JetBrains公司开发的一款...

Global site tag (gtag.js) - Google Analytics