wxpython开发实例_wxPython实例代码(购物车)

wxPython是一个流行的跨平台GUI工具包。用这个就可以给程序做窗口界面了。

官方网站:www.wxpython.org

我这也没好好学,就整了个小项目的例子。把代码完整贴下面了,下次做界面的时候可以参考这改改。

文档结构

主要就是几个py文件。resources文件夹里是放资源原件的,也就两张图片

Cart

│ app_main.py

├─conf

│ settings.py

│ __init__.py

├─resources

│ bats.ico

│ dragon.jpg

└─ui

list_frame.py

list_grid_table.py

login_frame.py

my_frame.py

__init__.py

settings 文件

这里也没设置,不过把数据放这里了,主要是搞定做界面,就不连数据库了:

# 登录的用户名和密码

ACCOUNTS = {

'admin': {'pwd': 'admin'},

'root': {'pwd': '123456'},

'user': {'pwd': 'user123'},

}

# 商品列名

COLUMN_NAMES = ["商品编号", "商品类别", "商品中文名", "商品英文名"]

# 商品类别

CATEGORY = ["食品", "酒类", "男装", "女装", "童装"]

# 商品信息,商品信息有点少,最好多搞几十条

PRODUCTS = [

{'id': "001", 'category': "食品", 'name_cn': "薯片", 'name_en': "ShuPian"},

{'id': "002", 'category': "酒类", 'name_cn': "葡萄酒", 'name_en': "PuTaoJiu"},

{'id': "003", 'category': "男装", 'name_cn': "西装", 'name_en': "XiZhuang"},

{'id': "004", 'category': "女装", 'name_cn': "短裙", 'name_en': "DuanQun"},

{'id': "005", 'category': "童装", 'name_cn': "连衣裙", 'name_en': "LianYiQun"},

]

启动文件

通过启动文件,启动我们的项目,这里主要是调用创建一个登录窗口,然后进入主事件循环

import wx

from ui.login_frame import LoginFrame

from ui.list_frame import ListFrame

class App(wx.App):

"""启动模块"""

def OnInit(self):

"""创建窗口对象"""

frame = LoginFrame()

# frame = ListFrame() # 单独调试商品界面的时候,省的每次都要登录一下

frame.Show()

return True

if __name__ == '__main__':

app = App() # 实例化

app.MainLoop() # 进入主事件循环

窗口基类

先给所有的窗口定义个基类,把所有窗口共有的属性定义在这个基类里。之后各个窗口都基础这个类:

"""定义Frame窗口基类"""

import sys

import wx

class MyFrame(wx.Frame):

session = {} # 模拟Web的session,保留会话的数据

def __init__(self, title, size):

super().__init__(parent=None, title=title, size=size,

style=wx.DEFAULT_FRAME_STYLE ^ wx.MAXIMIZE_BOX)

# style是定义窗口风格,具体看官网。https://docs.wxpython.org/wx.Frame.html#wx-frame

# 上面的DEFAULT就是包含了下面所有的风格的:

# wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER |

# wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN

# 上面的例子是去掉了其中的一个。官网的例子是这样的:

# style = wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX) 去掉了2个来固定窗口大小

# 设置窗口居中

self.Center()

# 设置Frame窗口内容面板

self.contentpanel = wx.Panel(parent=self)

# 图标文件

ico = wx.Icon("resources/bats.ico", wx.BITMAP_TYPE_ICO)

# 设置图标

self.SetIcon(ico)

# 设定窗口大小,这里设置了相同的最大和最小值,也就是固定了窗口大小。

# 因为上面的窗口风格了保留了wx.RESIZE_BORDER,所以这里用另外一个放来来保证大小不可调整

# 这样做有一点不好,就是鼠标放在窗口边缘,会变成调整窗口大小的样子,但是拉不动窗口

self.SetSizeHints(size, size)

# 绑定关闭按钮的点击事件

self.Bind(wx.EVT_CLOSE, self.on_close)

def on_close(self, event):

# 退出系统

self.Destroy()

sys.exit()

这里设置固定窗口的大小不可调整,不过应该还是官网的方法更好吧。

另外还定义了窗口的图标,和关闭窗口的所调用的方法。

self.contentpanel = wx.Panel(parent=self) 这个属性在后面会一直使用

登录窗口

现在开始真正开始做窗口界面了,先做一个简单的登录界面:

"""登录窗口"""

import wx

from ui.my_frame import MyFrame

from ui.list_frame import ListFrame

from conf import settings

class LoginFrame(MyFrame):

accounts = settings.ACCOUNTS

def __init__(self):

super().__init__(title="用户登录", size=(340, 230))

# 创建界面中的控件

username_st = wx.StaticText(self.contentpanel, label="用户名:") # 输入框前面的提示标签

password_st = wx.StaticText(self.contentpanel, label="密码:")

self.username_txt = wx.TextCtrl(self.contentpanel) # 输入框

self.password_txt = wx.TextCtrl(self.contentpanel, style=wx.TE_PASSWORD)

# 创建FlexGrid布局对象

fgs = wx.FlexGridSizer(2, 2, 20, 20) # 2行2列,行间距20,列间距20

fgs.AddMany([

# 下面套用了3个分隔,垂直居中,水平靠右,固定的最小尺寸

(username_st, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE),

# 位置居中,尺寸是膨胀

(self.username_txt, 1, wx.CENTER | wx.EXPAND),

(password_st, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE),

(self.password_txt, 1, wx.CENTER | wx.EXPAND),

])

# 设置FlexGrid布局对象

fgs.AddGrowableRow(0, 1) # 第一个0是指第一行,权重1

fgs.AddGrowableRow(1, 1) # 第一个1是指第二行,权重也是1

# 上面一共就2行,用户名和密码,就是2行的空间是一样的

fgs.AddGrowableCol(0, 1) # 第一列,权重1,就是标签的内容

fgs.AddGrowableCol(1, 4) # 第二列,权重4,就是输入框,并且输入框是膨胀的应该会撑满

# 上面2列分成5分,第一列占1/5,第二列占4/5

# 创建按钮对象

ok_btn = wx.Button(parent=self.contentpanel, label="确定")

cancel_btn = wx.Button(parent=self.contentpanel, label="取消")

# 绑定按钮事件:事件类型,绑定的事件,绑定的按钮

self.Bind(wx.EVT_BUTTON, self.ok_btn_onclick, ok_btn)

self.Bind(wx.EVT_BUTTON, self.cancel_btn_onclick, cancel_btn)

# 创建水平Box布局对象,放上面的2个按钮

box_btn = wx.BoxSizer(wx.HORIZONTAL)

# 添加按钮控件:居中,四周都有边框,膨胀。border是设置边框的大小,实际效果没有框,但是占用空间

box_btn.Add(ok_btn, 1, wx.CENTER | wx.ALL | wx.EXPAND, border=10)

box_btn.Add(cancel_btn, 1, wx.CENTER | wx.ALL | wx.EXPAND, border=10)

# 创建垂直Box,把上面的fgs对象和box_btn对象都放进来

box_outer = wx.BoxSizer(wx.VERTICAL)

box_outer.Add(fgs, -1, wx.CENTER | wx.ALL | wx.EXPAND, border=25) # 权重是-1,就是不指定了

# (wx.ALL ^ wx.TOP)这里只加3面的边框,上面就不加了

box_outer.Add(box_btn, -1, wx.CENTER | (wx.ALL ^ wx.TOP) | wx.EXPAND, border=20)

# 上面全部设置完成了,下面是设置Frame窗口内容面板

self.contentpanel.SetSizer(box_outer) # self.contentpanel 是在父类里定义的

def ok_btn_onclick(self, event):

username = self.username_txt.GetValue() # 取出输入框的值

password = self.password_txt.GetValue()

if username in self.accounts:

if self.accounts[username].get('pwd') == password:

self.session['username'] = username

print("登录成功")

# 接下来要进入下一个Frame

frame = ListFrame()

frame.Show()

self.Hide() # 隐藏登录窗口

return

else:

msg = "用户名或密码错误"

else:

msg = "用户名不存在"

print(msg)

dialog = wx.MessageDialog(self, msg, "登录失败") # 创建对话框

dialog.ShowModal() # 显示对话框

dialog.Destroy() # 销毁对话框

def cancel_btn_onclick(self, event):

self.on_close(event)

商品列表窗口

这个窗口比较复杂。有下拉列表,可以做筛选,下面有表格有图片,并且点击表格的单元格,窗口的内容会有相应的变化:

"""商品列表窗口"""

import wx, wx.grid

from ui.my_frame import MyFrame

from ui.list_grid_table import ListGridTable

from conf import settings

class ListFrame(MyFrame):

def __init__(self):

super().__init__(title="商品列表", size=(1000, 700))

# 购物车

self.cart = {}

# 商品列表

self.data = settings.PRODUCTS

# 创建分隔窗口

splitter = wx.SplitterWindow(self.contentpanel, style=wx.SP_3DBORDER)

# 分隔窗口的左侧面板

self.left_panel = self.create_left_panel(splitter) # 先准备一个函数,到函数里再去实现

# 分隔窗口的右侧面板

self.right_panel = self.create_right_panel(splitter)

# 设置分隔窗口的布局,调用SplitVertically方法就是左右布局

splitter.SplitVertically(self.left_panel, self.right_panel, 630)

# 设置整个窗口的布局,是一个垂直的Box布局

box_outer = wx.BoxSizer(wx.VERTICAL)

# 下面直接把这个Box放到内容面板里了,也可以最后放。

# 不过这个窗口的内容只有一个垂直Box,所以无所谓了

# 还有其他的控件没有写,不过写完都是往box_splitter里添加

self.contentpanel.SetSizer(box_outer)

# 添加顶部对象

box_outer.Add(self.create_top_box(), 1, flag=wx.EXPAND | wx.ALL, border=20)

# 添加分隔窗口对象

box_outer.Add(splitter, 1, flag=wx.EXPAND | wx.ALL, border=10)

# 创建底部的状态栏

self.CreateStatusBar()

self.SetStatusText("准备就绪,欢迎您:%s" % self.session['username'])

def create_top_box(self):

"""创建顶部的布局管理器"""

# 创建静态文本

label_st = wx.StaticText(parent=self.contentpanel, label="选择商品类别:", style=wx.ALIGN_RIGHT)

# 创建下拉列表对象,这里取了一个name,之后可以通过name找到这个控件获取里面的内容

# 查找的方法用FindWindowByName,另外还可以ById和ByLabel

choice = wx.Choice(self.contentpanel, choices=settings.CATEGORY, name="choice")

# 创建按钮对象

search_btn = wx.Button(parent=self.contentpanel, label="查询")

reset_btn = wx.Button(parent=self.contentpanel, label="重置")

# 绑定事件

self.Bind(wx.EVT_BUTTON, self.search_btn_onclick, search_btn)

self.Bind(wx.EVT_BUTTON, self.reset_btn_onclick, reset_btn)

# 创建一个布局管理器,把上面的控件添加进去

box = wx.BoxSizer(wx.HORIZONTAL)

box.AddSpacer(200) # 添加空白

box.Add(label_st, 1, flag=wx.FIXED_MINSIZE | wx.ALL, border=10)

box.Add(choice, 1, flag=wx.FIXED_MINSIZE | wx.ALL, border=5)

box.Add(search_btn, 1, flag=wx.FIXED_MINSIZE | wx.ALL, border=5)

box.Add(reset_btn, 1, flag=wx.FIXED_MINSIZE | wx.ALL, border=5)

box.AddSpacer(300) # 添加空白

return box

def create_left_panel(self, parent):

"""创建分隔窗口的左侧面板"""

panel = wx.Panel(parent)

# 创建网格对象

grid = wx.grid.Grid(panel, name='grid')

# 绑定事件

self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.select_row_handler)

self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.select_row_handler)

# 初始化网格

self.init_grid() # 还是到另一个函数里去实现

# 创建水平Box的布局管理器

box = wx.BoxSizer()

# 设置Box的网格grid

box.Add(grid, 1, flag=wx.ALL, border=5)

panel.SetSizer(box)

return panel

def init_grid(self):

"""初始化网格对象"""

# 通过网格名字获取到对象

grid = self.FindWindowByName('grid')

# 创建网格中所需要的表格,这里的表格是一个类

table = ListGridTable(settings.COLUMN_NAMES, self.data)

# 设置网格的表格属性

grid.SetTable(table, True)

# 获取网格行的信息对象,40是行高,每一行都是40,后面的列表是单独指定每一行的,这里是空列表

row_size_info = wx.grid.GridSizesInfo(40, [])

# 设置网格的行高

grid.SetRowSizes(row_size_info)

# 指定列宽,前面是0,后面分别指定每一列的列宽

col_size_info = wx.grid.GridSizesInfo(0, [100, 80, 130, 200])

grid.SetColSizes(col_size_info)

# 设置单元格默认字体

grid.SetDefaultCellFont(wx.Font(11, wx.FONTFAMILY_DEFAULT,

wx.FONTSTYLE_NORMAL,

wx.FONTWEIGHT_NORMAL,

faceName="微软雅黑"))

# 设置表格标题的默认字体

grid.SetLabelFont(wx.Font(11, wx.FONTFAMILY_DEFAULT,

wx.FONTSTYLE_NORMAL,

wx.FONTWEIGHT_NORMAL,

faceName="微软雅黑"))

# 设置网格选择模式为行选择模式

grid.SetSelectionMode(grid.wxGridSelectRows)

# 设置网格不能通过拖动改标高度和宽度

grid.DisableDragRowSize()

grid.DisableDragColSize()

def create_right_panel(self, parent):

"""创建分隔窗口的右侧面板"""

panel = wx.Panel(parent, style=wx.TAB_TRAVERSAL | wx.BORDER_DOUBLE)

panel.SetBackgroundColour(wx.WHITE) # 设置背景色,默认不是白色

# 显示图片

img_path = "resources/dragon.jpg"

img = wx.Bitmap(img_path, wx.BITMAP_TYPE_ANY) # 第二个参数设置图片格式可以是任意的

img_bitmap = wx.StaticBitmap(panel, bitmap=img, name='img_bitmap')

# 商品类别

category = "商品类别:【还未选中商品】"

category_st = wx.StaticText(panel, label=category, name='category') # 创建控件同时指定label

# 商品名称

name = "商品名称:【还未选中商品】"

name_st = wx.StaticText(panel, label=name, name='name')

# 商品价格

price = "商品价格:¥{0:.2f}".format(128)

price_st = wx.StaticText(panel, label=price, name='price')

# 商品描述

description = "商品描述:%s" % "总之很好就是了"

description_st = wx.StaticText(panel, label=description, name='description')

# 创建按钮对象

add_btn = wx.Button(panel, label="添加到购物车")

see_btn = wx.Button(panel, label="查看购物车")

self.Bind(wx.EVT_BUTTON, self.add_btn_onclick, add_btn)

self.Bind(wx.EVT_BUTTON, self.see_btn_onclick, see_btn)

# 布局,垂直的Box布局管理器

box = wx.BoxSizer(wx.VERTICAL)

box.Add(img_bitmap, 1, flag=wx.CENTER | wx.ALL, border=30)

box.Add(category_st, 1, flag=wx.EXPAND | wx.ALL, border=10)

box.Add(name_st, 1, flag=wx.EXPAND | wx.ALL, border=10)

box.Add(price_st, 1, flag=wx.EXPAND | wx.ALL, border=10)

box.Add(description_st, 1, flag=wx.EXPAND | wx.ALL, border=10)

box.Add(add_btn, 1, flag=wx.EXPAND | wx.ALL, border=10)

box.Add(see_btn, 1, flag=wx.EXPAND | wx.ALL, border=10)

panel.SetSizer(box)

return panel

def search_btn_onclick(self, event):

"""查询按钮可以按商品类别进行筛选"""

choice = self.FindWindowByName('choice')

selected = choice.GetSelection()

if selected >= 0:

category = settings.CATEGORY[selected]

# 根据商品类别查询商品

products = []

for item in settings.PRODUCTS:

if item.get('category') == category:

products.append(item)

# 上面已经生成了新了商品列表,将商品列表更新后,重新初始化网格

self.data = products

self.init_grid()

def reset_btn_onclick(self, event):

"""单击重置按钮

查询所有的商品/获取初始的商品列表

然后初始化网格

"""

self.data = settings.PRODUCTS

self.init_grid()

def select_row_handler(self, event):

"""选择的网格的行事件处理

这里会刷新右侧面板的商品类别和名称

"""

row_selected = event.GetRow()

if row_selected >= 0:

selected_data = self.data[row_selected]

# 商品类别

category = "商品类别:%s" % selected_data.get('category')

category_st = self.FindWindowByName('category')

category_st.SetLabelText(category) # 先创建好控件,再修改或者设置label

# 商品名称

name = "商品名称:%s" % selected_data.get('name_cn')

name_st = self.FindWindowByName('name')

name_st.SetLabelText(name)

# 刷新布局,如果更换了图片应该是要刷新的,没换图片不用刷新

# self.right_panel.Layout()

event.Skip() # 事件跳过,貌似这里没什么用

def add_btn_onclick(self, event):

pass

def see_btn_onclick(self, event):

pass

表格对象

窗口里显示的表格的内容,单独再这里的数据表格类里面实现。这里继承了 GridTableBase 这个类,然后重构其中的几个方法返回表格的行数、列数、单元格的内容,就能在窗口的表格里里显示出来了:

"""自定义数据表格类"""

from wx.grid import GridTableBase

class ListGridTable(GridTableBase):

"""自定义表格类

下面分别重构了4个方法

返回行数、列数、每个单元格的内容、列标题

"""

def __init__(self, column_names, data):

super().__init__()

self.col_labels = column_names

self.data = data

def GetNumberRows(self):

return len(self.data)

def GetNumberCols(self):

return len(self.col_labels)

def GetValue(self, row, col):

products = self.data[row]

return {

0: products.get('id'),

1: products.get('category'),

2: products.get('name_cn'),

3: products.get('name_en'),

}.get(col)

def GetColLabelValue(self, col):

return self.col_labels[col]

效果

登录窗口

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

商品列表窗口

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值