【Python】使用tkinter设计开发Windows桌面程序记事本(5)

news2025/5/22 17:30:26

上一篇:【Python】使用tkinter设计开发Windows桌面程序记事本(4)-CSDN博客

下一篇:待羽翼丰满之时,必将是文章更新之日!

作者发炎

本篇文章继承了前面四篇文章,并且实现了新建、保存、另存、打开、页面设置、退出功能。

现阶段我还不能实现打印功能,而新窗口要在最后阶段完成,所有我选择忽略这两个功能。

近期我将暂停本项目进度更新(能力受限),但博客文章不受影响,会不定期发布。

有疑问或建议,欢迎在评论区戳我哟!

设计步骤

 在"记事本项目" --> "code"目录下新建了一个"记事本功能设计_2.py"文件,开始本阶段的项目设计开发,如下图:

运行结果

导入【记事本项目.code.记事本底座】
导入【记事本项目.code.记事本功能设计_1】
导入【记事本项目.code.记事本_页面设置】
导入【记事本项目.code.记事本_页面设置功能设计_1】
光标位置:行 1 列 1
1editText: ['\n']
2editText: ['\n']
2readText: ['']
    ...
    ...
    ...
光标位置:行 7 列 16
1editText: ['本篇文章实现了新建、保存、另存、打开、页面设置、退出功能\n\n不足的是新窗口和打印功能未实现\n\n但是近期我将暂停本项目的更新,假以时日,羽翼丰满,再更新\n\n欢迎关注我的动态,一起变得更强!\n']
2editText: ['本篇文章实现了新建、保存、另存、打开、页面设置、退出功能\n\n不足的是新窗口和打印功能未实现\n\n但是近期我将暂停本项目的更新,假以时日,羽翼丰满,再更新\n\n欢迎关注我的动态,一起变得更强!\n']
2readText: ['']
光标位置:行 7 列 17

代码示例:记事本功能设计_2.py

"""
    记事本功能设计

不足:
    1.新窗口未完成,因为现在实现的话,会局限这里(功能不完全),所以要在最后实现
    2.打印未实现,能力所限,只好忽略
    3.在点击菜单栏后理应该可以与键盘交互,但未实现,因为Menu()没有鼠标焦点属性

"""

# 通配符 "*"
__all__ = ['Notepad_2']

# 导入内置模块
import tkinter.messagebox as tkmb
import tkinter.filedialog as tkfd

# 导入"记事本功能设计_1"模块
from 记事本项目.code.记事本功能设计_1 import Notepad_1
# 导入"记事本_页面设置功能设计_1"模块
from 记事本项目.code.记事本_页面设置功能设计_1 import PageSetup_1


class Notepad_2(Notepad_1):
    """ 继承Notepad_1, 设计记事本功能 """
    def __init__(self):
        """ 重写父类的构造方法 """
        # 调用父类的构造方法
        super().__init__()

        """ 开始对记事本功能进行设计 """

        self.readText = ''  # 读取编辑区文本数据

        # 新建(N)
        self.fileMenu.entryconfigure(0, command=self.newText)
        """ 新窗口(W)要在最后完成,因为"新窗口"需要完整的功能 """
        # self.fileMenu.entryconfigure(1, command=self.xxx)
        # 打开(O)...
        self.fileMenu.entryconfigure(2, command=self.openFile)
        # 保存(S)
        self.fileMenu.entryconfigure(3, command=self.saveFile)
        # 另存为(A)...
        self.fileMenu.entryconfigure(4, command=self.saveAsFile)
        """ 页面设置(U)...需要单独一个继承类来完成 """
        self.fileMenu.entryconfigure(6, command=self.pageSetup)
        """ 打印(P)... 水平有限,功能未完成 """
        # self.fileMenu.entryconfigure(7, command=self.xxx)
        # 退出
        self.fileMenu.entryconfigure(9, command=self.destroy)

        # 捆绑按键按下编辑文本事件
        self.bind('<KeyPress>', self.editText)
        # 新建文本 键盘触发
        self.bind('<Control-Key-n>', self.newText)
        """ 新窗口未实现 """
        # self.bind('Control-Shift-Key-N>', self.xxx)
        # 打开文件(BUG) 键盘触发
        self.bind('<Control-Key-o>', self.openFile)
        # 保存文件 键盘触发
        self.bind('<Control-Key-s>', self.saveFile)
        # 文件另存为 键盘触发
        self.bind('<Control-Shift-Key-S>', self.saveAsFile)
        """ 打印未实现 """
        # self.bind('Control-Key-p>', self.xxx)


    # 页面设置
    def pageSetup(self, event=None):
        pageSetup_ui = PageSetup_1()    # 实例化"页面设置"UI


    # 文件另存为
    def saveAsFile(self, event=None):
        global openPath
        # 文件保存类型
        filetypes = [("文本文档", ".txt"), ("所有文件", ".*")]
        # 保存文件对话框
        savePath = tkfd.asksaveasfile(defaultextension=".txt", initialfile='*.txt', filetypes=filetypes)
        # 确定保存
        if savePath:
            # 把文本编辑的数据写入文件
            with open(savePath.name, 'w', encoding=savePath.encoding) as file:
                file.write(self.text.get('1.0', 'end')[:-1:])
            # 窗口标题前去掉'*'
            self.title(self.title()[1::])
            # 修改标题
            self.title(f'{savePath.name.split("/")[-1]} - 记事本')
            self.readText = self.text.get('1.0', 'end')[:-1:]
            openPath = savePath


    # 保存文件
    def saveFile(self, event=None):
        global openPath
        # 判断文本是否编辑过
        if self.title()[0] == '*':
            self.bell()  # 警告声
            # 从程序打开进入的编辑
            if not self.readText:
                # 消息对话框选择是否保存
                ifYes = tkmb.askyesnocancel('记事本', f'你想将更改保存到 无标题 吗?')
                # 如果选择是
                if ifYes:
                    # 文件另存为
                    self.saveAsFile()

            # 打开文件后保存
            else:
                # 保存文本数据,写入文件
                with open(openPath.name, 'w', encoding=openPath.encoding) as file:
                    file.write(self.text.get('1.0', 'end')[:-1:])
                # 窗口标题前去掉'*'
                self.title(self.title()[1::])
                self.readText = self.text.get('1.0', 'end')[:-1:]


    # 打开文件
    def openFile(self, keyTrigger=None):
        global openPath
        ifYes = True
        savePath = True
        # 如果是键盘触发(必须)
        if keyTrigger:
            # 键盘Ctrl+O 触发,光标处会加入换行(不知道是否为BUG,求指教)
            self.text.delete('1.0', 'end')
            self.text.insert('1.0', self.textGet[:-1:])

        # 判断文本是否编辑过
        if self.title()[0] == '*':
            self.bell()  # 警告声
            # 从程序打开进入的编辑
            if not self.readText:
                fileName = f'你想将更改保存到 {self.title().split(" ")[0][1::]} 吗?'
            # 从文件打开进入的编辑
            else:
                fileName = f'你想将更改保存到\n{openPath.name}\n吗?'

            # 在消息对话框选择是否保存当前编辑的文本
            ifYes = tkmb.askyesnocancel('记事本', fileName)
            # 确定
            if ifYes:
                # 判断保存的文件是否存在
                if not self.readText:
                    # 文件另存为
                    self.saveAsFile()
                else:
                    # 保存文本数据,写入文件
                    with open(openPath.name, 'w', encoding=openPath.encoding) as file:
                        file.write(self.text.get('1.0', 'end')[:-1:])
                    # 窗口标题前去掉'*'
                    self.title(self.title()[1::])
                    self.readText = self.text.get('1.0', 'end')[:-1:]

        # 打开文件
        if ifYes != None and savePath:
            # 消息对话框打开文件
            # must be -defaultextension, -filetypes, -initialdir, -initialfile, -multiple, -parent, -title, or -typevariable
            filetypes = [('文本文档', '.txt'), ('所有文件', '.*')]
            # 打开文件对话框
            self.openPath = tkfd.askopenfile(filetypes=filetypes)
            # 确定打开文件
            if self.openPath:
                openPath = self.openPath
                # 窗口初始化
                self.text.delete('1.0', 'end')
                self.readText = ''
                # 打开文件读取数据插入到文本域
                with open(self.openPath.name, 'r', encoding=self.openPath.encoding) as file:
                    for i in file:
                        self.text.insert('end', i)
                        # 更新文本读取数据
                        self.readText += i
                # 修改窗口标题
                self.title(f'{self.openPath.name.split("/")[-1]} - 记事本')
                self.event_generate('<Key>')
                # 数据更新


    # 新建文本
    def newText(self, event=None):
        ifYes = True
        savePath = True
        # 判断文本是否编辑过
        if self.title()[0] == '*':
            self.bell()  # 警告声
            # 从程序打开进入的编辑
            if not self.readText:
                fileName = f'你想将更改保存到 {self.title().split(" ")[0][1::]} 吗?'
            # 从文件打开进入的编辑
            else:
                fileName = f'你想将更改保存到\n{openPath.name}\n吗?'

            # 在消息对话框选择是否保存当前编辑的文本
            ifYes = tkmb.askyesnocancel('记事本', fileName)
            # 确定
            if ifYes:
                # 判断保存的文件是否存在
                if not self.readText:
                    # 文件保存类型
                    filetypes = [("文本文档", ".txt"), ("所有文件", ".*")]
                    # 保存文件对话框
                    savePath = tkfd.asksaveasfile(defaultextension=".txt", initialfile='*.txt', filetypes=filetypes)
                    # 确定保存
                    if savePath:
                        # 把文本编辑的数据写入文件
                        with open(savePath.name, 'w', encoding=savePath.encoding) as file:
                            file.write(self.text.get('1.0', 'end')[:-1:])
                else:
                    # 保存文本数据,写入文件
                    with open(openPath.name, 'w', encoding=openPath.encoding) as file:
                        file.write(self.text.get('1.0', 'end')[:-1:])

        # 初始化窗口
        if ifYes != None and savePath:
            self.title('无标题 - 记事本')
            self.readText = ''
            self.text.delete('1.0', 'end')
            self.event_generate('<Key>')


    # 编辑Text文本
    def editText(self, event=None):
        print('1editText:', [self.text.get('1.0', 'end')])
        data = self.text.get('1.0', 'end')
        # 文本编辑时窗口标题前加入'*'
        if data[:-1:] != self.readText and data != '\n' and self.title()[0] != '*':
            self.title('*' + self.title())
        # 编辑过文本未保存或与原文本相同时窗口标题前去掉'*'
        elif data[:-1:] == self.readText or data == '\n':
            if self.title()[0] == '*':
                self.title(self.title()[1::])

        # 如果是键盘Ctrl+O触发打开文件(必须)
        self.textGet = self.text.get('1.0', 'end')

        print('2editText:', [self.text.get('1.0', 'end')])
        print('2readText:', [self.readText])


# 代码测试
if __name__ == '__main__':
    ui = Notepad_2()    # 实例化记事本UI
    ui.mainloop()       # 循环窗口运行
else:
    print(f'导入【{__name__}】')

作者:周华

创作日期:2024/1/13

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1382119.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Open3D 计算点云质心和中心(18)

Open3D 计算点云质心和中心(18) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 质心和中心是有所区别的,点云质心可以看作每个点的坐标均值,点云中心可以看作点云所在包围盒的中心,这也是上一章坐标最值的常用方法,下面就两种方法进行实现(图例,大概就是这个意思…

JVM工作原理与实战(十五):运行时数据区-程序计数器

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、运行时数据区 二、程序计数器 总结 前言 JVM作为Java程序的运行环境&#xff0c;其负责解释和执行字节码&#xff0c;管理内存&#xff0c;确保安全&#xff0c;支持多线程和提供…

电子学会C/C++编程等级考试2023年09月(四级)真题解析

C/C++编程(1~8级)全部真题・点这里 第1题:酒鬼 Santo刚刚与房东打赌赢得了一间在New Clondike 的大客厅。今天,他来到这个大客厅欣赏他的奖品。房东摆出了一行瓶子在酒吧上。瓶子里都装有不同体积的酒。令Santo高兴的是,瓶子中的酒都有不同的味道。房东说道:“你可以喝尽…

用ChatGPT写论文的重要指令

使用ChatGPT写论文&#xff0c;chatgpt3.5的普通版本与ChatGPTPLUS版本我都尝试过&#xff0c;这里我还是比较喜欢ChatGPTPLUS来写论文 快速订阅ChatGPTPLUS方法&#xff0c;0年费、0月费 具体步骤可参考 亲测&#xff0c;Chatgpt4.0充值&#xff08;虚拟卡充值&#xff09;-…

网络安全B模块(笔记详解)- 网络渗透测试

LAND网络渗透测试 1.进入虚拟机操作系统:BT5中的/root目录,完善该目录下的land.py文件,填写该文件当中空缺的Flag1字符串,将该字符串作为Flag值(形式:Flag1字符串)提交;(land.py脚本功能见该任务第6题) 输入flag sendp(packet) Flag:sendp(packet) 2.进入虚拟机操作…

QSpace:Mac上的简洁高效多窗格文件管理器

在Mac用户中&#xff0c;寻找一款能够提升文件管理效率的工具是常见的需求。QSpace&#xff0c;一款专为Mac设计的文件管理器&#xff0c;以其简洁的界面、高效的多窗格布局和丰富的功能&#xff0c;为用户提供了一个全新的文件管理体验。 QSpace&#xff1a;灵活与功能丰富的结…

CMake+QT+大漠插件的桌面应用开发

文章目录 CMakeQT大漠插件的桌面应用开发说明环境项目结构配置编译环境代码 CMakeQT大漠插件的桌面应用开发 说明 在CMake大漠插件的应用开发——处理dm.dll&#xff0c;免注册调用大漠插件中已经说明了如何免注册调用大漠插件&#xff0c;以及做了几个简单的功能调用&#x…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 第1章 HTML5+CSS3初体验 项目1-1 三栏布局页面

项目展示 三栏布局是一种常用的网页布局结构。 除了头部区域、底部区域外&#xff0c;中间的区域&#xff08;主体区域&#xff09;划分成了三个栏目&#xff0c;分别是左侧边栏、内容区域和右侧边栏&#xff0c;这三个栏目就构成了三栏布局。当浏览器的宽度发声变化时&#x…

最全对象存储(云盘)挂载本地主机或服务器

1.对象存储介绍 1.1 分类 分布式存储的应用场景相对于其存储接口&#xff0c;现在流行分为三种: 块存储: 这种接口通常以QEMU Driver或者Kernel Module的方式存在&#xff0c;这种接口需要实现Linux的Block Device的接口或者QEMU提供的Block Driver接口&#xff0c;块存储一般…

androidkiller的两种异常情况

第一种反编译时异常&#xff1a; Exception in thread “main” org.jf.dexlib2.dexbacked.DexBackedDexFile$NotADexFile: Not a valid dex magic value: cf 77 4c c7 9b 21 01 修改方法&#xff1a; 编辑 AndroidKiller 的 bin/apktool 目录下有一个 apktool.bat 文件 修改成…

nmealib 库移植 - -编译报错不完全类型 error: field ‘st_atim’ has incomplete type

一、报错提示-不完全类型(has incomplete type) Compiling obj/main.o from main.c.. arm-linux-gcc -g -w -stdgnu99 -DLINUX -I./ -Inmealib/inc/ -c -o obj/main.o main.c In file included from /home/user/Desktop/nuc980-sdk/sdk/arm_linux_4.8/usr/include/sys/stat…

豆包ai介绍

豆包是字节跳动基于云雀模型开发的AI工具&#xff0c;具有强大的语言处理能力和广泛的应用场景&#xff0c;无论是在学习、工作、生活中&#xff0c;都能派上用场。 豆包可以帮助打工人和创作者提升效率&#xff0c;完成各种工作任务&#xff0c;又能扮演各类AI角色进行高情商…

2003-2021年地级市知识产权保护水平数据

2003-2021年地级市知识产权保护水平数据 1、时间&#xff1a;2003-2021年 2、指标&#xff1a;city、year、地方知识产权审判结案数、地方GDP、国内知识产权审判结案数、国内GDP、知识产权保护水平 3、来源&#xff1a;北大法宝、城市年鉴、统计年鉴、历年知识产权保护状况白…

SpringMVC(六)RESTful

1.RESTful简介 REST:Representational State Transfer,表现层资源状态转移 (1)资源 资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件…

场效应管在电路中如何控制电流大小

场效应管的概念 场效应晶体管&#xff08;FieldEffectTransistor缩写&#xff08;FET&#xff09;&#xff09;简称场效应管。主要有两种类型&#xff08;juncTIonFET—JFET&#xff09;和金属-氧化物半导体场效应管&#xff08;metal-oxidesemiconductorFET&#xff0c;简称M…

Linux完全卸载Anaconda3和MiniConda3

如何安装Anaconda3和MiniConda3请看这篇文章&#xff1a; 安装Anaconda3和MiniConda3_minianaconda3-CSDN博客文章浏览阅读474次。MiniConda3官方版是一款优秀的Python环境管理软件。MiniConda3最新版只包含conda及其依赖项如果您更愿意拥有conda以及超过720个开源软件包&…

关联规则分析(Apriori算法2

目录 1.核心术语&#xff1a;2.强关联规则&#xff1a;小结&#xff1a; 1.核心术语&#xff1a; 支持度&#xff08;Support&#xff09;&#xff1a;指项集出现的频繁程度&#xff08;相当于项集出现的概率&#xff09; 最小支持度有绝对值和占比两种表示方式 置信度&#…

一个月带你手撕LLM理论与实践,并获得面试or学术指导!

大家好&#xff0c;我是zenRRan&#xff0c;是本号的小号主。 从该公众号的名字就能看出&#xff0c;运营已经好多年了&#xff0c;这些年当中直接或间接帮助很多同学从NLP入门到进阶&#xff0c;理论到实践&#xff0c;学校到企业&#xff0c;本科到硕士甚至博士。 每天习惯性…

buuctf-Misc 题目解答分解115-117

115.派大星的烦恼 解压下载文件时一个 bmp 文件&#xff0c;用notepad 打开有没有发现什么 &#xff0c;提示位图什么的 用Stegsolve.jar 打开 发现很多. 和- 第一时间想到了 电报码 但提示不是电报码&#xff0c;除了这个那就是很像二进制了 0,1 什么的&#xff0c;但这个感觉…

Vue中v-if与v-show区别详解

✨ 专栏介绍 在当今Web开发领域中&#xff0c;构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架&#xff0c;正是为了满足这些需求而诞生。它采用了MVVM架构模式&#xff0c;并通过数据驱动和组件化的方式&#xff0c;使…