简易IDE

基于tkinter的简易ide,参考文档和Baidu的资料制作的,过程中遇到了很多问题,也学到了很多知识。

功能:

1、菜单栏

2、编辑功能 open save...

3、快捷键  ctrl + O...

4、主题

5、右键功能

目录:

# bg 背景图 已完毕

# ico 图标

                        

# conf.ini  配置文件

使用 configparser库进行处理, 这里只用到了读取和写入,其它详细操作Baidu一下即可。

conf.ini

[window]
program_name = Footprint Editor [icon]
newfile = ico/newFile.png
openfile = ico/open.png
savefile = ico/save.png
undofile = ico/undo.png
redofile = ico/redo.png
cutfile = ico/cut.png
copyfile = ico/copy.png
pastefile = ico/paste.png
findfile = ico/find.png [theme]
color_schemes = {
'Default': '#000000.#FFFFFF',
'Greygarious': '#83406A.#D1D4D1',
'Aquamarine': '#5B8340.#D1E7E0',
'Bold Beige': '#4B4620.#FFF0E1',
'Cobalt Blue': '#ffffBB.#3333aa',
'Olive Green': '#D1E7E0.#5B8340',
'Night Mode': '#FFFFFF.#000000'}
select_themes = Default [common]
bgstartsetting = False
bgdir = bg
bgname = default_bg.png

# textEditor.py 主要程序

textEditor.py

# -*- coding: utf-8 -*-
# fengshunagzi
# 菜单栏
# 编辑功能 打开 保存..
# 基本快捷键 剪贴 保存...
# 主题
# 右键功能 from tkinter.filedialog import *
from tkinter import *
from pathlib import Path
from PIL import Image, ImageTk
import tkinter.messagebox as tmb
import shutil
from configparser import ConfigParser
d = os.path.dirname(__file__) def exitText(event=None):
# 保存 不保存
if tmb.askokcancel("Quit?", "Really quit?"):
## 退出前自动保存文件
save()
root.destroy() def cut():
'''剪切'''
content_text.event_generate("<<Cut>>") def copy():
'''复制'''
content_text.event_generate("<<Copy>>") def paste():
'''粘贴'''
content_text.event_generate("<<Paste>>") def undo(event=None):
'''向前撤销'''
content_text.event_generate("<<Undo>>")
return 'break' def redo(event=None):
'''向后返回'''
content_text.event_generate("<<Redo>>")
return 'break' def select_all(event=None):
'''全选'''
content_text.tag_add('sel', '1.0', 'end')
return "break" def find_text(event=None):
'''搜索字段'''
search_toplevel = Toplevel(root)
search_toplevel.title('Find Text')
search_toplevel.transient(root)
search_toplevel.resizable(False, False)
Label(search_toplevel, text="Find All:").grid(row=0, column=0, sticky='e')
search_entry_widget = Entry(search_toplevel, width=25)
search_entry_widget.grid(row=0, column=1, padx=2, pady=2, sticky='we')
search_entry_widget.focus_set()
ignore_case_value = IntVar()
Checkbutton(search_toplevel, text='IgnoreCase',variable=ignore_case_value).grid(row=1, column=1, sticky='e', padx=2, pady=2)
Button(search_toplevel, text="Find All", underline=0, command=lambda: search_output( search_entry_widget.get(), ignore_case_value.get(), content_text, search_toplevel,search_entry_widget)).grid(row=0, column=2, sticky='e' + 'w', padx=2, pady=2)
def close_search_window():
'''关闭选框'''
content_text.tag_remove('match', '1.0', END)
search_toplevel.destroy()
search_toplevel.protocol('WM_DELETE_WINDOW', close_search_window)
return "break" def search_output(needle, if_ignore_case, content_text,search_toplevel, search_box):
'''匹配文字'''
content_text.tag_remove('match', '1.0', END)
matches_found = 0
if needle:
start_pos = '1.0'
while True:
start_pos = content_text.search(needle, start_pos, nocase=if_ignore_case, stopindex=END)
if not start_pos:
break
end_pos = '{}+{}c'.format(start_pos, len(needle))
content_text.tag_add('match', start_pos, end_pos)
matches_found += 1
start_pos = end_pos
content_text.tag_config('match', foreground='red', background='yellow')
search_box.focus_set()
search_toplevel.title('{} matches found'.format(matches_found)) def open_file(event=None):
'''打开文件'''
print(1)
input_file_name = askopenfilename(defaultextension=".txt", filetypes=[("All Files", "*.*"), ("Text Documents", "*.txt")])
if input_file_name:
global file_name
file_name = input_file_name
root.title('{} - {}'.format(os.path.basename(file_name),PROGRAM_NAME))
content_text.delete(1.0, END)
with open(file_name) as _file:
content_text.insert(1.0, _file.read())
update_line_numbers() def save(event=None):
'''save文件'''
global file_name
try:
if not file_name:
save_as()
else:
write_to_file(file_name)
except:
pass
return "break" def save_as(event=None):
'''另存为'''
input_file_name = asksaveasfilename(defaultextension=".txt", filetypes=[("All Files", "*.*"),("Text Documents", "*.txt")])
if input_file_name:
global file_name
file_name = input_file_name
write_to_file(file_name)
root.title('{} - {}'.format(os.path.basename(file_name),PROGRAM_NAME))
return "break" def write_to_file(file_name):
'''写入文件'''
try:
content = content_text.get(1.0, 'end')
with open(file_name, 'w') as the_file:the_file.write(content)
except IOError:
pass def new_file(event=None):
'''新建文件'''
root.title("Untitled")
global file_name
file_name = None
content_text.delete(1.0,END) def display_about_messagebox(event=None):
'''about messagebox'''
tmb.showinfo( "About", "{}{}".format(PROGRAM_NAME, "\nTkinter GUIApplication\n Development Blueprints")) def display_help_messagebox(event=None):
'''help messagebox'''
tmb.showinfo("Help", "Fuck You: \nTkinter GUI Application\n Development Blueprints", icon='question') def on_content_changed(event=None):
'''输入框发送改变时'''
update_line_numbers()
update_cursor_info_bar() def get_line_numbers():
'''获取行号'''
output = ''
if show_line_number.get():
row, col = content_text.index("end").split('.')
for i in range(1, int(row)):
output += str(i)+ '\n'
return output def update_line_numbers(event = None):
'''更新行号'''
line_numbers = get_line_numbers()
line_number_bar.config(state='normal')
line_number_bar.delete('1.0', 'end')
line_number_bar.insert('1.0', line_numbers)
line_number_bar.config(state='disabled') def highlight_line(interval=100):
'''高亮显示当前行'''
content_text.tag_remove("active_line", 1.0, "end")
content_text.tag_add("active_line", "insert linestart", "insert lineend+1c")
content_text.after(interval, toggle_highlight) def undo_highlight():
'''取消高亮'''
content_text.tag_remove("active_line", 1.0, "end") def toggle_highlight(event=None):
'''高亮切换'''
if to_highlight_line.get():
highlight_line()
else:
undo_highlight() def show_cursor_info_bar():
'''显示底部行列信息'''
show_cursor_info_checked = show_cursor_info.get()
if show_cursor_info_checked:
cursor_info_bar.pack(expand='no', fill=None, side='right', anchor='se')
else:
cursor_info_bar.pack_forget() def update_cursor_info_bar(event=None):
'''更新底部行列信息'''
row, col = content_text.index(INSERT).split('.')
line_num, col_num = str(int(row)), str(int(col)+1) # col starts at 0
infotext = "Line: {0} | Column: {1}".format(line_num, col_num)
cursor_info_bar.config(text=infotext) def change_theme(event=None):
'''修改主题'''
selected_theme = themes_choices.get()
# 写入配置文件
conf.set('theme', 'select_themes', selected_theme)
saveConf()
fg_bg_colors = color_schemes.get(selected_theme)
foreground_color, background_color = fg_bg_colors.split('.')
content_text.config(background=background_color, fg=foreground_color) def select_background(event=None):
'''选择背景图片,已经取消,因为tkinter透明度不好用'''
conf.set('common', 'bgstartsetting', 'true')
saveConf()
bgStartChecked = bgStart.get()
print('[*] 是否启用背景设置', bgStartChecked)
if bgStartChecked:
print('弹出选择文件框')
imgSelect = askopenfilename(defaultextension=".txt", filetypes=[( ".png", ".jpg"), ("Text Documents", "*.txt")])
if imgSelect:
global imgSelectName
imgSelectName = imgSelect
print(imgSelectName) # C:/Users/hz/Desktop/我的文件/我的图片/11.jpg
# 将图片拷贝到当前文件夹 修改配置参数
shutil.copyfile(imgSelectName, Path(d) / bgDir / bgName )
else:
print('隐藏图片')
print('使用主题选择的颜色') def set_background():
'''设置背景'''
pass def readSettings():
'''读取配置文件'''
global PROGRAM_NAME
PROGRAM_NAME = conf.get('window', 'PROGRAM_NAME')
global newFile
newFile = conf.get('icon', 'newFile')
global openFile
openFile = conf.get('icon', 'openFile')
global saveFile
saveFile = conf.get('icon', 'saveFile')
global undoFile
undoFile = conf.get('icon', 'undoFile')
global redoFile
redoFile = conf.get('icon', 'redoFile')
global cutFile
cutFile = conf.get('icon', 'cutFile')
global copyFile
copyFile = conf.get('icon', 'copyFile')
global pasteFile
pasteFile = conf.get('icon', 'pasteFile')
global findFile
findFile = conf.get('icon', 'findFile')
global color_schemes
color_schemes_str = conf.get('theme', 'color_schemes')
color_schemes = eval(color_schemes_str)
global select_themes
select_themes = conf.get('theme', 'select_themes')
global bgstartsetting
bgstartsetting = conf.get('common', 'bgstartsetting')
global bgDir
bgDir = conf.get('common', 'bgdir')
global bgName
bgName = conf.get('common', 'bgname') def saveConf():
'''保存配置文件'''
fp = Path(d) / 'conf.ini'
with open(fp, 'w') as fw:
conf.write(fw) def show_popup_menu(event):
'''显示右键菜单'''
popup_menu.tk_popup(event.x_root, event.y_root) if __name__ == '__main__':
## 配置文件路径
fp = Path(d) / 'conf.ini' ## 实例化
conf = ConfigParser() ## 读取配置文件
conf.read(fp, encoding='utf8') ## 配置文件编码是utf-8 ## 读取里面的内容
readSettings() ## 开始窗体部分
root = Tk() # 引入菜单
menu_bar = Menu(root)
file_menu = Menu(menu_bar, tearoff=0)
edit_menu = Menu(menu_bar, tearoff=0)
view_menu = Menu(menu_bar, tearoff=0)
about_menu = Menu(menu_bar, tearoff=0)
themes_menu = Menu(menu_bar, tearoff=0) # 添加菜单列表
menu_bar.add_cascade(label='File', menu=file_menu)
menu_bar.add_cascade(label='Edit', menu=edit_menu)
menu_bar.add_cascade(label='View', menu=view_menu)
menu_bar.add_cascade(label='About', menu=about_menu) # File菜单
imageNew = ImageTk.PhotoImage(Image.open(Path(d) / newFile))
file_menu.add_command(label='New', accelerator='Ctrl+N', compound='left', image=imageNew, command=lambda: new_file()) imageOpen = ImageTk.PhotoImage(Image.open(Path(d) / openFile))
file_menu.add_command(label='Open', accelerator='Ctrl+O', compound='left', image=imageOpen, command=lambda: open_file()) imageSave = ImageTk.PhotoImage(Image.open(Path(d) / saveFile))
file_menu.add_command(label='Save', accelerator='Ctrl+S', compound='left', image=imageSave, command=lambda: save()) file_menu.add_command(label='Save as', accelerator='Ctrl+shift+s', compound='left', image='', command=lambda: save_as()) file_menu.add_separator()
file_menu.add_command(label='Exit', accelerator='Alt+F4', compound='left', image='', command=lambda: exitText()) # Edit菜单
imageUndo = ImageTk.PhotoImage(Image.open(Path(d) / undoFile))
edit_menu.add_command(label='Undo', accelerator='Ctrl+Z', compound='left', image=imageUndo, command=lambda: undo()) imageRedo = ImageTk.PhotoImage(Image.open(Path(d) / undoFile))
edit_menu.add_command(label='Redo', accelerator='Ctrl+Y', compound='left', image=imageRedo, command=lambda: redo()) imageCut = ImageTk.PhotoImage(Image.open(Path(d) / cutFile))
edit_menu.add_command(label='Cut', accelerator='Ctrl+X', compound='left', image=imageCut, command=lambda: cut()) imageCopy = ImageTk.PhotoImage(Image.open(Path(d) / copyFile))
edit_menu.add_command(label='Copy', accelerator='Ctrl+C', compound='left', image=imageCopy, command=lambda: copy()) imagePaste= ImageTk.PhotoImage(Image.open(Path(d) / pasteFile))
edit_menu.add_command(label='Paste', accelerator='Ctrl+V', compound='left', image=imagePaste, command=lambda: paste()) edit_menu.add_separator()
edit_menu.add_command(label='Find', accelerator='Ctrl+F', compound='left', image='', command=lambda: find_text()) edit_menu.add_separator()
edit_menu.add_command(label='Select All', accelerator='Ctrl+A', compound='left', image='',command=lambda: select_all()) # About菜单
about_menu.add_command(label='About', accelerator='', compound='left', image='', command=lambda: display_about_messagebox())
about_menu.add_command(label='Help', accelerator='', compound='left', image='', command=lambda: display_help_messagebox()) # 添加横向Frame
shortcut_bar = Frame(root, height=25, background='light seagreen')
shortcut_bar.pack(expand='no', fill='x') # 添加纵向Frame
line_number_bar = Text(root, width=4, padx=3, takefocus=0, border=0, background='khaki', state='disabled', wrap='none')
line_number_bar.pack(side='left', fill='y') # 添加文本框
content_text = Text(root, wrap='word', undo=True) ## undo True 可以无限撤销 False 不能撤销 ## 给文本框保定鼠标事件 同时绑定执行函数
content_text.bind('<Control-y>', redo) # handling Ctrl + small-case y
content_text.bind('<Control-Y>', redo) # handling Ctrl + upper-case Y
content_text.bind('<Control-a>', select_all) # handling Ctrl + upper-case a
content_text.bind('<Control-A>', select_all) # handling Ctrl + upper-case A
content_text.bind('<Control-f>', find_text) #ctrl + f
content_text.bind('<Control-F>', find_text) #ctrl + F
content_text.bind('<Control-N>', new_file) #ctrl + N
content_text.bind('<Control-n>', new_file) #ctrl + n
content_text.bind('<Control-O>', open_file) #ctrl + O
content_text.bind('<Control-o>', open_file) #ctrl + o
content_text.bind('<Control-S>', save) #ctrl + S
content_text.bind('<Control-s>', save) #ctrl + s
content_text.bind('<Control-Shift-S>', save_as) #ctrl + shift + S
content_text.bind('<Control-Shift-s>', save_as) #ctrl + sgift + s
content_text.bind('<KeyPress-F1>', display_help_messagebox)
content_text.bind('<Any-KeyPress>', on_content_changed) ## 切换行号
content_text.bind('<Button-1>', on_content_changed)
content_text.tag_configure('active_line', background='ivory2') # 增加右键功能
popup_menu = Menu(content_text)
popup_menu.add_command(label='Cut', compound='left', image=imageCut, command=lambda: cut())
popup_menu.add_command(label='Copy', compound='left', image=imageCopy, command=lambda: copy())
popup_menu.add_command(label='Paste', compound='left', image=imagePaste, command=lambda: paste())
popup_menu.add_command(label='Undo', compound='left', image=imageUndo, command=lambda: undo())
popup_menu.add_command(label='Redo', compound='left', image=imageRedo, command=lambda: redo())
popup_menu.add_separator()
popup_menu.add_command(label='Select All', underline=7, command=select_all) ## 文本框绑定右键事件
content_text.bind('<Button-3>', show_popup_menu) ## 显示文本框
content_text.pack(expand='yes', fill='both') ## 增加滚动条
scroll_bar = Scrollbar(content_text)
content_text.configure(yscrollcommand=scroll_bar.set)
scroll_bar.config(command=content_text.yview)
scroll_bar.pack(side='right', fill='y') # views 添加下拉选项
show_line_number = IntVar()
show_line_number.set(1)
view_menu.add_checkbutton(label="Show Line Number", variable=show_line_number, command=update_line_numbers) show_cursor_info = IntVar()
show_cursor_info.set(1)
view_menu.add_checkbutton(label="Show Cursor Location at Bottom", variable=show_cursor_info, command=show_cursor_info_bar) to_highlight_line = BooleanVar()
to_highlight_line.set(1)
view_menu.add_checkbutton(label="HighLight Current Line", variable=to_highlight_line, command=toggle_highlight)
toggle_highlight() ## 增加分割线
view_menu.add_cascade(label="Themes", menu=themes_menu) # theme ## 增加theme菜单
themes_choices = StringVar()
themes_choices.set(select_themes)
for k,themes_choice in color_schemes.items():
themes_menu.add_radiobutton(label=k, variable=themes_choices, command=change_theme, value=k) # 添加设置背景功能
# bgStart = IntVar()
# bgStart.set(0)
# view_menu.add_checkbutton(label="Set Background", variable=bgStart, command=select_background) ## 添加快捷图标
icons = [(newFile, 'new_file'), (openFile, 'open_file'), (saveFile , 'save'),(cutFile, 'cut'), (copyFile, 'copy'), (pasteFile, 'paste'), (undoFile, 'undo'), (redoFile, 'redo'), (findFile, 'find_text')]
for i, icon in enumerate(icons):
tool_bar_icon = ImageTk.PhotoImage(Image.open(Path(d) / icon[0]))
# cmd = eval(icon)
tool_bar = Button(shortcut_bar, image=tool_bar_icon, command=eval(icon[1]))
tool_bar.image = tool_bar_icon
tool_bar.pack(side='left') ## 添加底部显示行号
cursor_info_bar = Label(content_text, text='Line: 1 | Column: 1')
cursor_info_bar.pack(expand=NO, fill=None, side=RIGHT, anchor='se') ## 配置menu
root.config(menu=menu_bar) ## 设置rootname
root.title(PROGRAM_NAME) ## 设置最小size
root.minsize(1000, 600) ## 设置居中显示
root.geometry('%dx%d+%d+%d' % ( 1000, 600, (root.winfo_screenwidth() - 1000) / 2, (root.winfo_screenheight() - 600) / 2)) ## 配置默认主题
change_theme() mainloop()

运行效果

还有其它的小功能,运行之后就知道了。

问题:本来还说增加设置背景图片的功能,遇到了问题,资料也不足。

 

tkinter 写一个简易的ide的更多相关文章

  1. Summer——从头开始写一个简易的Spring框架

    Summer--从头开始写一个简易的Spring框架                ​ 参考Spring框架实现一个简易类似的Java框架.计划陆续实现IOC.AOP.以及数据访问模块和事务控制模块. ...

  2. 手写一个简易的IOC

    这个小项目是我读过一点Spring的源码后,模仿Spring的IOC写的一个简易的IOC,当然Spring的在天上,我写的在马里亚纳海沟,哈哈 感兴趣的小伙伴可以去我的github拉取代码看着玩 地址 ...

  3. 来,我们手写一个简易版的mock.js吧(模拟fetch && Ajax请求)

    预期的mock的使用方式 首先我们从使用的角度出发,思考编码过程 M1. 通过配置文件配置url和response M2. 自动检测环境为开发环境时启动Mock.js M3. mock代码能直接覆盖g ...

  4. 如何用 Python 写一个简易的抽奖程序

    不知道有多少人是被这个头图骗进来的:) 事情的起因是这样的,上周有同学问小编,看着小编的示例代码敲代码,感觉自己也会写了,如果不看的话,七七八八可能也写的出来,但是一旦自己独立写一段程序,感觉到无从下 ...

  5. 手写一个简易的多周期 MIPS CPU

    一点前言 多周期 CPU 相比单周期 CPU 以及流水线 CPU 实现来说其实写起来要麻烦那么一些,但是相对于流水线 CPU 和单周期 CPU 而言,多周期 CPU 除了能提升主频之外似乎并没有什么卵 ...

  6. 写一个简易web服务器、ASP.NET核心知识(4)

    前言 昨天尝试了,基于对http协议的探究,我们用控制台写了一个简单的浏览器.尽管浏览器很low,但是对于http协议有个更好的理解. 说了上面这一段,诸位猜到我要干嘛了吗?(其实不用猜哈,标题里都有 ...

  7. 写一个简易浏览器、ASP.NET核心知识(3)

    前言 先在文章前面说好了,省得大家发现我根本没有这样的头发,duang的一下一堆人骂我. 这篇文章的标题有点大,其实挺low的,我需要在开头解释一下.我这里只想写一个小的控制台,旨在模拟浏览器的htt ...

  8. 结合 Vue.observable 写一个简易 Vuex

    作为 Vue 全家桶的一员,Vuex 的重要性不言而喻,不管是用来管理状态,还是封装 Controler 都很好用 不过在一些体量较小的项目中,为了几个简单的状态或者处理函数而引入 Vuex,就像是高 ...

  9. Python3的tkinter写一个简单的小程序

    一.这个学期开始学习python,但是看了python2和python3,最后还是选择了python3 本着熟悉python的原因,并且也想做一些小程序来增加自己对python的熟练度.所以写了一个简 ...

随机推荐

  1. 【问题】用ant编译时,提示编码utf为不可映射字符

    分析:eclipse默认的编码为gbk,而ant里的build.xml文件里定义的为utf-8格式.两者格式不统一. 建议:将工程的编码改成utf-8的格式,一般java工程也建议为utf-8格式.

  2. arguments.callee弃用与webuploader

    使用最近使用ueditor的时候 谷歌浏览器下上传相同图片两次后第三次上传不了 而且取消了后会出现一个错误的图片.使用的ueditor是1.4.3 后来发现 这个是 webuploader插件的问题. ...

  3. 企业面试题:Buffer与cache的区别?

    buffer缓冲 cache是缓存. 写缓冲,读缓存.简单点说,buffer是即将要被写入磁盘的,而cache是被从磁盘中读出来的.缓冲(buffers)是根据磁盘的读写设计的,把分散的写操作集中进行 ...

  4. 遇见 TiDB

    遇见 TiDB 文章来源:企鹅号 - 塔塔驿站 最近TiDB掀起了一波分布式数据库的热潮,公司也在着手准备TiDB的落地工作,前几天也参与了几场公司针对TiDB的分享会,下面我们了解一下关于TiDB. ...

  5. SpringBoot下如何配置实现跨域请求?

    一.什么是跨域请求? 跨域请求,就是说浏览器在执行脚本文件的ajax请求时,脚本文件所在的服务地址和请求的服务地址不一样.说白了就是ip.网络协议.端口都一样的时候,就是同一个域,否则就是跨域.这是由 ...

  6. js 数字随机滚动(数字递增)

    HTML: <div class="textMon"> <img src="./img/20180830160315.png" alt=&qu ...

  7. 消息队列MQ】各类MQ比较

    目前业界有很多MQ产品,我们作如下对比:RabbitMQ 是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正是如此,使的它变的非常重量级 ...

  8. #考研笔记#计算机之word问题

    Word 问题:1. 如何为文档加密保存?单击 office 按钮\另存为\工具按钮\常规选项\设置打开文件时的密码 2. 怎样在横格稿纸中录入古诗?单击 office 按钮\新建\模板\信纸\稿纸( ...

  9. 【SpringBoot】服务器端主动推送SSE技术讲解

    =====================16.高级篇幅之SpringBoot2.0服务器端主动推送SSE技术讲解 ============================ 1.服务端推送常用技术介绍 ...

  10. /etc/hosts和/etc/hostname区别

    /etc/hosts主要是ip和域名的对应 /etc/hostname主要是本地主机域名(本地主机名修改过后需要重启服务器才能生效) 如果我想在另一台linux主机里面使用域名访问上面这台主机A,只需 ...