def __init__(self): super().__init__() self.text_area = TextArea(self, bg="white", fg="black", undo=True) self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.scroll_text) self.text_area.configure(yscrollcommand=self.scrollbar.set) self.scrollbar.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.line_numbers = LineNumbers(self, self.text_area, bg="grey", fg="white", width=1) self.highlighter = Highlighter(self.text_area, 'languages/python.yaml') # first_100_numbers = [str(n+1) for n in range(100)] # self.line_numbers.insert(1.0, "\n".join(first_100_numbers)) # self.line_numbers.configure(state="disabled", width=3) self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events()
def __init__(self): super().__init__() self.title('Python Text Editor v3') self.geometry('800x600') self.foreground = 'black' self.background = 'lightgrey' self.text_foreground = 'black' self.text_background = 'white' self.load_scheme_file('schemes/default.yaml') self.configure_ttk_elements() self.font_size = 15 self.font_family = "Ubuntu Mono" self.load_font_file('schemes/font.yaml') self.text_area = TextArea(self, bg=self.text_background, fg=self.text_foreground, undo=True, font=(self.font_family, self.font_size)) self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.scroll_text) self.text_area.configure(yscrollcommand=self.scrollbar.set) self.line_numbers = LineNumbers(self, self.text_area, bg="grey", fg="white", width=1) self.highlighter = Highlighter(self.text_area, 'languages/python.yaml') self.menu = tk.Menu(self, bg=self.background, fg=self.foreground) self.all_menus = [self.menu] sub_menu_items = ["file", "edit", "tools", "help"] self.generate_sub_menus(sub_menu_items) self.configure(menu=self.menu) self.right_click_menu = tk.Menu(self, bg=self.background, fg=self.foreground, tearoff=0) self.right_click_menu.add_command(label='Cut', command=self.edit_cut) self.right_click_menu.add_command(label='Copy', command=self.edit_copy) self.right_click_menu.add_command(label='Paste', command=self.edit_paste) self.all_menus.append(self.right_click_menu) self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events() self.open_file = ''
class MainWindow(tk.Tk): def __init__(self): super().__init__() self.text_area = TextArea(self, bg="white", fg="black", undo=True) self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.scroll_text) self.text_area.configure(yscrollcommand=self.scrollbar.set) self.scrollbar.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.line_numbers = LineNumbers(self, self.text_area, bg="grey", fg="white", width=1) self.highlighter = Highlighter(self.text_area, 'languages/python.yaml') # first_100_numbers = [str(n+1) for n in range(100)] # self.line_numbers.insert(1.0, "\n".join(first_100_numbers)) # self.line_numbers.configure(state="disabled", width=3) self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events() def bind_events(self): self.text_area.bind("<MouseWheel>", self.scroll_text) self.text_area.bind("<Button-4>", self.scroll_text) self.text_area.bind("<Button-5>", self.scroll_text) self.line_numbers.bind("<MouseWheel>", lambda e: "break") self.line_numbers.bind("<Button-4>", lambda e: "break") self.line_numbers.bind("<Button-5>", lambda e: "break") def scroll_text(self, *args): if len(args) > 1: print("greater", args[0], args[1]) self.text_area.yview_moveto(args[1]) self.line_numbers.yview_moveto(args[1]) else: event = args[0] print("else", args[0], event.delta) if event.delta: move = -1 * (event.delta / 120) else: if event.num == 5: move = 1 else: move = -1 self.text_area.yview_scroll(int(move), "units") self.line_numbers.yview_scroll(int(move) * 3, "units")
class MainWindow(tk.Tk): def __init__(self): super().__init__() self.text_area = TextArea(self, bg="white", fg="black", undo=True) self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.scroll_text) self.text_area.configure(yscrollcommand=self.scrollbar.set) self.line_numbers = LineNumbers(self, self.text_area, bg="grey", fg="white", width=1) self.highlighter = Highlighter(self.text_area, 'languages/python.yaml') self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events() def bind_events(self): self.text_area.bind("<MouseWheel>", self.scroll_text) self.text_area.bind("<Button-4>", self.scroll_text) self.text_area.bind("<Button-5>", self.scroll_text) self.bind('<Control-f>', self.show_find_window) self.line_numbers.bind("<MouseWheel>", lambda e: "break") self.line_numbers.bind("<Button-4>", lambda e: "break") self.line_numbers.bind("<Button-5>", lambda e: "break") def scroll_text(self, *args): if len(args) > 1: self.text_area.yview_moveto(args[1]) self.line_numbers.yview_moveto(args[1]) else: event = args[0] if event.delta: move = -1 * (event.delta / 120) else: if event.num == 5: move = 1 else: move = -1 self.text_area.yview_scroll(int(move), "units") self.line_numbers.yview_scroll(int(move) * 3, "units") def show_find_window(self, event=None): FindWindow(self.text_area)
def editor_mode(self, event=None): self.text_area.config(state=tk.NORMAL, tabs=4) self.text_area.delete('1.0', tk.END) self.text_area.insert(tk.END, self.editor_mode_buffer) self.highlighter = Highlighter(self.text_area) self.thee_mode = 1 self.line_numbers = LineNumbers(self.frame1, self.text_area) self.line_numbers.config(bg=self.text_background, width=len(self.line_numbers.line_number) * 10, highlightthickness=0) self.line_numbers.grid(row=0, column=0, sticky='ns') self.status_bar1.set("Line %d, Column %d" % (self.line, self.column)) self.status_bar3.set("%s" % self.file_name) self.status_bar4.set("Spaces: %d" % self.spaces) self.status_bar5.set("%s" % self.status)
def __init__(self): super().__init__() self.text_area = TextArea(self, bg="white", fg="black", undo=True) self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.scroll_text) self.text_area.configure(yscrollcommand=self.scrollbar.set) self.line_numbers = LineNumbers(self, self.text_area, bg="grey", fg="white", width=1) self.highlighter = Highlighter(self.text_area, 'languages/python.yaml') self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events()
class MainWindow(tk.Tk): def __init__(self): super().__init__() self.title('THEE') self.minsize(550, 40) # (width, height) self.winfo_screenwidth = self.winfo_screenwidth() self.winfo_screenheight = self.winfo_screenheight() self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) self.width = int(self.winfo_screenwidth / 3) self.height = int(self.winfo_screenheight / 3) self.geometry(f'{self.width}x{self.height}') self.thee_mode = 0 # 0: welcome, 1: editor, 2: terminal, 3: help self.count_text_changed = 0 self.editor_mode_buffer = "" self.terminal_mode_buffer = "" self.key_buffer = [] self.file_name = "untitled" self.status = "unsaved" self.spaces = 4 self.line = 1 self.column = 1 self.foreground = config.color['foreground'] self.background = config.color['background'] self.text_foreground = config.color['text_foreground'] self.text_background = config.color['text_background'] self.insertbackground = config.color['insertbackground'] self.statusbar_background = config.color['statusbarbg'] self.frame1 = tk.Frame(self, bg=self.background, width=self.width, height=self.height - 15) self.frame2 = tk.Frame(self, bg=self.statusbar_background, width=self.width, height=10) self.frame1.grid(row=0, column=0, sticky='wens') self.frame2.grid(row=1, column=0, sticky='wens') self.frame1.grid_columnconfigure(1, weight=1) self.frame1.grid_rowconfigure(0, weight=1) self.config_dir = os.path.join(str(Path.home()), '.thee') self.text_font_size = config.font['text']['size'] self.text_font_family = config.font['text']['family'] self.statusbar_font_size = config.font['statusbar']['size'] self.statusbar_font_family = config.font['statusbar']['family'] self.create_widget() # Entry point ==========# self.terminal = Terminal(self, self.text_area) # run terminal self.bind_events() self.open_file = '' self.protocol("WM_DELETE_WINDOW", self.close_window) def create_widget(self): self.text_area = TextArea(self.frame1, bg=self.text_background, fg=self.text_foreground, undo=True, relief=tk.FLAT, font=(self.text_font_family, self.text_font_size), insertbackground=self.insertbackground) self.text_area.config(highlightthickness=0) self.text_area.grid(row=0, column=1, sticky='wens') self.text_area.focus_set() self.welcome(event=None) self.status_bar1 = StatusBar(self.frame2, bg="pink", width=30, height=10) self.status_bar2 = StatusBar(self.frame2, bg="orange", width=30, height=10) self.status_bar3 = StatusBar(self.frame2, bg="blue", width=30, height=10) self.status_bar4 = StatusBar(self.frame2, bg="green", width=30, height=10) self.status_bar5 = StatusBar(self.frame2, bg="purple", width=30, height=10) self.status_bar1.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) self.status_bar2.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) self.status_bar3.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) self.status_bar4.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) self.status_bar5.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) def editor_mode(self, event=None): self.text_area.config(state=tk.NORMAL, tabs=4) self.text_area.delete('1.0', tk.END) self.text_area.insert(tk.END, self.editor_mode_buffer) self.highlighter = Highlighter(self.text_area) self.thee_mode = 1 self.line_numbers = LineNumbers(self.frame1, self.text_area) self.line_numbers.config(bg=self.text_background, width=len(self.line_numbers.line_number) * 10, highlightthickness=0) self.line_numbers.grid(row=0, column=0, sticky='ns') self.status_bar1.set("Line %d, Column %d" % (self.line, self.column)) self.status_bar3.set("%s" % self.file_name) self.status_bar4.set("Spaces: %d" % self.spaces) self.status_bar5.set("%s" % self.status) def terminal_mode(self, event=None): if self.thee_mode == 1: self.line_numbers.destroy() self.text_area.config(state=tk.NORMAL, tabs=4) self.text_area.delete('1.0', tk.END) self.text_area.insert(tk.END, self.terminal_mode_buffer) self.terminal.writeLoop() self.highlighter = Highlighter(self.text_area) self.thee_mode = 2 def text_been_modified(self, event=None): flag = self.text_area.edit_modified() if flag: # prevent from getting called twice if self.thee_mode == 1 and self.count_text_changed > 1: # editor mode self.editor_mode_buffer = self.text_area.get( 1.0, tk.END + "-1c") self.status = "unsaved" self.status_bar5.set("%s" % self.status) self.update_line_column() self.line_numbers.config( width=len(self.line_numbers.line_number) * 10) elif self.thee_mode == 2 and self.count_text_changed > 1: # terminal mode self.terminal_mode_buffer = self.text_area.get( 1.0, tk.END + "-1c") self.count_text_changed += 1 #reset so this will be called on the next change self.text_area.edit_modified(False) def retrieve_selected_line(self, event=None): if self.thee_mode == 1: self.current_line = self.text_area.get("1.0", 'end').rstrip() if event.keysym.isnumeric(): self.key_buffer.append(event.keysym) # check buffer after 500ms (0.5s) self.after(500, self.selected_line_action) def selected_line_action(self): if self.key_buffer: index = int(''.join(self.key_buffer)) - 1 self.key_buffer.clear() self.selected_line = self.current_line.split('\n')[index] selected_str = self.selected_line + "\n" # write selected code line(s) to the console in order to it running self.terminal.proc.stdin.write(selected_str.encode()) self.terminal.proc.stdin.flush() self.terminal_mode() def update_line_column(self, event=None): if self.thee_mode == 1: line, column = self.text_area.index(tk.INSERT).split('.') self.line = int(line) self.column = int(column) + 1 self.status_bar1.set("Line %d, Column %d" % (self.line, self.column)) def close_window(self): if self.editor_mode_buffer and self.status == "unsaved": #and self.status.get() == "unsaved": #SATUSBAR if msg.askokcancel("Quit", "Would you like to save the data?"): self.file_save() self.terminal.alive = False self.terminal.destroy() else: self.terminal.alive = False self.terminal.destroy() else: self.terminal.alive = False self.terminal.destroy() def bind_events(self): self.focus_set() self.text_area.bind_all('<<Modified>>', self.text_been_modified) self.text_area.bind('<Return>', self.enter) self.bind_all('<Button-1>', self.update_line_column) self.bind_all('<Control-e>', self.editor_mode) self.bind_all('<Control-t>', self.terminal_mode) self.bind_all('<Control-Key>', self.retrieve_selected_line) self.bind('<Control-f>', self.show_find_window) self.bind('<Control-n>', self.file_new) self.bind('<Control-o>', self.file_open) self.bind('<Control-s>', self.file_save) self.bind('<Control-S>', self.file_save_as) self.bind('<Control-w>', self.welcome) self.bind('<Control-h>', self.help_about) def enter(self, event=None): if self.thee_mode == 2: self.terminal.enter() def show_find_window(self, event=None): FindWindow(self.frame1, self.text_area) def show_welcome_page(self): if self.thee_mode == 1: self.line_numbers.destroy() self.text_area.config(state=tk.NORMAL) self.text_area.delete('1.0', tk.END) message = ''' \n\n THEE version 1.0 THE simple python key bindings Editor type Ctrl-h for help information by Fidel R. Monteiro <*****@*****.**> \n The Pynosso Project | Sat, Jun 26 2020 ''' self.text_area.insert(tk.END, message) self.text_area.config(state=tk.DISABLED) self.thee_mode = 0 def show_about_page(self): if self.thee_mode == 1: self.line_numbers.destroy() self.text_area.config(state=tk.NORMAL) self.text_area.delete('1.0', tk.END) message = ''' HELP Mode Commands Ctrl+e : Text mode Ctrl+t : Terminal mode Ctrl+<number> : Run selected line in python console Editing Commands Ctrl+a : Select all text Ctrl+x : Cut selected text Ctrl+c : Copy selected text Ctrl+v : Paste cut/copied text Ctrl+z : Undo Ctrl+y : Redo File Commands Ctrl+o : Open file Ctrl+s : Save current content Ctrl+S : Save current content as <filename> Ctrl+p : Print current content Ctrl+n : Open new file General Ctrl+m : Change syntax highlighting Ctrl+g : Change colour scheme Ctrl+l : Change font Ctrl+h : Display this help window AUTHOR Written by Fidel R. Monteiro (fm65) Sat, Jun 26 2020 thee version 1.0 "simple is better than complex" ''' self.text_area.insert(tk.END, message) self.text_area.config(state=tk.DISABLED) self.thee_mode = 3 def apply_colour_scheme(self, foreground, background, text_foreground, text_background): self.text_area.configure(fg=text_foreground, bg=text_background) self.background = background self.foreground = foreground for menu in self.all_menus: menu.configure(bg=self.background, fg=self.foreground) def update_font(self): #self.load_font_file(self.font_scheme_path) self.text_area.configure(font=(self.text_font_family, self.text_font_size)) def create_config_directory_if_needed(self): if not os.path.exists(self.config_dir): os.mkdir(self.config_dir) # =========== Menu Functions ============== def file_new(self, event=None): """ Ctrl+N """ self.text_area.delete(1.0, tk.END) self.open_file = None self.editor_mode() self.line_numbers.force_update() def file_open(self, event=None): """ Ctrl+O """ self.editor_mode() file_to_open = filedialog.askopenfilename(filetypes=[('Python files', '*.py')], defaultextension='.py') if file_to_open: self.open_file = file_to_open self.file_name = self.open_file.split('/')[-1] self.status_bar3.set("%s" % self.file_name) self.text_area.display_file_contents(file_to_open) self.highlighter.force_highlight() self.line_numbers.force_update() def file_save(self, event=None): """ Ctrl+s """ current_file = self.open_file if self.open_file else None if not current_file: current_file = filedialog.asksaveasfilename(filetypes=[ ('Python files', '*.py') ], defaultextension='.py') self.open_file = current_file self.file_name = current_file.split('/')[-1] self.status_bar3.set("%s" % self.file_name) if current_file: contents = self.text_area.get(1.0, tk.END) with open(current_file, 'w') as file: file.write(contents) self.status = "saved" self.status_bar5.set("%s" % self.status) def file_save_as(self, event=None): """ Ctrl+S """ new_file_name = filedialog.asksaveasfilename(filetypes=[ ('Python files', '*.py') ], defaultextension='.py', confirmoverwrite=False) f = open(self.new_file_name, 'w') f.write(self.get('1.0', 'end')) f.close() self.status = "saved" self.status_bar5.set("%s" % self.status) def edit_cut(self, event=None): """ Ctrl+X """ self.text_area.event_generate("<Control-x>") self.line_numbers.force_update() def edit_paste(self, event=None): """ Ctrl+V """ self.text_area.event_generate("<Control-v>") self.line_numbers.force_update() self.highlighter.force_highlight() def edit_copy(self, event=None): """ Ctrl+C """ self.text_area.event_generate("<Control-c>") def edit_select_all(self, event=None): """ Ctrl+A """ self.text_area.event_generate("<Control-a>") def edit_find_and_replace(self, event=None): """ Ctrl+F """ self.show_find_window() def welcome(self, event=None): """ Ctrl+W """ self.show_welcome_page() def help_about(self, event=None): """ Ctrl+H """ self.show_about_page()
def __init__(self): super().__init__() self.title('Python Text Editor v3') self.geometry('800x600') self.foreground = 'black' self.background = 'lightgrey' self.text_foreground = '#313131' self.text_background = '#f0f0f0' self.terminal_background = 'darkcyan' self.terminal_foreground = 'white' self.config_dir = os.path.join(str(Path.home()), '.tkedit') self.default_scheme_path = os.path.join(self.config_dir, 'schemes/default.yaml') self.python_language_path = os.path.join(self.config_dir, 'languages/python.yaml') self.font_scheme_path = os.path.join(self.config_dir, 'schemes/font.yaml') self.create_config_directory_if_needed() self.load_scheme_file(self.default_scheme_path) self.configure_ttk_elements() # Change self.font_size = 14 self.font_family = "Droid Sana Mono" self.terminal_font_size = 12 self.terminal_font_family = "Consolas" # Change self.load_font_file(self.font_scheme_path) self.text_area = TextArea(self, bg=self.text_background, fg=self.text_foreground, undo=True, font=(self.font_family, self.font_size)) self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.scroll_text) self.text_area.configure(yscrollcommand=self.scrollbar.set) self.line_numbers = LineNumbers(self, self.text_area, bg="grey", fg="white", width=1, font=(self.font_family, self.font_size)) self.highlighter = Highlighter(self.text_area, self.python_language_path) self.terminal = Terminal(self, height=8, bg=self.terminal_background, fg=self.terminal_foreground, undo=True, font=(self.terminal_font_family, self.terminal_font_size)) self.menu = tk.Menu(self, bg=self.background, fg=self.foreground) self.all_menus = [self.menu] self.text_area.__setattr__("update_line", self.line_numbers.force_update) self.text_area.__setattr__("update_highlight", self.highlighter.force_highlight) sub_menu_items = ["file", "edit", "tools", "help"] self.generate_sub_menus(sub_menu_items) self.configure(menu=self.menu) self.right_click_menu = tk.Menu(self, bg=self.background, fg=self.foreground, tearoff=0) self.right_click_menu.add_command(label='Cut', command=self.edit_cut) self.right_click_menu.add_command(label='Copy', command=self.edit_copy) self.right_click_menu.add_command(label='Paste', command=self.edit_paste) # Change self.right_click_menu.add_command(label='Undo', command=self.edit_undo) self.right_click_menu.add_command(label='Redo', command=self.edit_redo) # Change self.all_menus.append(self.right_click_menu) # change self.count_area = tk.Text(self, height=1) self.count_area.pack(side=tk.BOTTOM, fill=tk.X) # change # Change self.terminal.pack(side=tk.BOTTOM, fill=tk.X) # Change self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events() self.open_file = ''
class MainWindow(tk.Tk): def __init__(self): super().__init__() self.title('Python Text Editor v3') self.geometry('800x600') self.foreground = 'black' self.background = 'lightgrey' self.text_foreground = '#313131' self.text_background = '#f0f0f0' self.terminal_background = 'darkcyan' self.terminal_foreground = 'white' self.config_dir = os.path.join(str(Path.home()), '.tkedit') self.default_scheme_path = os.path.join(self.config_dir, 'schemes/default.yaml') self.python_language_path = os.path.join(self.config_dir, 'languages/python.yaml') self.font_scheme_path = os.path.join(self.config_dir, 'schemes/font.yaml') self.create_config_directory_if_needed() self.load_scheme_file(self.default_scheme_path) self.configure_ttk_elements() # Change self.font_size = 14 self.font_family = "Droid Sana Mono" self.terminal_font_size = 12 self.terminal_font_family = "Consolas" # Change self.load_font_file(self.font_scheme_path) self.text_area = TextArea(self, bg=self.text_background, fg=self.text_foreground, undo=True, font=(self.font_family, self.font_size)) self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.scroll_text) self.text_area.configure(yscrollcommand=self.scrollbar.set) self.line_numbers = LineNumbers(self, self.text_area, bg="grey", fg="white", width=1, font=(self.font_family, self.font_size)) self.highlighter = Highlighter(self.text_area, self.python_language_path) self.terminal = Terminal(self, height=8, bg=self.terminal_background, fg=self.terminal_foreground, undo=True, font=(self.terminal_font_family, self.terminal_font_size)) self.menu = tk.Menu(self, bg=self.background, fg=self.foreground) self.all_menus = [self.menu] self.text_area.__setattr__("update_line", self.line_numbers.force_update) self.text_area.__setattr__("update_highlight", self.highlighter.force_highlight) sub_menu_items = ["file", "edit", "tools", "help"] self.generate_sub_menus(sub_menu_items) self.configure(menu=self.menu) self.right_click_menu = tk.Menu(self, bg=self.background, fg=self.foreground, tearoff=0) self.right_click_menu.add_command(label='Cut', command=self.edit_cut) self.right_click_menu.add_command(label='Copy', command=self.edit_copy) self.right_click_menu.add_command(label='Paste', command=self.edit_paste) # Change self.right_click_menu.add_command(label='Undo', command=self.edit_undo) self.right_click_menu.add_command(label='Redo', command=self.edit_redo) # Change self.all_menus.append(self.right_click_menu) # change self.count_area = tk.Text(self, height=1) self.count_area.pack(side=tk.BOTTOM, fill=tk.X) # change # Change self.terminal.pack(side=tk.BOTTOM, fill=tk.X) # Change self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events() self.open_file = '' def bind_events(self): self.text_area.bind("<MouseWheel>", self.scroll_text) self.text_area.bind("<Button-4>", self.scroll_text) self.text_area.bind("<Button-5>", self.scroll_text) self.text_area.bind("<Button-3>", self.show_right_click_menu) # Change self.count_area.bind(self.count_text()) # Change self.bind('<Control-f>', self.show_find_window) self.bind('<Control-n>', self.file_new) self.bind('<Control-o>', self.file_open) self.bind('<Control-s>', self.file_save) self.bind('<Control-h>', self.help_about) self.bind('<Control-m>', self.tools_change_syntax_highlighting) self.bind('<Control-g>', self.tools_change_colour_scheme) self.bind('<Control-l>', self.tools_change_font) self.line_numbers.bind("<MouseWheel>", lambda e: "break") self.line_numbers.bind("<Button-4>", lambda e: "break") self.line_numbers.bind("<Button-5>", lambda e: "break") # change def count_text(self): contents = self.text_area.get(1.0, tk.END).replace(" ", "").split("\n") self.count_area.delete(1.0, tk.END) self.count_area.insert( tk.END, "当前字数为:" + str(CountWord(contents).bind_event(contents)) + " 字") return self.after(50, self.count_text) # change def scroll_text(self, *args): if len(args) > 1: self.text_area.yview_moveto(args[1]) self.line_numbers.yview_moveto(args[1]) else: event = args[0] if event.delta: move = -1 * (event.delta / 120) else: if event.num == 5: move = 1 else: move = -1 self.text_area.yview_scroll(int(move), "units") self.line_numbers.yview_scroll(int(move) * 3, "units") def show_find_window(self, event=None): FindWindow(self.text_area) def show_right_click_menu(self, event): x = self.winfo_x() + self.text_area.winfo_x() + event.x y = self.winfo_y() + self.text_area.winfo_y() + event.y self.right_click_menu.post(x, y) def generate_sub_menus(self, sub_menu_items): window_methods = [ method_name for method_name in dir(self) if callable(getattr(self, method_name)) ] tkinter_methods = [ method_name for method_name in dir(tk.Tk) if callable(getattr(tk.Tk, method_name)) ] my_methods = [ method for method in set(window_methods) - set(tkinter_methods) ] my_methods = sorted(my_methods) for item in sub_menu_items: sub_menu = tk.Menu(self.menu, tearoff=0, bg=self.background, fg=self.foreground) matching_methods = [] for method in my_methods: if method.startswith(item): matching_methods.append(method) for match in matching_methods: actual_method = getattr(self, match) method_shortcut = actual_method.__doc__.strip() friendly_name = ' '.join(match.split('_')[1:]) sub_menu.add_command(label=friendly_name.title(), command=actual_method, accelerator=method_shortcut) self.menu.add_cascade(label=item.title(), menu=sub_menu) self.all_menus.append(sub_menu) def show_about_page(self): msg.showinfo( "About", "My text editor, version 2, written in Python3.6 using tkinter!") def load_syntax_highlighting_file(self): syntax_file = filedialog.askopenfilename(filetypes=[("YAML file", ("*.yaml", "*.yml"))]) if syntax_file: self.highlighter.clear_highlight() self.highlighter = Highlighter(self.text_area, syntax_file) self.highlighter.force_highlight() def load_scheme_file(self, scheme): with open(scheme, 'r') as stream: try: config = yaml.load(stream) except yaml.YAMLError as error: print(error) return self.foreground = config['foreground'] self.background = config['background'] self.text_foreground = config['text_foreground'] self.text_background = config['text_background'] def load_font_file(self, file_path): with open(file_path, 'r') as stream: try: config = yaml.load(stream) except yaml.YAMLError as error: print(error) return self.font_family = config['family'] self.font_size = config['size'] def change_colour_scheme(self): ColourChooser(self) def apply_colour_scheme(self, foreground, background, text_foreground, text_background): self.text_area.configure(fg=text_foreground, bg=text_background) self.background = background self.foreground = foreground for menu in self.all_menus: menu.configure(bg=self.background, fg=self.foreground) self.configure_ttk_elements() def configure_ttk_elements(self): style = ttk.Style() style.configure('editor.TLabel', foreground=self.foreground, background=self.background) style.configure('editor.TButton', foreground=self.foreground, background=self.background) def change_font(self): FontChooser(self) def update_font(self): self.load_font_file(self.font_scheme_path) self.text_area.configure(font=(self.font_family, self.font_size)) def create_config_directory_if_needed(self): if not os.path.exists(self.config_dir): os.mkdir(self.config_dir) os.mkdir(os.path.join(self.config_dir, 'schemes')) os.mkdir(os.path.join(self.config_dir, 'languages')) self.create_default_scheme_if_needed() self.create_font_scheme_if_needed() self.create_python_language_if_needed() def create_default_scheme_if_needed(self): if not os.path.exists(self.default_scheme_path): yaml_file_contents = f"background: 'lightgrey'\n" \ + f"foreground: 'black'\n" \ + f"text_background: 'white'\n" \ + f"text_foreground: 'black'\n" with open(self.default_scheme_path, 'w') as yaml_file: yaml_file.write(yaml_file_contents) def create_font_scheme_if_needed(self): if not os.path.exists(self.font_scheme_path): yaml_file_contents = f"family: Ubuntu Mono\n" \ + f"size: 14" with open(self.font_scheme_path, 'w') as yaml_file: yaml_file.write(yaml_file_contents) def create_python_language_if_needed(self): if not os.path.exists(self.python_language_path): yaml_file_contents = """ categories: keywords: colour: orange matches: [for, def, while, from, import, as, with, self] variables: colour: red4 matches: ['True', 'False', None] conditionals: colour: green matches: [try, except, if, else, elif] functions: colour: blue4 matches: [int, str, dict, list, set, float] numbers: colour: purple strings: colour: '#e1218b' """ with open(self.python_language_path, 'w') as yaml_file: yaml_file.write(yaml_file_contents) # =========== Menu Functions ============== def file_new(self, event=None): """ Ctrl+N """ self.text_area.delete(1.0, tk.END) self.open_file = None self.line_numbers.force_update() def file_open(self, event=None): """ Ctrl+O """ file_to_open = filedialog.askopenfilename() if file_to_open: self.open_file = file_to_open self.text_area.display_file_contents(file_to_open) self.highlighter.force_highlight() self.line_numbers.force_update() def file_save(self, event=None): """ Ctrl+S """ current_file = self.open_file if self.open_file else None if not current_file: current_file = filedialog.asksaveasfilename() if current_file: contents = self.text_area.get(1.0, tk.END) with open(current_file, 'w') as file: file.write(contents) def edit_cut(self, event=None): """ Ctrl+X """ self.text_area.event_generate("<Control-x>") self.line_numbers.force_update() self.highlighter.force_highlight() def edit_paste(self, event=None): """ Ctrl+V """ self.text_area.event_generate("<Control-v>") self.line_numbers.force_update() self.highlighter.force_highlight() def edit_copy(self, event=None): """ Ctrl+C """ self.text_area.event_generate("<Control-c>") def edit_select_all(self, event=None): """ Ctrl+A """ self.text_area.event_generate("<Control-a>") def edit_find_and_replace(self, event=None): """ Ctrl+F """ self.show_find_window() def edit_undo(self, event=None): """ Ctrl+Z """ self.text_area.event_generate("<Control-z>") self.line_numbers.force_update() self.highlighter.force_highlight() def edit_redo(self, event=None): """ Ctrl+Y """ self.text_area.event_generate("<Control-y>") self.line_numbers.force_update() self.highlighter.force_highlight() def help_about(self, event=None): """ Ctrl+H """ self.show_about_page() def tools_change_syntax_highlighting(self, event=None): """ Ctrl+M """ self.load_syntax_highlighting_file() def tools_change_colour_scheme(self, event=None): """ Ctrl+G """ self.change_colour_scheme() def tools_change_font(self, event=None): """ Ctrl+L """ self.change_font()
def __init__(self): ''' @update 1.添加横向滚动条 2.修正行号与滚动条和窗口的关联 3.修正行号显示 ''' super().__init__() self.title('Python Text Editor v3') self.geometry('800x600') self.foreground = 'black' self.background = 'lightgrey' self.text_foreground = 'black' self.text_background = 'white' self.config_dir = os.path.join(str(Path.home()), '.tkedit') self.default_scheme_path = os.path.join(self.config_dir, 'schemes/default.yaml') self.python_language_path = os.path.join(self.config_dir, 'languages/python.yaml') self.none_language_path = os.path.join(self.config_dir, 'languages/None.yaml') self.font_scheme_path = os.path.join(self.config_dir, 'fonts/font.yaml') self.create_config_directory_if_needed() self.load_scheme_file(self.default_scheme_path) self.configure_ttk_elements() self.font_size = 15 self.font_family = "Ubuntu Mono" self.load_font_file(self.font_scheme_path) self.text_area = TextArea(self, bg=self.text_background, fg=self.text_foreground, undo=True, font=(self.font_family, self.font_size)) self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.text_area.yview) self.scrollbar2 = ttk.Scrollbar(orient="horizontal", command=self.text_area.xview) self.line_numbers = LineNumbers(self, self.text_area, bg="grey", fg="white", width=1, font=(self.font_family, self.font_size)) self.scrollbar.config(command=self.text_area.yview) self.text_area.config(yscrollcommand=self.scrollbar.set, xscrollcommand=self.scrollbar2.set) self.highlighter = Highlighter(self.text_area, self.none_language_path) self.menu = tk.Menu(self, bg=self.background, fg=self.foreground) self.all_menus = [self.menu] sub_menu_items = ["file", "edit", "tools", "help"] self.generate_sub_menus(sub_menu_items) self.configure(menu=self.menu) self.right_click_menu = tk.Menu(self, bg=self.background, fg=self.foreground, tearoff=0) self.right_click_menu.add_command(label='Cut', command=self.edit_cut) self.right_click_menu.add_command(label='Copy', command=self.edit_copy) self.right_click_menu.add_command(label='Paste', command=self.edit_paste) self.all_menus.append(self.right_click_menu) self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.scrollbar2.pack(side=tk.BOTTOM, fill=tk.X) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events() self.open_file = ''
class MainWindow(tk.Tk): ''' @param tk.TK: Windows、Mac、Unix下TK GUI套件的标准Python接口,可实现GUI界面 ''' #窗口设置 def __init__(self): ''' @update 1.添加横向滚动条 2.修正行号与滚动条和窗口的关联 3.修正行号显示 ''' super().__init__() self.title('Python Text Editor v3') self.geometry('800x600') self.foreground = 'black' self.background = 'lightgrey' self.text_foreground = 'black' self.text_background = 'white' self.config_dir = os.path.join(str(Path.home()), '.tkedit') self.default_scheme_path = os.path.join(self.config_dir, 'schemes/default.yaml') self.python_language_path = os.path.join(self.config_dir, 'languages/python.yaml') self.none_language_path = os.path.join(self.config_dir, 'languages/None.yaml') self.font_scheme_path = os.path.join(self.config_dir, 'fonts/font.yaml') self.create_config_directory_if_needed() self.load_scheme_file(self.default_scheme_path) self.configure_ttk_elements() self.font_size = 15 self.font_family = "Ubuntu Mono" self.load_font_file(self.font_scheme_path) self.text_area = TextArea(self, bg=self.text_background, fg=self.text_foreground, undo=True, font=(self.font_family, self.font_size)) self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.text_area.yview) self.scrollbar2 = ttk.Scrollbar(orient="horizontal", command=self.text_area.xview) self.line_numbers = LineNumbers(self, self.text_area, bg="grey", fg="white", width=1, font=(self.font_family, self.font_size)) self.scrollbar.config(command=self.text_area.yview) self.text_area.config(yscrollcommand=self.scrollbar.set, xscrollcommand=self.scrollbar2.set) self.highlighter = Highlighter(self.text_area, self.none_language_path) self.menu = tk.Menu(self, bg=self.background, fg=self.foreground) self.all_menus = [self.menu] sub_menu_items = ["file", "edit", "tools", "help"] self.generate_sub_menus(sub_menu_items) self.configure(menu=self.menu) self.right_click_menu = tk.Menu(self, bg=self.background, fg=self.foreground, tearoff=0) self.right_click_menu.add_command(label='Cut', command=self.edit_cut) self.right_click_menu.add_command(label='Copy', command=self.edit_copy) self.right_click_menu.add_command(label='Paste', command=self.edit_paste) self.all_menus.append(self.right_click_menu) self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.scrollbar2.pack(side=tk.BOTTOM, fill=tk.X) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events() self.open_file = '' #绑定事件 def bind_events(self): self.text_area.bind("<MouseWheel>", self.scroll_text) self.text_area.bind("<Button-4>", self.scroll_text) self.text_area.bind("<Button-5>", self.scroll_text) self.text_area.bind("<Button-3>", self.show_right_click_menu) self.bind('<Control-f>', self.show_find_window) self.bind('<Control-n>', self.file_new) self.bind('<Control-o>', self.file_open) self.bind('<Control-s>', self.file_save) self.bind('<Control-h>', self.help_about) self.bind('<Control-m>', self.tools_change_syntax_highlighting) self.bind('<Control-g>', self.tools_change_colour_scheme) self.bind('<Control-l>', self.tools_change_font) self.line_numbers.bind("<MouseWheel>", lambda e: "break") self.line_numbers.bind("<Button-4>", lambda e: "break") self.line_numbers.bind("<Button-5>", lambda e: "break") #滚动事件 def scroll_text(self, *args): if len(args) > 1: self.text_area.yview_moveto(args[1]) self.line_numbers.yview_moveto(args[1]) else: event = args[0] if event.delta: move = -1 * (event.delta / 120) else: if event.num == 5: move = 1 else: move = -1 self.text_area.yview_scroll(int(move), "units") self.line_numbers.yview_scroll(int(move) * 3, "units") #内容查找、替换窗口 def show_find_window(self, event=None): FindWindow(self.text_area) #显示右键菜单 def show_right_click_menu(self, event): x = self.winfo_x() + self.text_area.winfo_x() + event.x y = self.winfo_y() + self.text_area.winfo_y() + event.y self.right_click_menu.post(x, y) #设置子菜单 def generate_sub_menus(self, sub_menu_items): ''' @param sub_menu_items: 子菜单项目 ''' window_methods = [ method_name for method_name in dir(self) if callable(getattr(self, method_name)) ] tkinter_methods = [ method_name for method_name in dir(tk.Tk) if callable(getattr(tk.Tk, method_name)) ] my_methods = [ method for method in set(window_methods) - set(tkinter_methods) ] my_methods = sorted(my_methods) for item in sub_menu_items: sub_menu = tk.Menu(self.menu, tearoff=0, bg=self.background, fg=self.foreground) matching_methods = [] for method in my_methods: if method.startswith(item): matching_methods.append(method) for match in matching_methods: actual_method = getattr(self, match) method_shortcut = actual_method.__doc__.strip() friendly_name = ' '.join(match.split('_')[1:]) sub_menu.add_command(label=friendly_name.title(), command=actual_method, accelerator=method_shortcut) self.menu.add_cascade(label=item.title(), menu=sub_menu) self.all_menus.append(sub_menu) #显示关于 def show_about_page(self): msg.showinfo( "About", "My text editor, version 2, written in Python3.6 using tkinter!") #加载文字高亮配色方案 def load_syntax_highlighting_file(self): syntax_file = filedialog.askopenfilename(filetypes=[("YAML file", ("*.yaml", "*.yml"))]) if syntax_file: self.highlighter.clear_highlight() self.highlighter = Highlighter(self.text_area, syntax_file) self.highlighter.force_highlight() #加载窗体配色方案 def load_scheme_file(self, scheme): ''' @param scheme: 目标配置文件 @update GSC 预检测 ''' with open(scheme, 'r') as stream: try: config = yaml.load(stream) except yaml.YAMLError as error: print(error) return if 'foreground' in config: self.foreground = config['foreground'] if 'background' in config: self.background = config['background'] if 'text_foreground' in config: self.text_foreground = config['text_foreground'] if 'text_background' in config: self.text_background = config['text_background'] #加载字体及字号方案 def load_font_file(self, file_path): ''' @param file_path: 方案存放路径及文件名 ''' with open(file_path, 'r') as stream: try: config = yaml.load(stream) except yaml.YAMLError as error: print(error) return if 'family' in config: self.font_family = config['family'] if 'size' in config: self.font_size = config['size'] #修改窗体配色方案 def change_colour_scheme(self): ColourChooser(self) #应用窗体配色方案 def apply_colour_scheme(self, foreground, background, text_foreground, text_background): ''' @param foreground: 新窗体前景色 @param background: 新窗体背景色 @param text_foreground: 新字体前景色 @param text_background: 新字体背景色 ''' self.text_area.configure(fg=text_foreground, bg=text_background) self.background = background self.foreground = foreground for menu in self.all_menus: menu.configure(bg=self.background, fg=self.foreground) self.configure_ttk_elements() #应用按钮、标签配色方案 def configure_ttk_elements(self): style = ttk.Style() style.configure('editor.TLabel', foreground=self.foreground, background=self.background) style.configure('editor.TButton', foreground=self.foreground, background=self.background) #字体选择窗口 def change_font(self): FontChooser(self) #更新字体 def update_font(self): ''' @update 1.添加行号字体更新 ''' self.load_font_file(self.font_scheme_path) self.text_area.configure(font=(self.font_family, self.font_size)) self.line_numbers.configure(font=(self.font_family, self.font_size)) #运行环境检测 def create_config_directory_if_needed(self): if not os.path.exists(self.config_dir): os.mkdir(self.config_dir) if not os.path.exists(os.path.join(self.config_dir, 'schemes')): os.mkdir(os.path.join(self.config_dir, 'schemes')) if not os.path.exists(os.path.join(self.config_dir, 'languages')): os.mkdir(os.path.join(self.config_dir, 'languages')) if not os.path.exists(os.path.join(self.config_dir, 'fonts')): os.mkdir(os.path.join(self.config_dir, 'fonts')) self.create_default_scheme_if_needed() self.create_font_scheme_if_needed() self.create_python_language_if_needed() #运行环境创建 -- 窗体默认配置方案 def create_default_scheme_if_needed(self): if not os.path.exists(self.default_scheme_path): yaml_file_contents = f"background: 'lightgrey'\n" \ + f"foreground: 'black'\n" \ + f"text_background: 'white'\n" \ + f"text_foreground: 'black'\n" with open(self.default_scheme_path, 'w') as yaml_file: yaml_file.write(yaml_file_contents) #运行环境创建 -- 字体默认配置方案 def create_font_scheme_if_needed(self): if not os.path.exists(self.font_scheme_path): yaml_file_contents = f"family: Ubuntu Mono\n" \ + f"size: 15" with open(self.font_scheme_path, 'w') as yaml_file: yaml_file.write(yaml_file_contents) #运行环境创建 -- 语言文字高亮默认配置方案 def create_python_language_if_needed(self): if not os.path.exists(self.python_language_path): yaml_file_contents = """ categories: keywords: colour: orange matches: [for, def, while, from, import, as, with, self] variables: colour: red4 matches: ['True', 'False', None] conditionals: colour: green matches: [try, except, if, else, elif] functions: colour: blue4 matches: [int, str, dict, list, set, float] numbers: colour: purple strings: colour: '#e1218b' """ with open(self.python_language_path, 'w') as yaml_file: yaml_file.write(yaml_file_contents) if not os.path.exists(self.none_language_path): yaml_file_contents = """ categories: keywords: colour: black matches: [for, def, while, from, import, as, with, self] variables: colour: black matches: ['True', 'False', None] conditionals: colour: black matches: [try, except, if, else, elif] functions: colour: black matches: [int, str, dict, list, set, float] numbers: colour: black strings: colour: black """ with open(self.none_language_path, 'w') as yaml_file: yaml_file.write(yaml_file_contents) # =========== Menu Functions ============== #新建文件 def file_new(self, event=None): """ Ctrl+N """ self.text_area.delete(1.0, tk.END) self.open_file = "" self.line_numbers.force_update() #打开文件 def file_open(self, event=None): """ Ctrl+O """ file_to_open = filedialog.askopenfilename() if file_to_open: self.open_file = file_to_open self.text_area.display_file_contents(file_to_open) self.highlighter.force_highlight() self.line_numbers.force_update() #保存文件 def file_save(self, event=None): """ Ctrl+S """ current_file = self.open_file if self.open_file else None if not current_file: current_file = filedialog.asksaveasfilename() if current_file: contents = self.text_area.get(1.0, tk.END) with open(current_file, 'w') as file: file.write(contents) #剪切 def edit_cut(self, event=None): """ Ctrl+X """ self.text_area.event_generate("<Control-x>") self.line_numbers.force_update() #粘贴 def edit_paste(self, event=None): """ Ctrl+V """ self.text_area.event_generate("<Control-v>") self.line_numbers.force_update() self.highlighter.force_highlight() #复制 def edit_copy(self, event=None): """ Ctrl+C """ self.text_area.event_generate("<Control-c>") #全选 def edit_select_all(self, event=None): """ Ctrl+A """ self.text_area.event_generate("<Control-a>") #查找和替换 def edit_find_and_replace(self, event=None): """ Ctrl+F """ self.show_find_window() #帮助与关于 def help_about(self, event=None): """ Ctrl+H """ self.show_about_page() #选择语言(文字高亮) def tools_change_syntax_highlighting(self, event=None): """ Ctrl+M """ self.load_syntax_highlighting_file() #选择窗体配色 def tools_change_colour_scheme(self, event=None): """ Ctrl+G """ self.change_colour_scheme() #选择字体字号 def tools_change_font(self, event=None): """ Ctrl+L """ self.change_font()
class MainWindow(tk.Tk): def __init__(self): super().__init__() self.title('Python Text Editor v3') self.geometry('800x600') self.foreground = 'black' self.background = 'lightgrey' self.text_foreground = 'black' self.text_background = 'white' self.load_scheme_file('schemes/default.yaml') self.configure_ttk_elements() self.font_size = 15 self.font_family = "Ubuntu Mono" self.load_font_file('schemes/font.yaml') self.text_area = TextArea(self, bg=self.text_background, fg=self.text_foreground, undo=True, font=(self.font_family, self.font_size)) self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.scroll_text) self.text_area.configure(yscrollcommand=self.scrollbar.set) self.line_numbers = LineNumbers(self, self.text_area, bg="grey", fg="white", width=1) self.highlighter = Highlighter(self.text_area, 'languages/python.yaml') self.menu = tk.Menu(self, bg=self.background, fg=self.foreground) self.all_menus = [self.menu] sub_menu_items = ["file", "edit", "tools", "help"] self.generate_sub_menus(sub_menu_items) self.configure(menu=self.menu) self.right_click_menu = tk.Menu(self, bg=self.background, fg=self.foreground, tearoff=0) self.right_click_menu.add_command(label='Cut', command=self.edit_cut) self.right_click_menu.add_command(label='Copy', command=self.edit_copy) self.right_click_menu.add_command(label='Paste', command=self.edit_paste) self.all_menus.append(self.right_click_menu) self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events() self.open_file = '' def bind_events(self): self.text_area.bind("<MouseWheel>", self.scroll_text) self.text_area.bind("<Button-4>", self.scroll_text) self.text_area.bind("<Button-5>", self.scroll_text) self.text_area.bind("<Button-3>", self.show_right_click_menu) self.bind('<Control-f>', self.show_find_window) self.bind('<Control-n>', self.file_new) self.bind('<Control-o>', self.file_open) self.bind('<Control-s>', self.file_save) self.bind('<Control-h>', self.help_about) self.bind('<Control-m>', self.tools_change_syntax_highlighting) self.bind('<Control-g>', self.tools_change_color_scheme) self.bind('<Control-l>', self.tools_change_font) self.line_numbers.bind("<MouseWheel>", lambda e: "break") self.line_numbers.bind("<Button-4>", lambda e: "break") self.line_numbers.bind("<Button-5>", lambda e: "break") def scroll_text(self, *args): if len(args) > 1: self.text_area.yview_moveto(args[1]) self.line_numbers.yview_moveto(args[1]) else: event = args[0] if event.delta: move = -1 * (event.delta / 120) else: if event.num == 5: move = 1 else: move = -1 self.text_area.yview_scroll(int(move), "units") self.line_numbers.yview_scroll(int(move) * 3, "units") def show_find_window(self, event=None): FindWindow(self.text_area) def show_right_click_menu(self, event): x = self.winfo_x() + self.text_area.winfo_x() + event.x y = self.winfo_y() + self.text_area.winfo_y() + event.y self.right_click_menu.post(x, y) def generate_sub_menus(self, sub_menu_items): window_methods = [ method_name for method_name in dir(self) if callable(getattr(self, method_name)) ] tkinter_methods = [ method_name for method_name in dir(tk.Tk) if callable(getattr(tk.Tk, method_name)) ] my_methods = [ method for method in set(window_methods) - set(tkinter_methods) ] my_methods = sorted(my_methods) for item in sub_menu_items: sub_menu = tk.Menu(self.menu, tearoff=0, bg=self.background, fg=self.foreground) matching_methods = [] for method in my_methods: if method.startswith(item): matching_methods.append(method) for match in matching_methods: actual_method = getattr(self, match) method_shortcut = actual_method.__doc__.strip() friendly_name = ' '.join(match.split('_')[1:]) sub_menu.add_command(label=friendly_name.title(), command=actual_method, accelerator=method_shortcut) self.menu.add_cascade(label=item.title(), menu=sub_menu) self.all_menus.append(sub_menu) def show_about_page(self): msg.showinfo( "About", "My text editor, version 2, written in Python3.6 using tkinter!") def load_syntax_highlighting_file(self): syntax_file = filedialog.askopenfilename(filetypes=[("YAML file", ("*.yaml", "*.yml"))]) if syntax_file: self.highlighter.clear_highlight() self.highlighter = Highlighter(self.text_area, syntax_file) self.highlighter.force_highlight() def load_scheme_file(self, scheme): with open(scheme, 'r') as stream: try: config = yaml.load(stream) except yaml.YAMLError as error: print(error) return self.foreground = config['foreground'] self.background = config['background'] self.text_foreground = config['text_foreground'] self.text_background = config['text_background'] def load_font_file(self, file_path): with open(file_path, 'r') as stream: try: config = yaml.load(stream) except yaml.YAMLError as error: print(error) return self.font_family = config['family'] self.font_size = config['size'] def change_color_scheme(self): colorChooser(self) def apply_color_scheme(self, foreground, background, text_foreground, text_background): self.text_area.configure(fg=text_foreground, bg=text_background) self.background = background self.foreground = foreground for menu in self.all_menus: menu.configure(bg=self.background, fg=self.foreground) self.configure_ttk_elements() def configure_ttk_elements(self): style = ttk.Style() style.configure('editor.TLabel', foreground=self.foreground, background=self.background) style.configure('editor.TButton', foreground=self.foreground, background=self.background) def change_font(self): FontChooser(self) def update_font(self): self.load_font_file('schemes/font.yaml') self.text_area.configure(font=(self.font_family, self.font_size)) # =========== Menu Functions ============== def file_new(self, event=None): """ Ctrl+N """ self.text_area.delete(1.0, tk.END) self.open_file = None self.line_numbers.force_update() def file_open(self, event=None): """ Ctrl+O """ file_to_open = filedialog.askopenfilename() if file_to_open: self.open_file = file_to_open self.text_area.display_file_contents(file_to_open) self.highlighter.force_highlight() self.line_numbers.force_update() def file_save(self, event=None): """ Ctrl+S """ current_file = self.open_file if self.open_file else None if not current_file: current_file = filedialog.asksaveasfilename() if current_file: contents = self.text_area.get(1.0, tk.END) with open(current_file, 'w') as file: file.write(contents) def edit_cut(self, event=None): """ Ctrl+X """ self.text_area.event_generate("<Control-x>") self.line_numbers.force_update() def edit_paste(self, event=None): """ Ctrl+V """ self.text_area.event_generate("<Control-v>") self.line_numbers.force_update() self.highlighter.force_highlight() def edit_copy(self, event=None): """ Ctrl+C """ self.text_area.event_generate("<Control-c>") def edit_select_all(self, event=None): """ Ctrl+A """ self.text_area.event_generate("<Control-a>") def edit_find_and_replace(self, event=None): """ Ctrl+F """ self.show_find_window() def help_about(self, event=None): """ Ctrl+H """ self.show_about_page() def tools_change_syntax_highlighting(self, event=None): """ Ctrl+M """ self.load_syntax_highlighting_file() def tools_change_color_scheme(self, event=None): """ Ctrl+G """ self.change_color_scheme() def tools_change_font(self, event=None): """ Ctrl+L """ self.change_font()
def __init__(self): super().__init__() self.title('Text Editor') self.text_area = TextArea(self, bg="white", fg="black", undo=True) self.background = 'lightgrey' self.foreground = 'black' self.text_foreground = 'black' self.text_background = 'white' self.config_dir = os.path.join(str(Path.home()), '.tkedit') self.default_scheme_path = os.path.join(self.config_dir, 'schemes/default.yaml') self.python_language_path = os.path.join(self.config_dir, 'languages/python.yaml') self.font_scheme_path = os.path.join(self.config_dir, 'schemes/font.yaml') self.create_config_directory_if_needed() self.load_scheme_file(self.default_scheme_path) self.configure_ttk_elements() self.font_size = 15 self.font_family = "Ubuntu Mono" self.load_font_file(self.font_scheme_path) self.highlighter = Highlighter(self.text_area, self.python_language_path) self.menu = tk.Menu(self, bg=self.background, fg=self.foreground) self.all_menus = [self.menu] sub_menu_items = ['file', 'edit', 'tools', 'help'] self.generate_sub_menus(sub_menu_items) self.configure(menu=self.menu) self.right_click_menu = tk.Menu(self, bg='lightgrey', fg='black', tearoff=0) self.right_click_menu.add_command(label='Cut', command=self.edit_cut) self.right_click_menu.add_command(label='Copy', command=self.edit_copy) self.right_click_menu.add_command(label='Paste', command=self.edit_paste) self.all_menus.append(self.right_click_menu) self.open_file = None self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.scroll_text) self.text_area.configure(yscrollcommand=self.scrollbar.set) self.line_numbers = LineNumbers(self, self.text_area, bg='grey', fg='white', width=1) ''' self.line_numbers = tk.Text(self, bg="grey", fg="yellow") first_100_numbers = [str(n+1) for n in range(100)] self.line_numbers.insert(1.0, "\n".join(first_100_numbers)) self.line_numbers.configure(state="disabled", width=3) ''' self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events()
class MainWindow(tk.Tk): def __init__(self): super().__init__() self.title('Text Editor') self.text_area = TextArea(self, bg="white", fg="black", undo=True) self.background = 'lightgrey' self.foreground = 'black' self.text_foreground = 'black' self.text_background = 'white' self.config_dir = os.path.join(str(Path.home()), '.tkedit') self.default_scheme_path = os.path.join(self.config_dir, 'schemes/default.yaml') self.python_language_path = os.path.join(self.config_dir, 'languages/python.yaml') self.font_scheme_path = os.path.join(self.config_dir, 'schemes/font.yaml') self.create_config_directory_if_needed() self.load_scheme_file(self.default_scheme_path) self.configure_ttk_elements() self.font_size = 15 self.font_family = "Ubuntu Mono" self.load_font_file(self.font_scheme_path) self.highlighter = Highlighter(self.text_area, self.python_language_path) self.menu = tk.Menu(self, bg=self.background, fg=self.foreground) self.all_menus = [self.menu] sub_menu_items = ['file', 'edit', 'tools', 'help'] self.generate_sub_menus(sub_menu_items) self.configure(menu=self.menu) self.right_click_menu = tk.Menu(self, bg='lightgrey', fg='black', tearoff=0) self.right_click_menu.add_command(label='Cut', command=self.edit_cut) self.right_click_menu.add_command(label='Copy', command=self.edit_copy) self.right_click_menu.add_command(label='Paste', command=self.edit_paste) self.all_menus.append(self.right_click_menu) self.open_file = None self.scrollbar = ttk.Scrollbar(orient="vertical", command=self.scroll_text) self.text_area.configure(yscrollcommand=self.scrollbar.set) self.line_numbers = LineNumbers(self, self.text_area, bg='grey', fg='white', width=1) ''' self.line_numbers = tk.Text(self, bg="grey", fg="yellow") first_100_numbers = [str(n+1) for n in range(100)] self.line_numbers.insert(1.0, "\n".join(first_100_numbers)) self.line_numbers.configure(state="disabled", width=3) ''' self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.bind_events() def create_config_directory_if_needed(self): if not os.path.exists(self.config_dir): os.mkdir(self.config_dir) os.mkdir(os.path.join(self.config_dir, 'schemes')) os.mkdir(os.path.join(self.config_dir, 'languages')) self.create_default_scheme_if_needed() self.create_font_scheme_if_needed() self.create_python_language_if_needed() def create_default_scheme_if_needed(self): if not os.path.exists(self.default_scheme_path): yaml_file_contents = """ background: 'lightgrey' foreground: 'black' text_background: 'white' text_foreground: 'black' """ with open(self.default_scheme_path, 'w') as yaml_file: yaml_file.write(yaml_file_contents) def create_font_scheme_if_needed(self): if not os.path.exists(self.font_scheme_path): yaml_file_contents = """ family: Ubuntu Mono size: 14 """ with open(self.font_scheme_path, 'w') as yaml_file: yaml_file.write(yaml_file_contents) def create_python_language_if_needed(self): if not os.path.exists(self.python_language_path): yaml_file_contents = """ categories: keywords: color: orange matches: [for, def, while, from, import, as, with, self] variables: color: red matches: ['True', 'False', None] conditionals: color: green matches: [try, except, if, else, elif] functions: color: blue matches: [int, str, dict, list, set, float] numbers: color: purple strings: color: '#e1218b' """ with open(self.python_language_path, 'w') as yaml_file: yaml_file.write(yaml_file_contents) def bind_events(self): self.text_area.bind("<MouseWheel>", self.scroll_text) self.text_area.bind("<Button-4>", self.scroll_text) self.text_area.bind("<Button-5>", self.scroll_text) self.text_area.bind('<Button-3>', self.show_right_click_menu) self.bind('<Control-f>', self.show_find_window) self.line_numbers.bind("<MouseWheel>", lambda e: "break") self.line_numbers.bind("<Button-4>", lambda e: "break") self.line_numbers.bind("<Button-5>", lambda e: "break") self.bind('<Control-n>', self.file_new) self.bind('<Control-o>', self.file_open) self.bind('<Control-s>', self.file_save) self.bind('<Control-h>', self.help_about) self.bind('<Control-m>', self.tools_change_syntax_highlight) self.bind('<Control-g>', self.tools_Change_color_scheme) self.bind('<Control-l>', self.tools_change_font) def show_find_window(self, event=None): FindWindow(self.text_area) def scroll_text(self, *args): if len(args) > 1: self.text_area.yview_moveto(args[1]) self.line_numbers.yview_moveto(args[1]) else: event = args[0] if event.delta: move = -1 * (event.delta / 120) else: if event.num == 5: move = 1 else: move = -1 self.text_area.yview_scroll(int(move), "units") self.line_numbers.yview_scroll(int(move) * 3, "units") def generate_sub_menus(self, sub_menu_items): window_methods = [ method_name for method_name in dir(self) if callable(getattr(self, method_name)) ] tkinter_methods = [ method_name for method_name in dir(tk.Tk) if callable(getattr(tk.Tk, method_name)) ] my_methods = [ method for method in set(window_methods) - set(tkinter_methods) ] my_methods = sorted(my_methods) for item in sub_menu_items: sub_menu = tk.Menu(self.menu, tearoff=0, bg=self.background, fg=self.foreground) matching_methods = [] for method in my_methods: if method.startswith(item): matching_methods.append(method) for match in matching_methods: actual_method = getattr(self, match) method_shortcut = actual_method.__doc__.strip() friendly_name = ' '.join(match.split('_')[1:]) sub_menu.add_command(label=friendly_name.title(), command=actual_method, accelerator=method_shortcut) self.menu.add_cascade(label=item.title(), menu=sub_menu) self.all_menus.append(sub_menu) def show_right_click_menu(self, event): x = self.winfo_x() + self.text_area.winfo_x() + event.x y = self.winfo_y() + self.text_area.winfo_y() + event.y self.right_click_menu.post(x, y) def edit_cut(self, event=None): """ Ctrl+X """ self.text_area.event_generate('<Control-x>') self.line_numbers.force_update() def edit_paste(self, event=None): """ Ctrl+V """ self.text_area.event_generate('<Control-v>') self.line_numbers.force_update() self.highlighter.force_highlight() def edit_copy(self, event=None): """ Ctrl+C """ self.text_area.event_generate('<Control-c>') def file_open(self, event=None): """ Ctrl+O """ file_to_open = filedialog.askopenfilename() if file_to_open: self.open_file = file_to_open self.text_area.display_file_contents(file_to_open) self.highlighter.force_highlight() self.line_numbers.force_update() def file_save(self, event=None): """ Ctrl+S """ current_file = self.open_file if self.open_file else None if not current_file: current_file = filedialog.asksaveasfilename() if current_file: contents = self.text_area.get(1.0, tk.END) with open(current_file, 'w') as file: file.write(contents) def file_new(self, event=None): ''' Ctrl+N ''' self.text_area.delete(1.0, tk.END) self.open_file = None self.line_numbers.force_update() def edit_select_all(self, event=None): ''' Ctrl+A ''' self.text_area.event_generate('<Control-a>') def edit_find_and_replace(self, event=None): ''' Ctrl+F ''' self.show_find_window() def load_syntax_highlighting(self): syntax_file = filedialog.askopenfilename(filetypes=[('YAML file', ('*.yaml', '*.yml'))]) if syntax_file: self.highlighter.clear_highlight() self.highlighter = Highlighter(self.text_area, syntax_file) self.highlighter.force_highlight() def tools_change_syntax_highlight(self, event=None): ''' Ctrl+M ''' self.load_syntax_highlighting() def update_font(self): self.load_font_file(self.font_scheme_path) self.text_area.configure(font=(self.font_family, self.font_size)) def load_font_file(self, file_path): with open(file_path, 'r') as stream: try: config = yaml.load(stream) except yaml.YAMLError as e: print(e) return self.font_family = config['family'] self.font_size = config['size'] def load_scheme_file(self, scheme): with open(scheme, 'r') as stream: try: config = yaml.load(stream) except yaml.YAMLError as error: print(error) return self.foreground = config['foreground'] self.background = config['background'] self.text_foreground = config['text_foreground'] self.text_background = config['text_background'] def change_font(self): FontChooser(self) def tools_change_font(self, event=None): ''' Ctrl+L ''' self.change_font() def apply_color_scheme(self, foreground, background, text_foreground, text_background): self.background = background self.foreground = foreground self.text_area.configure(fg=text_foreground, bg=text_background) for menu in self.all_menus: menu.configure(bg=self.background, fg=self.foreground) self.configure_ttk_elements() def configure_ttk_elements(self): style = ttk.Style() style.configure('editor.TLabel', foreground=self.foreground, background=self.background) style.configure('editor.TButton', foreground=self.foreground, background=self.background) def change_color_scheme(self): ColorChooser(self) def tools_Change_color_scheme(self, event=None): ''' Ctrl+G ''' self.change_color_scheme() def show_about_page(self): msg.showinfo( 'About', 'My text editor , Version 3.0, written in python 3.7 using tkinter!' ) def help_about(self, event=None): ''' Ctrl+H ''' self.show_about_page()