Let’s add some features to “My notepad“, an app that we made as a simple exercise to learn a little more the use of tkinter as a GUI for Python’s app. We want to show how you can do something interesting and useful starting from a very basic start. If you wanto to know how we get here, click on this post link.
This was the notepad in his ‘output’:
And at this link you can find the code of the previous GUI.
Let’s create an ebook maker
The following code is a little different from the one of the previous post, but we will see that we can make it very useful to read and, then, create an ebook.
It will work this way: the single chapter of the ebook will be made as single txt file in a folder. The GUI will let you see the chapter throught it’s widgets just like we did with the .py files before.
For now the changes are just this:
for file in glob("*.txt"):
So that we can browse trhough all the txt files. The txt file should be saved with a name like ch_001.txt, ch_002.txt or something like this, so that they appear in order.
Another difference in the following code is contained in this line:
self.lb.bind("<<ListboxSelect>>", lambda x: self.show_text())
This makes the text of the txt file appear when you select the name on the left of the window, so that you do not have to double click on it. Note that the ListboxSelect bind has a double << >> angular parenthesys, instead of one as usual.
If you prefer to double click to read the text, you can substitute the line with this code:
self.lb.bind("<Double-Button>", lambda x: self.show_text())
Another small change is the color of the two widgets.
The one on the left goes in ‘dark mode’:
self.lb['bg'] = "black" self.lb['fg'] = "white"
The one on the right has the darkgreen background and the white color for the foreground characters, plus a bigger character.
self.text['font'] = "Arial 16" self.text['bg'] = "darkgreen" self.text['fg'] = "white"
So, very small changes, nothing too fancy, until now. Just text instead of .py files, a different way to show text with selection of names instead of double clicking and some color and characters size changes.
import tkinter as tk from glob import glob class Notepad: fullscreen = False def __init__(self, root): self.root = root self.root.geometry("600x400") self.root.title("My notepad") self.root['bg'] = "coral" self.frame1 = tk.Frame(self.root) self.frame1['bg'] = "coral" self.frame1.pack(side="left", fill=tk.Y) self.lb = tk.Listbox(self.frame1, width=30) self.lb.pack(fill=tk.Y, expand=1) self.lb['bg'] = "black" self.lb['fg'] = "white" for file in glob("*.txt"): self.lb.insert(tk.END, file) self.text = tk.Text(self.root, width=70) self.text.pack(fill=tk.BOTH, expand=1) self.text['font'] = "Arial 16" self.text['bg'] = "darkgreen" self.text['fg'] = "white" self.root.bind("<F11>", lambda x: self.toggle_fullscreen()) self.lb.bind("<<ListboxSelect>>", lambda x: self.show_text()) def show_text(self): num_item = self.lb.curselection() # the index of item selected fname = self.lb.get(num_item) # the file name selected with open(fname, encoding="utf-8") as file: self.text.delete("1.0", tk.END) file = file.read() self.text.insert(tk.END, file) def toggle_fullscreen(self): if Notepad.fullscreen == False: self.root.attributes("-fullscreen", True) Notepad.fullscreen = True else: self.root.attributes("-fullscreen", False) Notepad.fullscreen = False root = tk.Tk() # creates a window app = Notepad(root) root.mainloop()
Messagebox
1. showinfo(“Title”,”Message”)
We want to add a messagebox to the app. Let’s see how messagebox works.
import tkinter as tk from tkinter import messagebox # window, title and size root = tk.Tk() root.title("message") root.geometry("400x400") def message(): messagebox.showinfo("Ciao","Hello") root.bind("<Button-1>", lambda x: message()) root.mainloop()
We will see how to create, modify and save new files from the app.
showwarning()
This message will show that something is happening and you should take care of that.
import tkinter as tk from tkinter import messagebox root = tk.Tk() root.title("messagebox") def message(): messagebox.showwarning("Be careful!") root.bind("<Button-1>", lambda x: message()) root.mainloop()
error()
This is the message that tell you something is gone wrong.
import tkinter as tk from tkinter import messagebox root = tk.Tk() root.title("messagebox") def message(): messagebox.showerror("Ops!") root.bind("<Button-1>", lambda x: message()) root.mainloop()
How to hide the window using the messagebox
In case you want to hide the main window, because you just want to use the messagebox (maybe into a script that uses the command line interface only and you want for some reason use the messagebox only as an alert or something), you can use root.withdraw() or root.iconify(). The method iconify() has its opposite in root.deiconify(). If you want to get rid of the window at the end, use root.destroy(). Go to this stackoverflow question to get other interesting suggestions about hiding the main tkinter window.
import tkinter as tk from tkinter import messagebox # window, title and size root = tk.Tk() root.title("message") root.geometry("400x400") def message(): root.iconify() # Window iconify itself before the messagebox appears messagebox.showinfo("Ciao","Hello") root.deiconify() # windows return to original position and dimensions root.bind("<Button-1>", lambda x: message()) root.mainloop()
In this example, the windows goes into the toolbar while the messagebox appears.
In this code, instead, the window will just disappear, without seeing that effect that makes you see the window go into the toolbar. At the end of the messageboxes (Error, Warning and Information), the window will be destroyed. So, e careful, if you use tkinter withdraw() function, the window is not visible, but will be there.
import tkinter as tk from tkinter import messagebox # window, title and size root = tk.Tk() root.title("message") root.geometry("400x400") def message(): root.withdraw() # message box display messagebox.showerror("Error", "Error message") messagebox.showwarning("Warning","Warning message") messagebox.showinfo("Information","Informative message") root.destroy() print("Window has been deleted") root.bind("<Button-1>", lambda x: message()) root.mainloop()
messagebox: Ask yes or no
This code takes your choise among yes or no.
import tkinter as tk from tkinter import messagebox # window, title and size root = tk.Tk() root.title("message") root.geometry("400x400") def message(): root.overrideredirect(1) root.withdraw() # message box display x = messagebox.askquestion("Do you like Python?") if x == "yes": print("So, you do like Python") else: print("Sorry to hear that") print(f"You answered {x}") root.destroy() print("Window has been deleted") root.bind("<Button-1>", lambda x: message()) root.mainloop()
In the console the output is this
messagebox: ok or cancel
This time you will be asked to say yes of cancel to confirm an action.
import tkinter as tk from tkinter import messagebox # window, title and size root = tk.Tk() root.title("message") root.geometry("400x400") def message(): root.overrideredirect(1) root.withdraw() # message box display x = messagebox.askokcancel("Do you want to go on?") if x: print("Ok, go on reading") else: print("See ya soon, then") print(f"You answered {x}") root.destroy() print("Window has been deleted") root.bind("<Button-1>", lambda x: message()) root.mainloop()
Ask retry or cancel
With this you ask if you want to retry when something goes wrong. It returns True if you retry and False if you cancel.
import tkinter as tk from tkinter import messagebox root = tk.Tk() root.title("messagebox") def message(): x = messagebox.askretrycancel("Gone wrong!") print(x) root.bind("<Button-1>", lambda x: message()) root.mainloop()
Let’s make a menu appear when you right click
We will see this in the next episode of the Python makes ebooks 3.