2019年12月21日
一.系统分析与设计
1.项目描述
2.需求分析
3.原型设计 (原型图)
4.数据库可设计(实体ER图)
5.架构设计
6.系统设计
写4个Frame,两个GridTable
二.创建数据库
1.数据库安装略
2.编写数据库DDL脚本
/* 创建数据库 */
CREATE DATABASE IF NOT EXISTS petstore;
use petstore;
/* 用户表 */
CREATE TABLE IF NOT EXISTS accounts (
userid varchar(80) not null, /* 用户Id */
password varchar(25) not null, /* 用户密码 */
email varchar(80) not null, /* 用户Email */
name varchar(80) not null, /* 用户名 */
addr varchar(80) not null, /* 地址 */
city varchar(80) not null, /* 所在城市 */
country varchar(20) not null, /* 国家 */
phone varchar(80) not null, /* 电话号码 */
PRIMARY KEY (userid));
/* 商品表 */
CREATE TABLE IF NOT EXISTS products (
productid varchar(10) not null, /* 商品Id */
category varchar(10) not null, /* 商品类别 */
cname varchar(80) null, /* 商品中文名 */
ename varchar(80) null, /* 商品英文名 */
image varchar(20) null, /* 商品图片 */
descn varchar(255) null, /* 商品描述 */
listprice decimal(10,2) null, /* 商品市场价 */
unitcost decimal(10,2) null, /* 商品单价 */
PRIMARY KEY (productid));
/* 订单表 */
CREATE TABLE IF NOT EXISTS orders (
orderid bigint not null, /* 订单Id */
userid varchar(80) not null, /* 下订单的用户Id */
orderdate datetime not null, /* 下订单时间 */
status int not null default 0, /* 订单付款状态 0待付款 1已付款 */
amount decimal(10,2) not null, /* 订单应付金额 */
PRIMARY KEY (orderid));
/* 订单明细表 */
CREATE TABLE IF NOT EXISTS orderdetails (
orderid bigint not null, /* 订单Id */
productid varchar(10) not null, /* 商品Id */
quantity int not null, /* 商品数量 */
unitcost decimal(10,2) null, /* 商品单价 */
PRIMARY KEY (orderid, productid));
外键创建参考:https://www.jianshu.com/p/452ac68a1865
eg:
alert table orderdetails add foreign key(orderid) reference orders(orderid) ON UPDATE CASCADE ON DELETE CASCADE
3.插入初始数据
use petstore;
/* 用户表数据 */
INSERT INTO accounts VALUES('j2ee','j2ee','yourname@yourdomain.com','关东升', '北京丰台区', '北京', '中国', '18811588888');
INSERT INTO accounts VALUES('ACID','ACID','acid@yourdomain.com','Tony', '901 San Antonio Road', 'Palo Alto', 'USA', '555-555-5555');
/* 商品表数据 */
INSERT INTO products VALUES ('FI-SW-01','鱼类','神仙鱼', 'Angelfish', 'fish1.jpg', '来自澳大利亚的咸水鱼', 650, 400);
INSERT INTO products VALUES ('FI-SW-02','鱼类','虎鲨', 'Tiger Shark','fish4.jpg', '来自澳大利亚的咸水鱼', 850, 600);
INSERT INTO products VALUES ('FI-FW-01','鱼类','锦鲤', 'Koi','fish3.jpg', '来自日本淡水鱼', 150, 120);
INSERT INTO products VALUES ('FI-FW-02','鱼类','金鱼', 'Goldfish','fish2.jpg', '来自中国的淡水鱼', 150, 120);
INSERT INTO products VALUES ('K9-BD-01','狗类','斗牛犬', 'Bulldog','dog2.jpg', '来自英国友好的伴侣犬', 1500, 1200);
INSERT INTO products VALUES ('K9-PO-02','狗类','狮子狗', 'Poodle','dog6.jpg', '来自法国可爱狗狗', 1250, 1000);
INSERT INTO products VALUES ('K9-DL-01','狗类','斑点狗', 'Dalmation','dog5.jpg', '有很多斑点的狗狗', 2150, 2000);
INSERT INTO products VALUES ('K9-RT-01','狗类', '金毛猎犬', 'Golden Retriever','dog1.jpg', '很好的伴侣犬', 3800, 3400);
INSERT INTO products VALUES ('K9-RT-02','狗类', '拉布拉多犬','Labrador Retriever','dog5.jpg', '很好的狩猎犬', 3600, 3020);
INSERT INTO products VALUES ('K9-CW-01','狗类', '吉娃娃', 'Chihuahua','dog4.jpg', '性格温顺的狗狗', 1500, 120);
INSERT INTO products VALUES ('RP-SN-01','爬行类','响尾蛇', 'Rattlesnake','snake1.jpg','可怕且危险的动物', 150, 110);
INSERT INTO products VALUES ('RP-LI-01','爬行类','鬣蜥蜴', 'Iguana','lizard1.jpg', '主要生活在美洲和马达加斯加、斐济和汤加等地。',2600, 2203);
INSERT INTO products VALUES ('RP-LI-02','爬行类','变色树蜥蜴', 'Iguana','lizard2.jpg', '可随环境及光线强弱改变体色', 1000, 903);
INSERT INTO products VALUES ('RP-LI-03','爬行类','中国水龙蜴', 'Iguana','lizard3.jpg', '生活在中国云南的蜥蜴', 1600, 1003);
INSERT INTO products VALUES ('FL-DSH-01','猫类','马恩岛猫', 'Manx','cat3.jpg', '它能有效地减少老鼠的数量很有好处', 2503, 2120);
INSERT INTO products VALUES ('FL-DLH-02','猫类','波斯', 'Persian','cat1.jpg', '非常好的家猫', 3150, 2620);
INSERT INTO products VALUES ('FL-DLH-03','猫类','狸花猫', 'Persian2','cat2.jpg', '原产于中国的猫', 1000, 940);
INSERT INTO products VALUES ('AV-CB-01','鸟类','亚马逊鹦鹉', 'Amazon Parrot','bird4.jpg', '寿命长达75年的大鸟', 3150, 3000);
INSERT INTO products VALUES ('AV-SB-02','鸟类','鹦鹉1', 'Finch1','bird1.jpg', '会唱歌的鸟儿', 150, 110);
INSERT INTO products VALUES ('AV-SB-03','鸟类','鹦鹉2', 'Finch2','bird2.jpg', '会唱歌的鸟儿', 150, 110);
INSERT INTO products VALUES ('AV-SB-04','鸟类','鹦鹉3', 'Finch3','bird3.jpg', '会唱歌的鸟儿', 150, 110);
INSERT INTO products VALUES ('AV-SB-05','鸟类','鹦鹉4', 'Finch6','bird6.jpg', '会唱歌的鸟儿', 150, 110);
INSERT INTO products VALUES ('AV-SB-06','鸟类','鹦鹉5', 'Finch5','bird5.jpg', '会唱歌的鸟儿', 150, 110);
4.执行上面sql语句,可以在mysql模式,直接复制粘贴执行,也可以用如下方式执行
mysql -h localhost -u root -p < /Users/mac/Documents/wangyu/gitRepository/HelloProj/com/pkg1/db/jpetstore-mysql-schema.sql
三.初始化项目
1.添加图片资源 右键HelloProj 选择粘贴即可 (只是普通的文件夹,不是包)
2.添加包 右键主工程选择package类型 ( 不是普通的文件夹init.py)
ui:com.ewell.petstore.ui
dao:com.ewell.petstore.dao
四.编写数据持久层代码
1.数据库连接配置文件
2.编写dao基类
# coding=utf-8
"""定义DAO基类"""
import pymysql
import configparser
class BaseDao(object):
def __init__(self):
self.config = configparser.ConfigParser()
self.config.read('config.ini', encoding='utf-8')
host = self.config['db']['host']
user = self.config['db']['user']
# 读取整数port数据
port = self.config.getint('db', 'port')
password = self.config['db']['password']
database = self.config['db']['database']
charset = self.config['db']['charset']
self.conn = pymysql.connect(host=host,
user=user,
port=port,
password=password,
database=database,
charset=charset)
def close(self):
"""关闭数据库连接"""
self.conn.close()
3.用户管理dao
# coding=utf-8
"""用户管理DAO"""
from com.ewell.petstore.dao.base_dao import BaseDao
class AccountDao(BaseDao):
def __init__(self):
super().__init__()
def findbyid(self, userid):
account = None
try:
# 2. 创建游标对象
with self.conn.cursor() as cursor:
# 3. 执行SQL操作
sql = 'select userid,password,email,name,addr,city,country,phone ' \
'from accounts where userid =%s'
cursor.execute(sql, userid)
# 4. 提取结果集
row = cursor.fetchone()
if row is not None:
account = {}
account['userid'] = row[0]
account['password'] = row[1]
account['email'] = row[2]
account['name'] = row[3]
account['addr'] = row[4]
account['city'] = row[5]
account['country'] = row[6]
account['phone'] = row[7]
# with代码块结束 5. 关闭游标
finally:
# 6. 关闭数据连接
self.close()
return account
4.商品管理dao
# coding=utf-8
"""商品管理DAO"""
from com.ewell.petstore.dao.base_dao import BaseDao
class ProductDao(BaseDao):
def __init__(self):
super().__init__()
def findall(self):
"""查询所有商品信息"""
products = []
try:
# 2. 创建游标对象
with self.conn.cursor() as cursor:
# 3. 执行SQL操作
sql = 'select productid,category,cname,ename,image,listprice,unitcost,descn ' \
'from products'
cursor.execute(sql)
# 4. 提取结果集
result_set = cursor.fetchall()
for row in result_set:
product = {}
product['productid'] = row[0]
product['category'] = row[1]
product['cname'] = row[2]
product['ename'] = row[3]
product['image'] = row[4]
product['listprice'] = row[5]
product['unitcost'] = row[6]
product['descn'] = row[7]
products.append(product)
# with代码块结束 5. 关闭游标
finally:
# 6. 关闭数据连接
self.close()
return products
def findbycat(self, catname):
"""按照商品类别查询商品"""
products = []
try:
# 2. 创建游标对象
with self.conn.cursor() as cursor:
# 3. 执行SQL操作
sql = 'select productid,category,cname,ename,image,listprice,unitcost,descn ' \
'from products where category=%s'
cursor.execute(sql, catname)
# 4. 提取结果集
result_set = cursor.fetchall()
for row in result_set:
product = {}
product['productid'] = row[0]
product['category'] = row[1]
product['cname'] = row[2]
product['ename'] = row[3]
product['image'] = row[4]
product['listprice'] = row[5]
product['unitcost'] = row[6]
product['descn'] = row[7]
products.append(product)
# with代码块结束 5. 关闭游标
finally:
# 6. 关闭数据连接
self.close()
return products
def findbyid(self, productid):
"""按照商品id查询商品"""
product = None
try:
# 2. 创建游标对象
with self.conn.cursor() as cursor:
# 3. 执行SQL操作
sql = 'select productid,category,cname,ename,image,listprice,unitcost,descn' \
' from products where productid=%s'
cursor.execute(sql, productid)
# 4. 提取结果集
row = cursor.fetchone()
if row is not None:
product = {}
product['productid'] = row[0]
product['category'] = row[1]
product['cname'] = row[2]
product['ename'] = row[3]
product['image'] = row[4]
product['listprice'] = row[5]
product['unitcost'] = row[6]
product['descn'] = row[7]
# with代码块结束 5. 关闭游标
finally:
# 6. 关闭数据连接
self.close()
return product
5.订单管理dao
# coding=utf-8
"""订单管理DAO"""
import pymysql
from com.ewell.petstore.dao.base_dao import BaseDao
class OrderDao(BaseDao):
def __init__(self):
super().__init__()
def findall(self):
"""查询所有订单"""
orders = []
try:
# 2. 创建游标对象
with self.conn.cursor() as cursor:
# 3. 执行SQL操作
sql = 'select orderid,userid,orderdate from orders'
cursor.execute(sql)
# 4. 提取结果集
result_set = cursor.fetchall()
for row in result_set:
order = {}
order['orderid'] = row[0]
order['userid'] = row[1]
order['orderdate'] = row[2]
orders.append(order)
# with代码块结束 5. 关闭游标
finally:
# 6. 关闭数据连接
self.close()
return orders
# order 是列表 或元组
def create(self, order):
"""创建订单,插入到数据库"""
try:
# 2. 创建游标对象
with self.conn.cursor() as cursor:
# 3. 执行SQL操作
sql = 'insert into orders (orderid,userid,orderdate,status,amount) ' \
'values (%s,%s,%s,%s,%s)'
affectedcount = cursor.execute(sql, order)
print('成功插入{0}条数据'.format(affectedcount))
# 4. 提交数据库事物
self.conn.commit()
# with代码块结束 5. 关闭游标
except pymysql.DatabaseError as e:
# 4. 回滚数据库事物
self.conn.rollback()
print(e)
finally:
# 6. 关闭数据连接
self.close()
6.订单明细管理dao
# coding=utf-8
"""订单明细管理DAO"""
import pymysql
from com.ewell.petstore.dao.base_dao import BaseDao
class OrderDetailDao(BaseDao):
def __init__(self):
super().__init__()
# orderdetail是元组或列表
def create(self, orderdetail):
"""创建订单明细,插入到数据库"""
try:
# 2. 创建游标对象
with self.conn.cursor() as cursor:
# 3. 执行SQL操作
sql = 'insert into orderdetails (orderid, productid,quantity,unitcost) ' \
'values (%s,%s,%s,%s)'
affectedcount = cursor.execute(sql, orderdetail)
print('成功插入{0}条数据'.format(affectedcount))
# 4. 提交数据库事物
self.conn.commit()
# with代码块结束 5. 关闭游标
except pymysql.DatabaseError as e:
# 4. 回滚数据库事物
self.conn.rollback()
print(e)
finally:
# 6. 关闭数据连接
self.conn.close()
五.编写表示层代码
1.编写启动主模块app_main.py
# coding=utf-8
import wx
from com.ewell.petstore.ui.login_frame import LoginFrame
class App(wx.App):
def OnInit(self):
# 创建窗口对象
frame = LoginFrame()
frame.Show()
return True
if __name__ == '__main__':
app = App()
app.MainLoop() # 进入主事件循环
2.编写自定义窗口类 MyFrame(父类)
# coding=utf-8
"""定义Frame窗口基类"""
import sys
import wx
class MyFrame(wx.Frame):
# 用户登录成功后,保存当前用户信息
Session = {}
def __init__(self, title, size):
super().__init__(parent=None, title=title, size=size,
style=wx.DEFAULT_FRAME_STYLE ^ wx.MAXIMIZE_BOX)
# 设置窗口居中
self.Centre()
# 设置Frame窗口内容面板
self.contentpanel = wx.Panel(parent=self)
ico = wx.Icon('resources\icon\dog4.ico', wx.BITMAP_TYPE_ICO)
# 设置窗口图标
self.SetIcon(ico)
# 设置窗口的最大和最小尺寸
self.SetSizeHints(size, size)
self.Bind(wx.EVT_CLOSE, self.OnClose)
def OnClose(self, event):
# 退出系统
self.Destroy()
sys.exit(0)
3.编写用户登录界面
# coding=utf-8
"""用户登录窗口"""
import wx
from com.ewell.petstore.dao.account_dao import AccountDao
from com.ewell.petstore.ui.my_frame import MyFrame
from com.ewell.petstore.ui.product_list_frame import ProductListFrame
class LoginFrame(MyFrame):
def __init__(self):
super().__init__(title='用户登录', size=(340, 230))
# 创建界面控件
accountid_st = wx.StaticText(self.contentpanel, label='账号:')
password_st = wx.StaticText(self.contentpanel, label='密码:')
self.accountid_txt = wx.TextCtrl(self.contentpanel)
self.password_txt = wx.TextCtrl(self.contentpanel, style=wx.TE_PASSWORD)
# 创建FlexGrid布局fgs对象
fgs = wx.FlexGridSizer(2, 2, 20, 20)
fgs.AddMany([(accountid_st, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE),
(self.accountid_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)
fgs.AddGrowableRow(1, 1)
fgs.AddGrowableCol(0, 1)
fgs.AddGrowableCol(1, 4)
# 创建按钮对象
okb_btn = wx.Button(parent=self.contentpanel, label='确定')
self.Bind(wx.EVT_BUTTON, self.okb_btn_onclick, okb_btn)
cancel_btn = wx.Button(parent=self.contentpanel, label='取消')
self.Bind(wx.EVT_BUTTON, self.cancel_btn_onclick, cancel_btn)
# 创建水平Box布局hbox对象
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(okb_btn, 1, wx.CENTER | wx.ALL | wx.EXPAND, border=10)
hbox.Add(cancel_btn, 1, wx.CENTER | wx.ALL | wx.EXPAND, border=10)
# 创建垂直Box布局,把fgs和hbox添加到垂直Box布局对象上
vbox = wx.BoxSizer(wx.VERTICAL)
# -1不指定权重
vbox.Add(fgs, -1, wx.CENTER | wx.ALL | wx.EXPAND, border=25)
vbox.Add(hbox, -1, wx.CENTER | wx.BOTTOM, border=20)
self.contentpanel.SetSizer(vbox)
def okb_btn_onclick(self, event):
"""确定按钮事件处理"""
dao = AccountDao()
account = dao.findbyid(self.accountid_txt.GetValue())
password = self.password_txt.GetValue()
if account is not None and account['password'] == password:
print('登录成功。')
next_frame = ProductListFrame()
next_frame.Show()
self.Hide()
# 登录成功保存用户Session
MyFrame.Session = account
else:
print('登录失败。')
dlg = wx.MessageDialog(self, '您输入的账号或密码有误,请重新输入。',
'登录失败',
wx.OK | wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()
def cancel_btn_onclick(self, event):
"""取消按钮事件处理"""
# 退出系统
self.OnClose(self, event)
4.编写商品列表界面
# coding=utf-8
"""商品列表窗口"""
import wx
import wx.grid
from com.ewell.petstore.dao.product_dao import ProductDao
from com.ewell.petstore.ui.cart_frame import CartFrame
from com.ewell.petstore.ui.my_frame import MyFrame
from com.ewell.petstore.ui.product_list_gridtable import ProductListGridTable
# 商品类别
CATEGORYS = ['鱼类', '狗类', '爬行类', '猫类', '鸟类']
class ProductListFrame(MyFrame):
def __init__(self):
super().__init__(title='商品列表窗口', size=(1000, 700))
# 购物车,键是选择的商品Id,值是商品的数量
self.cart = {}
# 选中商品
self.selecteddata = {}
# 创建DAO对象
dao = ProductDao()
# 查询所有数据
self.data = dao.findall()
# 创建分隔窗口
splitter = wx.SplitterWindow(self.contentpanel, style=wx.SP_3DBORDER)
# 创建分隔窗口中的左侧面板
self.leftpanel = self.createleftpanel(splitter)
# 创建分隔窗口中的右侧面板
self.rightpanel = self.createrightpanel(splitter)
# 设置分隔窗口左右布局
splitter.SplitVertically(self.leftpanel,
self.rightpanel,
630)
# 设置最小窗口尺寸
splitter.SetMinimumPaneSize(630)
# 设置整个窗口布局是垂直Box布局
vbox = wx.BoxSizer(wx.VERTICAL)
self.contentpanel.SetSizer(vbox)
# 添加顶部对象(topbox)到vbox
vbox.Add(self.createtopbox(), 1, flag=wx.EXPAND | wx.ALL, border=20)
# 添加底部对象(splitter)到vbox
vbox.Add(splitter, 1, flag=wx.EXPAND | wx.ALL, border=10)
# 在当前创建(Frame对象)创建并添加默认状态栏
self.CreateStatusBar()
self.SetStatusText('准备就绪')
def createtopbox(self):
"""创建顶部布局管理器topbox"""
# 创建静态文本
pc_st = wx.StaticText(parent=self.contentpanel, label='选择商品类别:', style=wx.ALIGN_RIGHT)
# 创建按钮对象
search_btn = wx.Button(parent=self.contentpanel, label='查询')
reset_btn = wx.Button(parent=self.contentpanel, label='重置')
choice = wx.Choice(self.contentpanel, choices=CATEGORYS, name='choice')
# 绑定事件处理
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(pc_st, 1, flag=wx.FIXED_MINSIZE | wx.ALL, border=10)
box.Add(choice, 1, flag=wx.EXPAND | wx.ALL, border=5)
box.Add(search_btn, 1, flag=wx.EXPAND | wx.ALL, border=5)
box.Add(reset_btn, 1, flag=wx.EXPAND | wx.ALL, border=5)
box.AddSpacer(260)
return box
def createleftpanel(self, parent):
"""创建分隔窗口中的左侧面板"""
panel = wx.Panel(parent)
# 创建网格对象
grid = wx.grid.Grid(panel, name='grid')
# 绑定网格事件处理
self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.selectrow_handler)
self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.selectrow_handler)
# 初始化网格
self.initgrid()
# 创建水平Box管理管理
box = wx.BoxSizer()
# 设置水平Box管理管理网格grid
box.Add(grid, 1, flag=wx.ALL, border=5)
panel.SetSizer(box)
return panel
def initgrid(self):
"""初始化网格对象"""
# 通过网格名字获得网格对象
grid = self.FindWindowByName('grid')
# 创建网格中所需的表格
table = ProductListGridTable(self.data)
# 设置网格的表格属性
grid.SetTable(table, True)
rowsizeinfo = wx.grid.GridSizesInfo(40, [])
# 设置网格所有行高
grid.SetRowSizes(rowsizeinfo)
colsizeinfo = wx.grid.GridSizesInfo(0, [100, 80, 130, 200])
# 设置网格所有列宽
grid.SetColSizes(colsizeinfo)
# 设置单元格默认字体
grid.SetDefaultCellFont(wx.Font(11, wx.FONTFAMILY_DEFAULT,
wx.FONTSTYLE_NORMAL,
wx.FONTWEIGHT_NORMAL, faceName='微软雅黑'))
# 设置行和列标题的默认字体
grid.SetLabelFont(wx.Font(9, wx.FONTFAMILY_DEFAULT,
wx.FONTSTYLE_NORMAL,
wx.FONTWEIGHT_NORMAL, faceName='微软雅黑'))
# 设置网格选择模式为行选择
grid.SetSelectionMode(grid.wxGridSelectRows)
# 设置行不能通过拖动改变高度
grid.DisableDragRowSize()
# 设置列不能通过拖动改变宽度
grid.DisableDragColSize()
def createrightpanel(self, parent):
"""创建分隔窗口中的右侧面板"""
panel = wx.Panel(parent, style=wx.TAB_TRAVERSAL | wx.BORDER_DOUBLE)
panel.SetBackgroundColour(wx.WHITE)
# 显示第一张图片
imagepath = 'resources/images/' + self.data[0]['image']
image = wx.Bitmap(imagepath, wx.BITMAP_TYPE_ANY)
image_sbitmap = wx.StaticBitmap(panel, bitmap=image, name='image_sbitmap')
# 商品市场价格
slistprice = "商品市场价:¥{0:.2f}".format(self.data[0]['listprice'])
listprice_st = wx.StaticText(panel, label=slistprice, name='listprice')
# 市场价格
sunitcost = "商品单价:¥{0:.2f}".format(self.data[0]['unitcost'])
unitcost_st = wx.StaticText(panel, label=sunitcost, name='unitcost')
# 商品描述
descn = "商品描述:{0}".format(self.data[0]['descn'])
descn_st = wx.StaticText(panel, label=descn, name='descn')
# 创建按钮对象
addcart_btn = wx.Button(panel, label='添加到购物车')
seecart_btn = wx.Button(panel, label='查看购物车')
# 绑定事件处理
self.Bind(wx.EVT_BUTTON, self.addcart_btn_onclick, addcart_btn)
self.Bind(wx.EVT_BUTTON, self.seecart_btn_onclick, seecart_btn)
# 创建垂直Box布局管理器
box = wx.BoxSizer(wx.VERTICAL)
box.AddSpacer(50)
box.Add(image_sbitmap, 1, flag=wx.CENTER | wx.ALL, border=30)
box.AddSpacer(50)
box.Add(listprice_st, 1, flag=wx.EXPAND | wx.ALL, border=10)
box.Add(unitcost_st, 1, flag=wx.EXPAND | wx.ALL, border=10)
box.Add(descn_st, 1, flag=wx.EXPAND | wx.ALL, border=10)
box.AddSpacer(20)
box.Add(addcart_btn, 1, flag=wx.EXPAND | wx.ALL, border=10)
box.Add(seecart_btn, 1, flag=wx.EXPAND | wx.ALL, border=10)
panel.SetSizer(box)
return panel
def search_btn_onclick(self, event):
"""查询按钮事件处理"""
# 通过名字查询choice控件
choice = self.FindWindowByName('choice')
# 获得选中类别索引
selectcatidx = choice.GetSelection()
if selectcatidx >= 0:
# 获得选中的商品类别
catname = CATEGORYS[selectcatidx]
# 根据类别查询商品
dao = ProductDao()
self.data = dao.findbycat(catname)
# 初始化网格
self.initgrid()
def reset_btn_onclick(self, event):
"""重置按钮事件处理"""
# 查询所有商品
dao = ProductDao()
self.data = dao.findall()
# 初始化网格
self.initgrid()
def addcart_btn_onclick(self, event):
"""添加到购物车事件处理"""
if len(self.selecteddata) == 0:
self.SetStatusText('请先选择商品')
return
# 获得选择的商品id
productid = self.selecteddata['productid']
if productid in self.cart.keys(): # 判断购物车中已经有该商品
# 获得商品数量
quantity = self.cart[productid]
self.cart[productid] = (quantity + 1)
else: # 购物车中还没有该商品
self.cart[productid] = 1
# 显示在状态栏
self.SetStatusText('商品{0}添加到购物车'.format(productid))
print(self.cart)
def seecart_btn_onclick(self, event):
"""查看添加到购物车事件处理"""
next_frame = CartFrame(self.cart, self)
next_frame.Show()
self.Hide()
def selectrow_handler(self, event):
"""选择网格行事件处理"""
srowidx = event.GetRow()
if srowidx >= 0:
print(self.data[srowidx])
self.selecteddata = self.data[srowidx]
self.SetStatusText('选择第{0}行数据'.format(srowidx + 1))
# 显示选择的图片
imagepath = 'resources/images/' + self.selecteddata['image']
image = wx.Bitmap(imagepath, wx.BITMAP_TYPE_ANY)
# 通过名字查询子窗口
image_sbitmap = self.FindWindowByName('image_sbitmap')
image_sbitmap.SetBitmap(image)
# 商品市场价格
slistprice = "商品市场价:¥{0:.2f}".format(self.selecteddata['listprice'])
listprice_st = self.FindWindowByName('listprice')
listprice_st.SetLabelText(slistprice)
# 市场价格
sunitcost = "商品单价:¥{0:.2f}".format(self.selecteddata['unitcost'])
unitcost_st = self.FindWindowByName('unitcost')
unitcost_st.SetLabelText(sunitcost)
# 商品描述
descn = "商品描述:{0}".format(self.selecteddata['descn'])
descn_st = self.FindWindowByName('descn')
descn_st.SetLabelText(descn)
self.rightpanel.Layout()
event.Skip()
# coding=utf-8
"""自定义GridTableBase类, 用于商品网格"""
import wx.grid
# 商品网格列名
COLUMN_NAMES = ['商品编号', '商品类别', '商品中文名', '商品英文名']
class ProductListGridTable(wx.grid.GridTableBase):
def __init__(self, data):
super().__init__()
self.colLabels = COLUMN_NAMES
self.data = data
def GetNumberRows(self):
return len(self.data)
def GetNumberCols(self):
return len(COLUMN_NAMES)
def GetValue(self, rowidx, colidx):
product = self.data[rowidx]
if colidx == 0:
return product['productid']
elif colidx == 1:
return product['category']
elif colidx == 2:
return product['cname']
else:
return product['ename']
def GetColLabelValue(self, colidx):
return self.colLabels[colidx]
5.编写购物车界面
其余代码参考:
https://github.com/wangyu204/HelloProj.git
六.发布可执行文件
1.TODO任务 查看
2.发布为可执行文件
2.1安装pyinstaller (大概花了40分钟,一致报错)
官网:http://www.pyinstaller.org/
pip install pyinstaller
2.2 参考
2.3 实现步骤
第一步切换到根目录,创建规范文件
cd /Users/mac/Documents/wangyu/gitRepository/HelloProj
wangyuMBP:HelloProj mac$ pyi-makespec [app_main.py](http://app_main.py/)
第二步:修改规范文件 (主要是添加资源文件和配置文件)
第三步执行(也是在根目录)
cd /Users/mac/Documents/wangyu/gitRepository/HelloProj
pyinstaller app_main.spec
报如下错误: TypeError: an integer is required (got type bytes)
网上反馈是兼容问题,
参考:https://github.com/pyinstaller/pyinstaller/issues/4265
解决:先卸载3.5版本,在安装开发版本 (晚上试了很久都下载不了,直接下载安装也不行)
pip uninstall pyinstaller
pip install https://github.com/pyinstaller/pyinstaller/archive/develop.tar.gz
pip install https://github.com/pyinstaller/pyinstaller/tarball/develop
https://pyinstaller.readthedocs.io/en/stable/installation.html#installing-in-mac-os-x
第二天早上公司一运行就很快安装好了
再次运行成功了
pyinstaller app_main.spec
点击 dist目录下的 app_main/app_main文件就可以正常运行了(下面错误待研究)
如果您发现本文对你有所帮助,如果您认为其他人也可能受益,请把它分享出去。