Python Forum
[Tkinter] Indentation for Tkinter-made Text Editor
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Indentation for Tkinter-made Text Editor
#1
Hello, there.

I am writing my own programming language in Python, and along with it, my own text editor, made with the Tkinter module. I already have basic functionality set up, and it is very similar in use and abilities to Microsoft Notepad.
As of now, you are able to write text, save the text file, open the text file, create a new text file; the entire code is below:

import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox


class Menubar:

    def __init__(self, parent):
        font_specs = ("ubuntu", 14)

        menubar = tk.Menu(parent.master, font=font_specs)
        parent.master.config(menu=menubar)

        file_dropdown = tk.Menu(menubar, font=font_specs, tearoff=0)
        file_dropdown.add_command(label="New File",
                                  accelerator="Ctrl+N",
                                  command=parent.new_file)
        file_dropdown.add_command(label="Open File",
                                  accelerator="Ctrl+O",
                                  command=parent.open_file)
        file_dropdown.add_command(label="Save",
                                  accelerator="Ctrl+S",
                                  command=parent.save)
        file_dropdown.add_command(label="Save As",
                                  accelerator="Ctrl+Shift+S",
                                  command=parent.save_as)
        file_dropdown.add_separator()
        file_dropdown.add_command(label="Exit",
                                  command=parent.master.destroy)

        about_dropdown = tk.Menu(menubar, font=font_specs, tearoff=0)
        about_dropdown.add_command(label="Release Notes",
                                   command=self.show_release_notes)
        about_dropdown.add_separator()
        about_dropdown.add_command(label="About",
                                   command=self.show_about_message)

        menubar.add_cascade(label="File", menu=file_dropdown)
        menubar.add_cascade(label="About", menu=about_dropdown)

    def show_about_message(self):
        box_title = "About TextEditor"
        box_message "A simple text editor."
        messagebox.showinfo(box_title, box_message)

    def show_release_notes(self):
        box_title = "Release Notes"
        box_message = "Version 0.1 - new."
        messagebox.showinfo(box_title, box_message)


class Statusbar:

    def __init__(self, parent):

        font_specs = ("ubuntu", 12)

        self.status = tk.StringVar()
        self.status.set("TextEditor v1.0")

        label = tk.Label(parent.textarea, textvariable=self.status, fg="black",
                         bg="lightgrey", anchor='sw', font=font_specs)
        label.pack(side=tk.BOTTOM, fill=tk.BOTH)

    def update_status(self, *args):
        if isinstance(args[0], bool):
            self.status.set("Your File Has Been Saved!")
        else:
            self.status.set("TextEditor")


class TextEditor:

    def __init__(self, master):
        master.title("Untitled - TextEditor")
        master.geometry("1200x700")

        font_specs = ("ubuntu", 18)

        self.master = master
        self.filename = None

        self.textarea = tk.Text(master, font=font_specs)
        self.scroll = tk.Scrollbar(master, command=self.textarea.yview)
        self.textarea.configure(yscrollcommand=self.scroll.set)
        self.textarea.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.scroll.pack(side=tk.RIGHT, fill=tk.Y)

        self.menubar = Menubar(self)
        self.statusbar = Statusbar(self)

        self.bind_shortcuts()


    def set_window_title(self, name=None):
        if name:
            self.master.title(name + " - TextEditor")
        else:
            self.master.title("Untitled - TextEditor")

    def new_file(self, *args):
        self.textarea.delete(1.0, tk.END)
        self.filename = None
        self.set_window_title()

    def open_file(self, *args):
        self.filename = filedialog.askopenfilename(
            defaultextension=".txt",
            filetypes=[("All Files", "*.*"),
                       ("Text Files", "*.txt"),
                       ("Python Scripts", "*.py"),
                       ("Markdown Documents", "*.md"),
                       ("JavaScript Files", "*.js"),
                       ("HTML Documents", "*.html"),
                       ("CSS Documents", "*.css")])
        if self.filename:
            self.textarea.delete(1.0, tk.END)
            with open(self.filename, "r") as f:
                self.textarea.insert(1.0, f.read())
            self.set_window_title(self.filename)

    def save(self, *args):
        if self.filename:
            try:
                textarea_content = self.textarea.get(1.0, tk.END)
                with open(self.filename, "w") as f:
                    f.write(textarea_content)
                self.statusbar.update_status(True)
            except Exception as e:
                print(e)
        else:
            self.save_as()

    def save_as(self, *args):
        try:
            new_file = filedialog.asksaveasfilename(
                initialfile="Untitled.txt",
                defaultextension=".txt",
                filetypes=[("All Files", "*.*"),
                        ("Text Files", "*.txt"),
                        ("Python Scripts", "*.py"),
                        ("Markdown Documents", "*.md"),
                        ("JavaScript Files", "*.js"),
                        ("HTML Documents", "*.html"),
                        ("CSS Documents", "*.css")])
            textarea_content = self.textarea.get(1.0, tk.END)
            with open(new_file, "w") as f:
                f.write(textarea_content)
            self.filename = new_file
            self.set_window_title(self.filename)
            self.statusbar.update_status(True)
        except Exception as e:
            print(e)

    def bind_shortcuts(self):
        self.textarea.bind('<Control-n>', self.new_file)
        self.textarea.bind('<Control-o>', self.open_file)
        self.textarea.bind('<Control-s>', self.save)
        self.textarea.bind('<Control-S>', self.save_as)
        self.textarea.bind('<Key>', self.statusbar.update_status)


if __name__ == "__main__":
    master = tk.Tk()
    pt = TextEditor(master)
    master.mainloop()
The editor is functional and acts as a basic text editor, but I would to create a more advanced editor: with syntax highlighting and indentation. For now, I'm focusing on indentation.

I mentioned I am writing my own programming language (based off of Python), but for now, because I want to test if the editor is working, i'm going to be testing out indentation with Python. So for example, if it detects an if statement (such as if <variable> == 1:) or a function (such as def function():), or anything else that requires indentation, then the editor automatically indents four spaces when the user goes on a new line.

Is there any way I can achieve this with Tkinter?

Thank you.
Reply
#2
(Jun-08-2020, 10:05 AM)ShakeyPakey Wrote: Hello, there.

I am writing my own programming language in Python, and along with it, my own text editor, made with the Tkinter module. I already have basic functionality set up, and it is very similar in use and abilities to Microsoft Notepad.
As of now, you are able to write text, save the text file, open the text file, create a new text file; the entire code is below:

import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox


class Menubar:


    def __init__(self, parent):
        font_specs = ("ubuntu", 14)

        menubar = tk.Menu(parent.master, font=font_specs)
        parent.master.config(menu=menubar)

        file_dropdown = tk.Menu(menubar, font=font_specs, tearoff=0)
        file_dropdown.add_command(label="New File",
                                  accelerator="Ctrl+N",
                                  command=parent.new_file)
        file_dropdown.add_command(label="Open File",
                                  accelerator="Ctrl+O",
                                  command=parent.open_file)
        file_dropdown.add_command(label="Save",
                                  accelerator="Ctrl+S",
                                  command=parent.save)
        file_dropdown.add_command(label="Save As",
                                  accelerator="Ctrl+Shift+S",
                                  command=parent.save_as)
        file_dropdown.add_separator()
        file_dropdown.add_command(label="Exit",
                                  command=parent.master.destroy)

        about_dropdown = tk.Menu(menubar, font=font_specs, tearoff=0)
        about_dropdown.add_command(label="Release Notes",
                                   command=self.show_release_notes)
        about_dropdown.add_separator()
        about_dropdown.add_command(label="About",
                                   command=self.show_about_message)

        menubar.add_cascade(label="File", menu=file_dropdown)
        menubar.add_cascade(label="About", menu=about_dropdown)

    def show_about_message(self):
        box_title = "About TextEditor"
        box_message "A simple text editor."
        messagebox.showinfo(box_title, box_message)

    def show_release_notes(self):
        box_title = "Release Notes"
        box_message = "Version 0.1 - new."
        messagebox.showinfo(box_title, box_message)


class Statusbar:

    def __init__(self, parent):

        font_specs = ("ubuntu", 12)

        self.status = tk.StringVar()
        self.status.set("TextEditor v1.0")

        label = tk.Label(parent.textarea, textvariable=self.status, fg="black",
                         bg="lightgrey", anchor='sw', font=font_specs)
        label.pack(side=tk.BOTTOM, fill=tk.BOTH)

    def update_status(self, *args):
        if isinstance(args[0], bool):
            self.status.set("Your File Has Been Saved!")
        else:
            self.status.set("TextEditor")


class TextEditor:

    def __init__(self, master):
        master.title("Untitled - TextEditor")
        master.geometry("1200x700")

        font_specs = ("ubuntu", 18)

        self.master = master
        self.filename = None

        self.textarea = tk.Text(master, font=font_specs)
        self.scroll = tk.Scrollbar(master, command=self.textarea.yview)
        self.textarea.configure(yscrollcommand=self.scroll.set)
        self.textarea.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.scroll.pack(side=tk.RIGHT, fill=tk.Y)

        self.menubar = Menubar(self)
        self.statusbar = Statusbar(self)

        self.bind_shortcuts()


    def set_window_title(self, name=None):
        if name:
            self.master.title(name + " - TextEditor")
        else:
            self.master.title("Untitled - TextEditor")

    def new_file(self, *args):
        self.textarea.delete(1.0, tk.END)
        self.filename = None
        self.set_window_title()

    def open_file(self, *args):
        self.filename = filedialog.askopenfilename(
            defaultextension=".txt",
            filetypes=[("All Files", "*.*"),
                       ("Text Files", "*.txt"),
                       ("Python Scripts", "*.py"),
                       ("Markdown Documents", "*.md"),
                       ("JavaScript Files", "*.js"),
                       ("HTML Documents", "*.html"),
                       ("CSS Documents", "*.css")])
        if self.filename:
            self.textarea.delete(1.0, tk.END)
            with open(self.filename, "r") as f:
                self.textarea.insert(1.0, f.read())
            self.set_window_title(self.filename)

    def save(self, *args):
        if self.filename:
            try:
                textarea_content = self.textarea.get(1.0, tk.END)
                with open(self.filename, "w") as f:
                    f.write(textarea_content)
                self.statusbar.update_status(True)
            except Exception as e:
                print(e)
        else:
            self.save_as()

    def save_as(self, *args):
        try:
            new_file = filedialog.asksaveasfilename(
                initialfile="Untitled.txt",
                defaultextension=".txt",
                filetypes=[("All Files", "*.*"),
                        ("Text Files", "*.txt"),
                        ("Python Scripts", "*.py"),
                        ("Markdown Documents", "*.md"),
                        ("JavaScript Files", "*.js"),
                        ("HTML Documents", "*.html"),
                        ("CSS Documents", "*.css")])
            textarea_content = self.textarea.get(1.0, tk.END)
            with open(new_file, "w") as f:
                f.write(textarea_content)
            self.filename = new_file
            self.set_window_title(self.filename)
            self.statusbar.update_status(True)
        except Exception as e:
            print(e)

    def bind_shortcuts(self):
        self.textarea.bind('<Control-n>', self.new_file)
        self.textarea.bind('<Control-o>', self.open_file)
        self.textarea.bind('<Control-s>', self.save)
        self.textarea.bind('<Control-S>', self.save_as)
        self.textarea.bind('<Key>', self.statusbar.update_status)


if __name__ == "__main__":
    master = tk.Tk()
    pt = TextEditor(master)
    master.mainloop()
The editor is functional and acts as a basic text editor, but I would to create a more advanced editor: with syntax highlighting and indentation. For now, I'm focusing on indentation.

I mentioned I am writing my own programming language (based off of Python), but for now, because I want to test if the editor is working, i'm going to be testing out indentation with Python. So for example, if it detects an if statement (such as if <variable> == 1:) or a function (such as def function():), or anything else that requires indentation, then the editor automatically indents four spaces when the user goes on a new line.

Is there any way I can achieve this with Tkinter?

Thank you.

Hey, So firstly i think that this is really cool for a project, but i found an error when running.
With Box_title you put an = but with box_message theres no = meaning the the thing wont run.
Reply
#3
(Jun-08-2020, 11:42 AM)MianDoesCoding Wrote: Hey, So firstly i think that this is really cool for a project, but i found an error when running.
With Box_title you put an = but with box_message theres no = meaning the the thing wont run.

Oops, forgot to fix that. It's easily fixed, though.

Anyways, do you have any ideas for what I can do with indentation? And thanks for being interested in the project :)
Reply
#4
(Jun-08-2020, 11:59 AM)ShakeyPakey Wrote:
(Jun-08-2020, 11:42 AM)MianDoesCoding Wrote: Hey, So firstly i think that this is really cool for a project, but i found an error when running.
With Box_title you put an = but with box_message theres no = meaning the the thing wont run.

Oops, forgot to fix that. It's easily fixed, though.

Anyways, do you have any ideas for what I can do with indentation? And thanks for being interested in the project :)
if you want, we could work together on it!
my email is [email protected]
Reply
#5
If you are doing this after code has already written on the line above, you should be able to do the auot indent with the insert.
Going by the documentation you can use a column, row index for positioning.
Here is a link on stackoverflow. The first response has an example.
And a link to EffBot
As a side not python3's f-string recognizes &nbsp; as a space character. I found this out experimenting on something for displaying. I do not know about the tkinters text widget but, the labels will use it.
Stackoverflow
Tikinter Book Text Widget
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  How can I run an interface I made using PyQt5 and a Map program I made using Tkinter bki 6 1,047 Nov-09-2023, 11:12 PM
Last Post: bki
  [Tkinter] Updating tkinter text BliepMonster 5 5,673 Nov-28-2022, 01:42 AM
Last Post: deanhystad
  [Tkinter] The Text in the Label widget Tkinter cuts off the Long text in the view malmustafa 4 4,672 Jun-26-2022, 06:26 PM
Last Post: menator01
  tkinter change the text of the checkbox zazas321 1 3,759 Sep-17-2021, 06:19 AM
Last Post: zazas321
  tkinter text widget word wrap position chrisdb 6 7,462 Mar-18-2021, 03:55 PM
Last Post: chrisdb
  [Tkinter] tkinter.Menu – How to make text-variable? Sir 3 5,546 Mar-10-2021, 04:21 PM
Last Post: Sir
Photo Tkinter TEXT background image _ShevaKadu 5 7,656 Nov-02-2020, 10:34 AM
Last Post: joe_momma
  tkinter | Button color text on Click Maryan 2 3,317 Oct-09-2020, 08:56 PM
Last Post: Maryan
  [Tkinter] Text Upload LearningLittlebyLittle 0 2,014 Sep-04-2020, 07:55 PM
Last Post: LearningLittlebyLittle
  [Tkinter] Syntax Highlighting in Text Editor ShakeyPakey 4 4,914 Jun-10-2020, 02:23 AM
Last Post: deanhystad

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020