Python做一个简易IDE(2)

上一期我们大致分析了一个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的大致代码了,但仅凭这些还不能运行,下一期:完善程序

posted @ 2022-07-19 19:47  GitTJBKBeta  阅读(34)  评论(0编辑  收藏  举报