Python ebooks maker 2

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.

The output of the code for the messagebox

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.

Published by pythonprogramming

Started with basic on the spectrum, loved javascript in the 90ies and python in the 2000, now I am back with python, still making some javascript stuff when needed.