目录
上一章节已经介绍了如何将程序主窗口设计好生成python代码,运行成功的展示了窗体。
上一章内容地址:
wxFormBuilder + Python 工具开发第一章-拖出日记本图形界面_魂尾ac的博客-CSDN博客
这一章节将会介绍如何将代码目录架构定好,实现树与文章从数据库展示到前端窗体的内容
功能与内容:
数据库选型
设计数据表
实现数据IO
展示树节点
切换展示文章
实现后基本功能测试
本节最终效果图
文中 wxFormBuilder 均简化为 wxF 代替
代码目录设计为
NodeBook
manage
template
NodeBook为日记本项目目录,template为wxF生成的图形界面代码目录,manage是一些继承template里图界面代码类的类文件、数据库管理代码文件、以及其它逻辑代码的目录,后面还会有一个目录存放本地数据库
1、新增名为template的pkg目录,将图形界面代码移入
2、新增名为manage的pkg目录,在其下新增newWindow.py文件,将runMain里的MainFrame派生类移入其中
PS:注释MainFrame导入头会变成:from NodeBook.template.noname import MainFrame
3、在runMain.py中去掉MainFrame派生类的代码,添加NewWindow的导入头:
from NodeBook.manage.newWindow import NewWindow
runMain.py始终是项目代码运行入口。
4、运行,检查代码是否正常
小工具要使用的数据应该是一个跟着工具走,本地的,开源的,Sqlite刚好满足这样一个需求;许多开发手机app小工具的都使用它作为数据库。
1、Sqlite下载
在https://www.sqlite.org/download.html网站下载
解压sqlite-tools-win32-x86-3390200.zip
2、建库
打开sqlite.exe文件
输入命令:.open notebook.db 生成数据库
3、建表
使用navicat连接notebook.db(navicat怎么连sqlite, 百度学习一下)
建一个user表,表里有accout、password字段,建表SQL如下:
create table user(
id INTEGER primary key autoincrement,
account VARCHAR not null,
password VARCHAR not null
)
在user表里添加几条数据供python调试
4、python连接notebook.db库
1)在代码目录新增一个database目录,将notebook.db 拷贝到database目录下。
2)manage目录下新增一个sqliteio.py文件,
3)先获取一下notebook.db的绝对路径,编写代码如下
- import os
- import sqlite3
-
-
-
- #获取上一层目录的绝对路径
- par_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
- #获取database绝对路径
- dpath = os.path.join(par_path, 'database')
-
- #获取notebook.db的绝对路径
- nbpath = os.path.join(dpath, 'notebook.db')
-
-
- print(nbpath)
执行结果:
4)连接数据,读写user数据,编写代码如下
- #连接数据
- conn = sqlite3.connect(nbpath)
-
- #获取游标
- cur = conn.cursor()
-
- #执行查询SQL语句
- cur.execute('select * from user;')
-
-
- #遍历查出的数据,fetchall()即获取查出所有数据的列表
- for row in cur.fetchall():
- print(row)
-
-
- #执行插入数据
- cur.execute('insert into user(account, password) values("xiaotian","qwert1234")')
- print('-------插入数据后---- 重新查询------- ')
-
-
- #重新查询
- cur.execute('select * from user;')
-
-
- #遍历查出的数据,fetchall()即获取查出所有数据的列表
- for row in cur.fetchall():
- print(row)
-
- #关闭游标、关闭数据库连接
- cur.close()
- conn.close()
执行结果
Sqlite基础操作暂时告一段落,后面开始做Notebook数据库开的正式内容
1、表设计
日记本,日期与名称,做一个树节点表,有id,父id,节点名称等等;再做一个文章表,有树节点外键,文章标题,文章内容等等。
树表:treenodes
字段 | 类型 | 长度 | 可否为空 | 描述 |
id | 主键自增 | 否 | ||
tree_note | char | 200 | 否 | 节点名称 |
parent_id | Int | 可 | 父节点id | |
Is_delete | int | 否 | 删除标识,默认为0未删除, 1为删除 | |
create_time | Data_time | 可 | 创建时间 | |
updata_time | Data_time | 可 | 更新时间 |
文章表:articles
字段 | 类型 | 长度 | 可否为空 | 描述 |
id | 主键自增 | 否 | ||
tree_id | treenodes外键 | 否 | ||
name | vchar | 200 | 否 | 文章名称 |
content | text | 可 | 文章内容 | |
Is_delete | int | 否 | 删除标识,默认为0未删除, 1为删除 | |
create_time | Data_time | 可 | 创建时间 | |
Updata_time | Data_time | 可 | 更新时间 |
2、创建表脚本
- -- 创建树表
- create table treenodes(
- id INTEGER primary key autoincrement,
- tree_note CHAR(200) not null,
- parent_id INT,
- is_delete INT default 0,
- create_time DATETIME not null default current_timestamp,
- updata_time DATETIME not null default current_timestamp
- )
-
-
- -- 创建文件内容表
- create table articles(
- id INTEGER primary key autoincrement,
- tree_id INTEGER,
- name CHAR(200) not null,
- content TEXT,
- is_delete INT default 0,
- create_time DATETIME not null default current_timestamp,
- updata_time DATETIME not null default current_timestamp,
- FOREIGN KEY (tree_id)
- REFERENCES treenodes(id) on delete cascade on update cascade
- )
3、数据库封装
1)新增类SqliteIo的类,初始化数据连接,析造数据
代码如下:
- class SqliteIo(object):
- def __init__(self):
-
- '''
- 构造函数
- 初始化数据库连接
- '''
- self.conn = sqlite3.connect(nbpath)
- self.cur = self.conn.cursor()
-
- def __del__(self):
-
- '''
- 析造函数
- 关闭游标与数据库连接
- :return:
- '''
- self.cur.close()
- self.conn.close()
2)treenotes增删改查
代码如下:
- def get_treeNode_lst(self):
- '''
- 获取treenodes所有未删除的数据
- :return:
- list: [{},{},{}]表数据列表
- '''
- try:
- #执行sql
- sql = 'select * from treenodes where is_delete = 0'
- self.cur.execute(sql)
- #用推导式 获取表头字段名
- title = tuple(item[0] for item in self.cur.description)
- #获取所有的数据
- rows = self.cur.fetchall()
- #用推导式 将表头与数据拼装成一个字典列表
- result = [dict(zip(title, item)) for item in rows]
- return result
- except Exception as e:
- return []
-
- def insert_treeNode_data(self, data):
- '''
- 新增节点
- :param data: 节点数据
- :return: bool 成功与否
- '''
- try:
- sql = '''insert into treenodes(tree_note, parent_id, level) values('{}', {}, {})'''.format(data['tree_node'], data['parent_id'], data['level'])
- self.cur.execute(sql)
- self.conn.commit()
- id = self.cur.lastrowid
- return True, id
- except Exception as e:
- return False
-
-
- def del_treeNode_data(self, id):
- '''
- 删除节点(逻辑删)
- :param id: 节点id
- :return: bool 成功与否
- '''
- try:
- sql = 'update treenodes set is_delete = 1 where id = {}'.format(str(id))
- self.cur.execute(sql)
- self.conn.commit()
- return True
- except:
- return False
-
-
- def update_treeNode_data(self, data):
- '''
- 更新节点名称
- :param data: 节点数据 dict
- :return: bool 成功与否
- '''
- try:
- sql = '''update treenodes set tree_note = '{}' where id = {}'''.format(data['tree_node'], data['id'])
- self.cur.execute(sql)
- self.conn.commit()
- return True
- except:
- return False
3)articles增删改查
- def get_articles(self, tree_node_id):
- '''
- 通过树id找文章
- :param tree_node_id: 树id
- :return: dict,返回文章内容
- '''
- try:
- sql = '''select * from articles where tree_id = {}'''.format(tree_node_id)
- # 用推导式 获取表头字段名
- self.cur.execute(sql)
- title = (item[0] for item in self.cur.description)
- #获取数据
- item = self.cur.fetchone()
- return dict(zip(title, item))
- except:
- return {}
-
- def insert_articles(self, data):
- '''
- 新增文章
- :param data: 文章数据
- :return: bool 成功与否
- '''
- try:
- sql = '''insert into articles(tree_id, name) values({}, '{}')'''.format(data['tree_id'], data['name'])
- self.cur.execute(sql)
- self.conn.commit()
- return True
- except:
- return False
-
- def updata_articles(self, data):
- '''
- 更新文章
- :param data:
- :return: bool 成功与否
- '''
- try:
- sql = '''update articles set name='{}', content='{}' where id = {}'''.format(data['name'], data['content'], data['id'])
- self.cur.execute(sql)
- self.conn.commit()
- return True
- except:
- return False
-
-
- def del_articles(self, id):
- '''
- 删除文章(逻辑删除)
- :param id: 文章id
- :return: bool 成功与否
- '''
- try:
- sql = '''update articles set is_delete = 1 where id = {}'''.format(str(id))
- self.cur.execute(sql)
- self.conn.commit()
- return True
- except:
- return False
-
-
- sqlt = SqliteIo()
数据库代码封闭完毕,中间的细节,慢慢会补上
后面的sqlt是将数据库读取类单例化
1、在数据库添加数据
添加四个树节点,根目录,两个日期(二级)目录,一个文章(三级目录)目录
parent_id决定父节点,id与parent_id构成树节点的级联关系
添加一篇文章,对tree_id=4
tree_id,表示这篇文章属于哪个树节点,后期效果,点击某个三级节点,展示对应文章内容
2、展示树节点
首先呢,在newWindow.py里导入sqlt数据库操作对象
编写一个list_to_tree的递归函数,实现数据格式化
树节点格式
[
{
Id:1,
....
Children:[{子节点}]
}
]
在NewWindow里添加一个方法get_tree_node(),用例sqlt调用函数get_treeNode_lst()获取数据库里的数据,然后调用list_to_tree()函数将获取的数据转换成树格式
在构造函数里新增一个m_tree的变量,调用get_tree_node函数,将返回赋值给m_tree
将树展示在窗体中
编写函数set_tree(),在其中递归将节点设置到self.my_nodetree中(my_nodetree是窗体树的对象)
在构造函数init中调用set_tree(),传入self.m_tree,将m_tree的树数据展示出来
运行runMain.py文件
窗体中的树展示的节点是按照treenodes里的数据逻辑形成的,‘2022-9-6’、‘2022-9-7’两个节点的parent_id是1,也就是‘根目录’,‘那年夏天’的parent_id是2,也就是‘2022-9-6’
展示文章应该是点击文章标题展示对应文章,从选择的节点中获取data,在data找到id,通过id在articles的tree_id中找到文章,展示在编辑框中
(1)切换树节点响应事件函数实现
在wxF中选择m_nodetree:wxTreeCtrl添加OnLetfDown的事件,on_change_rticles。
再将生成的代码复制过来,如果熟悉了,可以局部复制,免得再去修改兼容代码
在newWindow.py覆盖这个事件函数,编写选择节点的数据打印一下
运行runMain.py,点击树节点来回切换,看控制台打印
好,切换树节点功能实现
3、展示文章
在响应函数里添加获取文章数据并展示在编辑框中的代码,编辑框的对象是m_textEdit
运行runMain.py节点,点击‘那年夏天’,可以看到右边的编辑框,可以展示对应的文章内容了
此时我们在数据里多添加一些文章,看看切换是否有效果
本章完成,下一章讲述树节点数据的增改删的开发
本章代码: