wxFormBuilder + wxPython 工具开发第二章-日记本工具数据连接与展示

article/2025/9/12 8:53:27

目录

 

前言

一、代码目录层级

二、数据库

三、数据表设计

四、展示数据


前言

上一章节已经介绍了如何将程序主窗口设计好生成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:#执行sqlsql = '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 resultexcept 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.lastrowidreturn True, idexcept Exception as e:return Falsedef 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 Trueexcept:return Falsedef 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 Trueexcept: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 Trueexcept:return Falsedef 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 Trueexcept:return Falsedef 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 Trueexcept:return Falsesqlt = 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’

  1. 展示文章

展示文章应该是点击文章标题展示对应文章,从选择的节点中获取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节点,点击‘那年夏天’,可以看到右边的编辑框,可以展示对应的文章内容了

此时我们在数据里多添加一些文章,看看切换是否有效果

本章完成,下一章讲述树节点数据的增改删的开发

本章代码:

https://download.csdn.net/download/weixin_40331132/86616745


http://chatgpt.dhexx.cn/article/Es5AkV0i.shtml

相关文章

HBuidler运行小程序:rovider:wxf72d316417b6767f, version:1.0.1, AppID 不合法,invalid appid

解决: 这个是官方的demo,把对应的id值删掉就可以运行成功, 在微信开发者工具里,找到app.json, plugins里的2个广告配置删除可以运行成功。

wxFormBuilder + wxPython 工具开发第三章-日记本工具树节点增、改、删功能

目录 前言 一、添加树右击菜单 二、新增 1、实现二级日期节点新增 2、实现三级文章节点新增 三、修改 四、删除 前言 上一章节实现了对目记本表数据设计,数据库连接,数据展示的功能 wxFormBuilder Python 工具开发第二章-日记本工具数据连接与展…

进程和多线程的生命周期

进程和线程 进程 对于操作系统来说,一个任务就是一个进程(Process)。 课本概念:程序的一个执行实例,正在执行的程序等。 内核观点:担当分配系统资源(CPU时间,内存)的实…

Python 线程的生命周期

CPU 在轮换执行线程过程中,线程都经历了什么呢?线程从创建到消亡的整个过程,可能会历经 5 种状态,分别是新建、就绪、运行、阻塞和死亡,如图 1 所示。 图 1 线程状态转换图 线程的新建和就绪状态 无论是通过 Thread …

线程的生命周期和线程池的生命周期

目录 线程的生命周期 1、新建状态 2、就绪状态 3、运行状态 4、死亡状态 5、阻塞状态 线程池的生命周期 1、RUNNING 2、SHUTDOWN 3、STOP 4、TIDYING 5、TERMINATED 线程的生命周期 1、新建状态 通过new关键字创建出一个线程对象,没有启动之前&#xff…

Java多线程的生命周期

多线程的生命周期 1. 线程周期 NEW :新建状态。RUNNABLE:在JAVA虚拟机中执行的线程处于这个阶段BLOCKED:线程阻塞状态,被阻塞等待监视器锁定的线程处于这个状态。WAITING:正在等待另一个线程执行特定的动作的线程处于…

Java多线程(1):线程生命周期

您好,我是湘王,这是我的CSDN博客,欢迎您来,欢迎您再来~ 从事Java开发这些年来,如果要问我Java当中最难的部分是什么?最有意思的部分是什么?最多人讨论的部分是什么?那我会…

多线程的生命周期

1、线程的生命周期及五种基本状态 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t new Thread(); 就绪状态(Runnable):当调用线程对象的start()方法&…

Java线程的生命周期(有代码演示)

文章目录 概览NEWRUNNABLEBLOCKEDWAITINGTIMED_WAITINGTERMINATED 概览 Java语言中,多线程是由线程的核心概念驱动的,而线程的生命周期会经历以下的不同状态。 Java java.lang.Thread类包含了一个静态类State,它定义了线程的状态&#xff…

Java 多线程之线程的生命周期 | 图解

转载:https://www.exception.site/java-concurrency/java-concurrency-thread-life-cycle 在 Java 初中级面试中,关于线程的生命周期可以说是常客了。本文就针对这个问题,通过图文并茂的方式详细说说。 结合上图,线程的生命周期大…

java多线程之线程的生命周期

1.生命周期 一个事物从出生的那一刻开始到最终死亡中间的整个过程.在事物的漫长的生命周期过程中,总会经历不同的状态(婴儿状态/青少年状态/中年状态/老年状态...).线程也是有生命周期的,也是存在不同的状态的,状态相互之间的转换. 线程对象的状态存放在Thread类的内部类(Sta…

线程生命周期及五种状态

文章目录 一、线程生命周期及五种状态1、New(初始化状态)2、Runnable(就绪状态)3、Running(运行状态)4、Blocked(阻塞状态)5、Terminated(终止状态) 二、线程基本方法1、线程等待(wait)2、线程睡眠(sleep)3…

线程的生命周期和状态

线程的六种状态 线程的生命周期主要有以下六种状态: New(新创建)Runnable(可运行)Blocked(被阻塞)Waiting(等待)Timed Waiting(计时等待)Termin…

线程的生命周期以及其中的方法

文章目录 线程的生命周期线程的5种状态 线程的基本方法线程等待:wait 方法线程睡眠:sleep 方法线程让步:yield 方法线程中断:interrupt 方法线程加入:join 方法线程唤醒:notify 方法后台守护线程&#xff1…

Java多线程 (五)—— 线程的生命周期

文章目录 前言1、线程生命周期1.1、NEW(新建)1.2、RUNNABLE(可运行)1.3、BLOCKED(阻塞)1.4、WAITING(等待)1.5、TIMED_WAITING(计时等待)1.5、TERMINATED&…

线程的生命周期及五种基本状态

一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程各重要知识点。掌握了上图中的各知识点,Java中的多线程也就基本上掌握了。主要包括: Java线程具有五…

浅谈线程的生命周期

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态…

java中,线程的生命周期

java中,线程的生命周期 一、什么是线程? 见之前写的。 当线程启动后(线程对象调用start方法),它不能一直"独占"着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次…

JAVA 多线程并发

1.1.1. JAVA 并发知识库 1.1.2. JAVA 线程实现/创建方式 1.1.2.1. 继承 Thread 类 Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过 Thread 类的 start()实例方法。start()方法是一个 native 方法,它…

攻防世界 web高手进阶区 10分题 TimeKeeper

前言 继续ctf的旅程 开始攻防世界web高手进阶区的10分题 本文是TimeKeeper的writeup 解题过程 进入界面 惯例源码御剑 源码没发现 御剑扫到一个Flask debug console 先正常注册登录 尝试在注册和登录界面sqli 失败 没有别的头绪 就尝试研究debug 参考Flask debug pin安全问…