本文旨在采取界面与交互分离的方式构建一个基本的文本编辑器,目前仅完成了一半。目前有部分菜单逻辑交互方式借鉴了此片博文的方法http://m.blog.csdn.net/article/details?id=50669230
一、首先是主界面UI,完成界面整体需求布局--TestTextUI:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import PyTkinter
import tkinter
from tkinter import *
import Adaptive
import os
from tkinter.filedialog import *
font = Adaptive.monaco_font
class TestTextUI(object):
def __init__(self, master=None):
self.root = master
'''
1.create the up frame: text frame
2.create the down frame: status frame
'''
self.editframe = PyTkinter.PyLabelFrame(self.root)
self.infoframe = PyTkinter.PyLabelFrame(self.root, height=2)
self.editframe.pack(fill=BOTH, expand=1)
self.infoframe.pack(fill=X)
'''
create the edit frame
'''
self.number_editframe = PyTkinter.PyLabel(self.editframe,
width=4)
self.content_editframe = PyTkinter.PyText(self.editframe,
width=120)
#self.content_editframe.insert('1.0', 'hello world')
self.number_editframe.pack(fill=Y, side=LEFT)
self.content_editframe.pack(fill=BOTH, expand=1, side=RIGHT)
'''
create the info frame
'''
self.line_column_label = PyTkinter.PyLabel(self.infoframe,
text="Line ,Column ",
font=font,
height=2)
self.line_column_label.pack(fill=X, side=LEFT)
#the test code
if __name__ == "__main__":
root = tkinter.Tk()
root.geometry('+120+50')
ttUI = TestTextUI(master=root)
ttUI.content_editframe.delete('1.0', END)
ttUI.content_editframe.insert('1.0', 'hello world!')
root.mainloop()
二、这里UI界面的控件进行了一定程度的重写,使之更加符合软件界面风格--PyTkinter
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
initial the Tkinter component
'''
import tkinter
g_default_theme = "dark"
class PyButton(tkinter.Button):
'''
button component
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tkinter.Button.__init__(self, master, self.temp)
def choose_theme(self):
if self.theme == "dark":
#the dictionary of the color property
dark_theme_dict = {
"activebackground": "#00B2EE",
"activeforeground": "#E0EEEE",
"bg": "#008B8B",
"fg": "#FFFFFF"
}
#for initialing the property of the color of button
for key,value in dark_theme_dict.items():
self.temp[key] = value
#to fill the text of the component
for key,value in self.kv.items():
self.temp[key] = value
class PyLabel(tkinter.Label):
'''
Label component
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tkinter.Label.__init__(self,master,self.temp)
def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg":"#292929",
"fg":"#E0EEEE"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value
for key,value in self.kv.items():
self.temp[key] = value
class PyLabelFrame(tkinter.LabelFrame):
'''
Frame component
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tkinter.LabelFrame.__init__(self,master,self.temp)
def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg":"#292929",
"fg":"#1e90ff"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value
for key,value in self.kv.items():
self.temp[key] = value
class PyListbox(tkinter.Listbox):
'''
Listbox component
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tkinter.Listbox.__init__(self,master,self.temp)
def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg":"#292929",
"fg":"#1e90ff",
"selectbackground":"#00b2ee"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value
for key,value in self.kv.items():
self.temp[key] = value
class PyText(tkinter.Text):
'''
Listbox component
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tkinter.Text.__init__(self,master,self.temp)
def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg":"#292929",
"fg":"#1e90ff",
"selectbackground":"#00b2ee"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value
for key,value in self.kv.items():
self.temp[key] = value
class PyCheckbutton(tkinter.Checkbutton):
'''
Checkbutton component
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tkinter.Checkbutton.__init__(self,master,self.temp)
def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg":"#292929",
"fg":"#1e90ff",
"activebackground":"#292929",
"activeforeground":"#ffffff",
"selectcolor":"#292929"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value
for key,value in self.kv.items():
self.temp[key] = value
class PyRadiobutton(tkinter.Radiobutton):
'''
Radiobutton component
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tkinter.Radiobutton.__init__(self,master,self.temp)
def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg":"#292929",
"fg":"#1e90ff",
"activebackground":"#292929",
"selectcolor":"#292929"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value
for key,value in self.kv.items():
self.temp[key] = value
class PyEntry(tkinter.Entry):
'''
Entry component
'''
def __init__(self, master, theme=g_default_theme, **kv):
self.theme = theme
self.kv = kv
self.temp = dict()
self.choose_theme()
tkinter.Entry.__init__(self,master,self.temp)
def choose_theme(self):
if self.theme == "dark":
dark_theme_dict = {
"bg":"#292929",
"fg":"#1e90ff",
"insertbackground":"#e0eeee"
}
for key,value in dark_theme_dict.items():
self.temp[key] = value
for key,value in self.kv.items():
self.temp[key] = value
#the test code
if __name__ == "__main__":
root = tkinter.Tk()
PyButton(root, text="123",font=("Monaco",12)).pack()
PyLabel(root, text="123",font=("Monaco",12)).pack()
PyLabelFrame(root, text="123",font=("Monaco",12)).pack()
listbox_0 = PyListbox(root, height=2, font=("Monaco", 15))
listbox_0.pack()
for i in range(2):
listbox_0.insert("end", i)
PyText(root, font=("Monaco", 15), height=3,width = 20).pack()
PyCheckbutton(root, text="123", font=("Monaco", 15)).pack()
radio_intvar = tkinter.IntVar()
PyRadiobutton(root, text="001", variable=radio_intvar, value=0, font=("Monaco", 15)).pack()
PyRadiobutton(root, text="002", variable=radio_intvar, value=1, font=("Monaco", 15)).pack()
PyRadiobutton(root, text="003", variable=radio_intvar, value=2, font=("Monaco", 15)).pack()
radio_intvar.set(1)
PyEntry(root, font=("Monaco", 15)).pack()
root.mainloop()
三、接下来需要将软件整体框架和菜单栏进行整合,这里我还不太清楚如何将菜单栏分离为一个class进行添加,整体的menu都直接依赖于root--TestTextV0.3
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from TestTextUI import TestTextUI
from tkinter import *
from tkinter.filedialog import *
from MenuCommand import *
class TestText(object):
#create a initial frame
def __init__(self):
#create the base frame
self.root = Tk()
self.root.title('TestText')
self.root.geometry('+120+60')
#self.ttUI = TestTextUI(master=self.root)
self.mc = MenuCommand()
#create the menubar frame
self.menubar = Menu(self.root, bg='purple')
#create the filemenu frame
self.filemenu = Menu(self.menubar, tearoff=0)
self.filemenu.add_command(label='New File', accelerator='Ctrl+n',
command=self.mc.newfile, underline=0)
self.filemenu.add_command(label='Open File', accelerator='Ctrl+o',
command=self.mc.openfile, underline=0)
self.filemenu.add_command(label='Save', accelerator='Ctrl+s',
command=self.mc.savefile, underline=0)
self.filemenu.add_command(label='Save As', command=self.mc.saveasfile, underline=0)
self.filemenu.add_separator()
self.filemenu.add_command(label='Exit', accelerator='Ctrl+t',
command=self.root.destroy, underline=0)
self.menubar.add_cascade(label='File', underline=0, menu=self.filemenu)
#create the editmenu frame
self.editmenu = Menu(self.menubar, tearoff=0)
self.editmenu.add_command(label='Undo', accelerator='Ctrl+z',
command=self.mc.undoedit, underline=0)
self.editmenu.add_command(label='Redo', accelerator='Ctrl+z',
command=self.mc.redoedit, underline=0)
self.menubar.add_cascade(label='Edit', underline=0, menu=self.editmenu)
#create the optionmenu frame
self.optionmenu = Menu(self.menubar, tearoff=0)
self.optionmenu.add_command(label='Configuration', command=self.mc.configText, underline=0)
self.menubar.add_cascade(label='Options', underline=0, menu=self.optionmenu)
#create the helpmenu frame
self.helpmenu = Menu(self.menubar, tearoff=0)
self.helpmenu.add_command(label='About', command=self.mc.aboutText, underline=0)
self.menubar.add_cascade(label='Help', underline=0, menu=self.helpmenu)
self.root.config(menu=self.menubar)
self.root.mainloop()
if __name__ == "__main__":
TestText()
四、根据菜单功能需求添加菜单反馈函数集--MenuCommand
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
menu command array
'''
from TestTextUI import TestTextUI
from tkinter.filedialog import *
class MenuCommand(object):
def __init__(self):
#print('Open MenuCommand')
self.ttUI = TestTextUI()
self.var = StringVar()
pass
def newfile(self):
print("create a new file")
def openfile(self):
print("open a file")
filetypes = [
("All Files", '*'),
("Python Files", '*.py', 'TEXT'),
("Text Files", '*.txt', 'TEXT'),
("Config Files", '*.conf', 'TEXT')]
fobj = askopenfile(filetypes=filetypes)
if fobj:
self.ttUI.content_editframe.delete('1.0', END)
self.ttUI.content_editframe.insert('1.0', fobj.read())
def savefile(self):
print("save a file")
value = self.var.get().strip()
if value:
f = open(value, 'w')
f.write(self.ttUI.content_editframe.get('1.0', END).strip() + '\n')
f.close()
else:
self.saveasfile()
def saveasfile(self):
print("save as a renamefile")
text_value = self.ttUI.content_editframe.get('1.0', END).strip()
if text_value:
fobj = asksaveasfile()
if fobj:
fobj.write(text_value + '\n')
def undoedit(self):
print("return last status")
def redoedit(self):
print("return next status")
def configText(self):
print("the configuration of the TextIdle")
def aboutText(self):
print("the TextIdle info")
#the test code
if __name__ == "__main__":
mc = MenuCommand()
mc.newfile()
以上就是个人目前完成的包含基础功能的文本编辑器的全部代码了,这里还有许多进行需要优化的功能,这里先简要列几条作为后期优化改进的方向:
1、完善菜单功能,尤其是configuration功能,满足个性化修改界面外观的需求,undo&redo的功能
2、完善路径填充功能,满足title显示文件路径的需求
3、完善行显示的功能,text左侧直接显示当前光标所在行,底部状态显示当前光标所在行列值
4、完善多文件显示/切换功能,菜单栏下方直接留出一栏显示当前已打开的文件
5、完善缓存/记忆功能,保障关闭软件后仍旧能够记忆已打开的文件,下次打开时仍旧可以显示
6、完善文本高亮显示功能,能够根据打开的文件类型对相应的关键之进行高亮显示
……
以上为个人完成的一个简单的文本编辑器及对后续更新的相关思考,欢迎交流和指正~