I'm developing a dirt-simple text editor for personal use, customized the way I like it. My biggest difficulty is with grasping how OOP works. Could you kindly review the following code and suggest improvements (or at least link further information)? Much appreciated.

from tkinter import Tk, END, INSERT
from tkinter.scrolledtext import ScrolledText
from tkinter.filedialog import asksaveasfilename, askopenfilename

class Scratchpad:

    def __init__(self, Tk):
        self.display = Tk()
        self.display.title("Onager Text Editor--<F7> save, <F5> open and insert")
        self.display.bind('<F7>', self.save_file)
        self.display.bind('<F5>', self.open_file)
        self.display.bind('<Control-c>', self.copy)
        self.display.bind('<Control-p>', self.cut)
        self.display.bind('<Control-v>', self.paste)

    def create_editor(self, ScrolledText):
        self.editing_window = ScrolledText(self.display)
        self.editing_window.configure(fg='gold', bg='blue', insertbackground='cyan',
            height='25', width='70', padx='12', pady='12',
            wrap='word', tabs='48', font='serif 12')
        self.editing_window.pack()

    def save_file(self, event=None):
        name = asksaveasfilename()
        outfile = open(name, 'w')
        contents = self.editing_window.get(0.0, END)
        outfile.write(contents)
        outfile.close()

    def open_file(self, event=None):
        name = askopenfilename()
        infile = open(name, 'r')
        contents = infile.read()
        self.editing_window.insert(INSERT, contents)
        infile.close()

    def copy(self, event=None):
        self.display.clipboard_clear()
        text = self.editing_window.get("sel.first", "sel.last")
        self.display.clipboard_append(text)

    def cut(self, event):
        self.copy()
        self.editing_window.delete("sel.first", "sel.last")

    def paste(self, event):
        self.editing_window.insert(INSERT, self.display.clipboard_get())

def main():
    onager = Scratchpad(Tk)
    onager.create_editor(ScrolledText)
    onager.display.mainloop()

if __name__=='__main__':
    main()

Recommended Answers

All 6 Replies

Hello, I think you can start a long list of missing features. The first in sight are

  1. A shortcut to exit the editor
  2. Why is there no menubar ? Is it by design ?
  3. The text area does not update as it should when the window is resized with the mouse
  4. A font selection tool is missing (especially the font size selection)
  5. Syntax highlighting for languages such as python ?

To be fully honest, I think there are so many good editors that it is an potentially huge effort to write your own with very little chance to do something better than existing tools.

My favorite editor is Kate . It is very powerful and easy to use. Have you tried it ?

Thanks for your comments.

The missing features are missing because I don't use them. I've implemented only the features I normally rely on, and the window size and font are what I happen to like. This script is only for personal use, not distribution.

Yes, i've tried Kate/Gedit/Pluma/Emacs etc and all of them are too busy. I wanted something very simple that would include minimal clutter, and I've pretty much got it here.

My question was really whether the OO layout of the script is done in the standard, acceptable way. I've made a few changes and this is how the OO is laid out now:

from tkinter import Tk, END, INSERT
from tkinter.scrolledtext import ScrolledText
from tkinter.filedialog import asksaveasfilename, askopenfilename

class Scratchpad:

    def __init__(self, Tk, ScrolledText):
        self.display = Tk()
        self.display.title("Onager Text Editor")
        self.display.bind('<F7>', self.save_file)
        self.display.bind('<F5>', self.open_file)
        self.create_editor(ScrolledText)

    def create_editor(self, ScrolledText):
        self.editing_window = ScrolledText(self.display)
        self.editing_window.configure(fg='gold', bg='blue', insertbackground='cyan',
            height='25', width='70', padx='12', pady='12',
            wrap='word', tabs='48', font='serif 12')
        self.editing_window.pack()

    def save_file(self, event=None):
        name = asksaveasfilename()
        outfile = open(name, 'w')
        contents = self.editing_window.get(0.0, END)
        outfile.write(contents)
        outfile.close()

    def open_file(self, event=None):
        name = askopenfilename()
        infile = open(name, 'r')
        contents = infile.read()
        self.editing_window.insert(INSERT, contents)
        infile.close()

def main():
    onager = Scratchpad(Tk, ScrolledText)
    onager.display.mainloop()

if __name__=='__main__':
    main()

It seems very good to me.

You use global imported variables locally.

There is no need to pass ScrolledText and Tk to the Scratchpad class's dunder init. This is redundant.

This is the same, but cleaned up:

from tkinter import Tk, END, INSERT
from tkinter.scrolledtext import ScrolledText
from tkinter.filedialog import asksaveasfilename, askopenfilename

class Scratchpad:

    def __init__(self):
        self.display = Tk()
        self.display.title("Onager Text Editor")
        self.display.bind('<F7>', self.save_file)
        self.display.bind('<F5>', self.open_file)
        self.create_editor()

    def create_editor(self):
        self.editing_window = ScrolledText(self.display)
        self.editing_window.configure(fg='gold', bg='blue', insertbackground='cyan',
            height='25', width='70', padx='12', pady='12',
            wrap='word', tabs='48', font='serif 12')
        self.editing_window.pack()

    def save_file(self, event=None):
        name = asksaveasfilename()
        outfile = open(name, 'w')
        contents = self.editing_window.get(0.0, END)
        outfile.write(contents)
        outfile.close()

    def open_file(self, event=None):
        name = askopenfilename()
        infile = open(name, 'r')
        contents = infile.read()
        self.editing_window.insert(INSERT, contents)
        infile.close()

def main():
    onager = Scratchpad()
    onager.display.mainloop()

if __name__=='__main__':
    main()

Thank you, all.

I wish I could figure out what the native clearscreen keystroke combination is. The rest work fine (control-c for copy, control-x for cut, control-v for paste, control-a for select all, etc).

in the executable I compiled through pyinstaller under ActivePython, there is an issue with copy accidentally cutting text, but that doesn't happen with the interpreted .pyw script. (I haven't yet done the cross-platform compile under Debian, but a test on Hello World worked great.)

I like your post. It's a nice post. I'm amazed to see the post.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.