上一期我们大致分析了一个IDE应具有的功能,这一期就把这些“小功能”全部实现。
文件功能
这个功能与记事本的文件功能一样,而且简单一点。
def pynew():
global textPad,filename
textPad.delete(1.0,tk.END)
filename='newfile.py'
def pyopen():
global textPad,filename
filename2=askopenfilename(defaultextension='.py')
if filename2 != '':
textPad.delete(1.0,tk.END)
f=open(filename2,'r',encoding='utf-8',errors='ignore')
textPad.insert(1.0,f.read())
f.close()
filename=filename2
def pysave():
global textPad,filename
filename = asksaveasfilename(initialfile = filename,defaultextension ='.py')
if filename != '':
fh = open(filename,'w',encoding='utf-8',errors='ignore')
msg = textPad.get(1.0,tk.END)
fh.write(msg)
fh.close()
上面的代码就是文件功能了,运行效果如下:
编辑功能
这个功能看似实用又难做,实际上没什么太大用处,而且不是很难。键盘快捷键全可以解决。
既然提到快捷键了就写写实用的快捷键吧:
Ctrl+C 复制
Ctrl+V 粘贴
Ctrl+T 剪切
Ctrl+A 全选
Ctrl+Z 撤销
Win+R 运行
Win+I 设置
…貌似Win+A~Z都有对应的快捷键…
Win+. 图形和表情(这个经常被忽略)
快捷键还有很多,这里不再一一列举了。
回归正题,继续写我们的编辑功能
def cut():
global textPad
textPad.event_generate("<<Cut>>")
def copy():
global textPad
textPad.event_generate("<<Copy>>")
def paste():
global textPad
textPad.event_generate("<<Paste>>")
def undo():
global textPad
textPad.event_generate("<<Undo>>")
def redo():
global textPad
textPad.event_generate("<<Redo>>")
def select_all():
global textPad
textPad.tag_add("sel", "1.0", "end")
效果如下:
运行功能
这里的运行功能只是一个按钮,还没有任何相关代码。这里就把它们全放在一个菜单里了。
直接上代码:
runmenu = tk.Menu(menubar, tearoff=False)
runmenu.add_command(label="运行", accelerator="", command=runpy)
runmenu.add_command(label="更改文件位置", accelerator="", command=selectdirectory)
menubar.add_cascade(label="运行", menu=runmenu)
上面代码是一个菜单,selectdirectory函数的代码如下:
def selectdirectory():
path_ = askdirectory()
tree.clear()
tree.load_path(path_ )
树控件
在selectdirectory函数函数里有tree.***
的代码,这里的tree就是树控件。
声明:树控件这里需要借鉴HP_tk模块,这里只有改版后的HP_tk模块,具体HP_tk完整模块请与原著(荷蒲)联系。
这里需要新建一个文件,名字命名为core.py,其核心代码如下:
class Tree(tk.Frame):
def __init__(self, master=None,ico=True,**kw):
tk.Frame.__init__(self, master,**kw)
self.root = master
self.index=None
self.ico=ico
self.col = [1,2]
self.tree=ttk.Treeview(self)
self.usepop=None
self.tree_root=None
self.tree.pack(fill=tk.BOTH, expand=tk.YES,side = tk.LEFT)
self.xscroll = tk.Scrollbar(self.tree, orient=tk.HORIZONTAL, command=self.tree.xview)
self.tree.configure(xscrollcommand = self.xscroll.set)
self.xscroll.pack(side = tk.BOTTOM, fill = tk.X)
self.yscrollbar = tk.Scrollbar(self.tree, orient=tk.VERTICAL, command=self.tree.yview)
self.tree.configure(yscrollcommand = self.yscrollbar.set)
self.yscrollbar.pack(side = tk.RIGHT, fill = tk.Y)
self.tree.bind("<Double-Button-1>", self.popup)
def delete_tree(self):
items =self.tree.get_children()
[self.tree.delete(item) for item in items]
def clear(self):
items =self.tree.get_children()
[self.tree.delete(item) for item in items]
def load_path(self,path='.'):
self.img= tk.PhotoImage(file="ico/open2.gif")
self.abspath = os.path.abspath(path)
if self.ico:
self.root_node = self.tree.insert('', 'end', text=self.abspath, open=True,image=self.img)
else:
self.root_node = self.tree.insert('', 'end', text=self.abspath, open=True)
self.process_directory(self.root_node, self.abspath)
self.fix_last()
def process_directory(self, parent, path):
for p in os.listdir(path):
abspath = os.path.join(path, p)
isdir = os.path.isdir(abspath)
if self.ico:
oid = self.tree.insert(parent, 'end', text=p, open=False)
else:
oid = self.tree.insert(parent, 'end', text=p, open=False)
if isdir:
self.process_directory(oid, abspath)
def process_dict(self,d, tr='',ii=0):
i=ii
for k,v in d.items():
i+=1
if type(v) == list:
if type(v[0]) == dict:
if self.ico:
trr = self.tree.insert(tr, 'end', text=k, open=True,image=imgx)
else:
trr = self.tree.insert(tr, 'end', text=k, open=True)
for ls in v:
i+=1
self.process_dict(ls, trr,i)
else:
if self.ico:
self.tree.insert(tr, 'end', text=k, values= v,image=imgx)
else:
self.tree.insert(tr, 'end', text=k, values= v)
elif type(v) == dict:
if self.ico:
trr = self.tree.insert(tr, 'end', text=k, open = True,image=imgx)
else:
trr = self.tree.insert(tr, 'end', text=k, open = True)
self.process_dict(v, trr,i)
def load_dict(self,d):
self.process_dict(d)
self.fix_last()
def fix_last(self):
children = self.tree.get_children()
idd=children[-1]
children = self.tree.get_children(idd)
idd=children[-1]
if idd !='I001':
if self.ico:
self.tree.item(idd)
else:
self.tree.item(idd)
def popup(self,event):
if self.usepop !=None:
self.usepop(event)
上面是core中树控件代码。
在IDE中添加以下代码:
paned= tk.PanedWindow(root,orient=tk.HORIZONTAL,showhandle=True, \
sashrelief=tk.SUNKEN,sashwidth=1)
paned.pack(fill=tk.BOTH, expand=1)
tree = htk.Tree(paned,ico=True,width=200,bg='black')
tree.load_path('./')
tree.pack(expand = 1, fill = tk.BOTH)
paned.add(tree)
paned.paneconfig(tree,width=200)
def treeDoubleClick(event):
global textPad,filename
item = tree.tree.selection()[0]
i2=tree.tree.parent(item)
s2=""
while i2!="":
s2=tree.tree.item(i2, "text")+'\\'+s2
i2=tree.tree.parent(i2)
txt2=s2+tree.tree.item(item, "text")
if txt2[-4:]=='.txt' or txt2[-3:]=='.py':
filename2=txt2
textPad.delete(1.0,tk.END)#delete all
f = open(filename2,'r',encoding='utf-8',errors='ignore')
textPad.insert(1.0,f.read())
f.close()
filename=filename2
tree.usepop=treeDoubleClick
至此,树控件已经完成了!
程序运行
现在大多数代码都完成了,现在还有最后一项,程序运行。
直接在IDE文件中添加以下代码:
def myprint(txt):
global textMess
if textMess != None :
textMess.insert(tk.END, txt)
textMess.see(tk.END)
def hprint(txt,color='black'):
global textMess
if textMess != None :
if color!='black':
textMess.tag_config(color, foreground=color)
textMess.insert(tk.END, txt,color)
textMess.see(tk.END)
hprint('-错误:0\n-警告:0\n-编译:1.00\n-程序运行成功!')
def runpy():
global textPad,textMess
try:
msg = textPad.get(1.0,tk.END)
mg=globals()
ml=locals()
exec(msg,mg,ml)
except Exception as e:
print('Error:'+str(e)+'red')
总结
至此,我们已经拥有了一个IDE的大致代码了,但仅凭这些还不能运行,下一期:完善程序