• tkinter 写一个简易的ide


    简易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, "
    Tkinter GUIApplication
     Development Blueprints"))
    
    def display_help_messagebox(event=None):
        '''help messagebox'''
        tmb.showinfo("Help", "Fuck You: 
    Tkinter GUI Application
     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)+ '
    '
        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()

    运行效果

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

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

     

  • 相关阅读:
    windows server 2003打补丁升级后,网站上的aspx页面打不开的解决办法
    为什么IM还有生存空间
    CTO俱乐部深圳:移动互联网发展与趋势 活动分享
    为word文档创建文档结构图的的步骤
    面试官面试总结
    dll与exe通信的VC++程序实例源码
    openfire的集群研究
    如何有效地记忆与学习
    How The Kernel Manages Your Memory
    C语言循环小技巧
  • 原文地址:https://www.cnblogs.com/shuangzikun/p/python_tao_tao_tkinter_ide.html
Copyright © 2020-2023  润新知