Related
Can anybody tell me where I am doing wrong in this following Python program?
I am trying to create a Paint like application but it is showing errors.
File "E:\project\New folder\paint_new.py", line 33, in use_eraser
activate_button(eraser_button, eraser_mode=True)
File "E:\project\New folder\paint_new.py", line 36, in activate_button
active_button.config(relief=RAISED)
UnboundLocalError: local variable 'active_button' referenced before assignment
name 'eraser_on' is not defined
from tkinter import *
from tkinter.colorchooser import askcolor
import tkinter as tk
DEFAULT_PEN_SIZE = 5.0
DEFAULT_COLOR = 'black'
def setup():
old_x = None
old_y = None
line_width = choose_size_button.get()
color = DEFAULT_COLOR
eraser_on = False
active_button = pen_button
c.bind('<B1-Motion>', paint)
c.bind('<ButtonRelease-1>', reset)
def use_pen():
activate_button(pen_button)
def use_brush():
activate_button(brush_button)
def choose_color():
eraser_on = False
color = askcolor(color=color)[1]
def use_eraser():
activate_button(eraser_button, eraser_mode=True)
def activate_button(some_button, eraser_mode=False):
active_button.config(relief=RAISED)
some_button.config(relief=SUNKEN)
active_button = some_button
eraser_on = eraser_mode
def paint(event):
line_width = choose_size_button.get()
paint_color = 'white' if eraser_on else color
if old_x and old_y:
c.create_line(old_x, old_y, event.x, event.y,
width=line_width, fill=paint_color,
capstyle=ROUND, smooth=TRUE, splinesteps=36)
old_x = event.x
old_y = event.y
def reset(event):
old_x, old_y = None, None
root = tk.Tk()
pen_button = Button(root, text='pen', command=use_pen)
pen_button.grid(row=0, column=0)
brush_button = Button(root, text='brush', command=use_brush)
brush_button.grid(row=0, column=1)
color_button = Button(root, text='color', command=choose_color)
color_button.grid(row=0, column=2)
eraser_button = Button(root, text='eraser', command=use_eraser)
eraser_button.grid(row=0, column=3)
choose_size_button = Scale(root, from_=1, to=10, orient=HORIZONTAL)
choose_size_button.grid(row=0, column=4)
c = Canvas(root, bg='white', width=600, height=600)
c.grid(row=1, columnspan=5)
setup()
root.mainloop()
The smart solution would be to use sth. like this:
from tkinter import *
from tkinter.colorchooser import askcolor
import tkinter as tk
DEFAULT_PEN_SIZE = 5.0
DEFAULT_COLOR = 'black'
class ABC:
def setup(self):
self.old_x = None
self.old_y = None
self.line_width = self.choose_size_button.get()
self.color = DEFAULT_COLOR
self.eraser_on = False
self.active_button = self.pen_button
self.c.bind('<B1-Motion>', self.paint)
self.c.bind('<ButtonRelease-1>', self.reset)
def use_pen(self):
self.activate_button(self.pen_button)
def use_brush(self):
self.activate_button(self.brush_button)
def choose_color(self):
self.eraser_on = False
self.color = askcolor(color=self.color)[1]
def use_eraser(self):
self.activate_button(self.eraser_button, eraser_mode=True)
def activate_button(self, some_button, eraser_mode=False):
self.active_button.config(relief=RAISED)
some_button.config(relief=SUNKEN)
self.active_button = some_button
self.eraser_on = eraser_mode
def paint(self, event):
self.line_width = self.choose_size_button.get()
self.paint_color = 'white' if self.eraser_on else self.color
if self.old_x and self.old_y:
self.c.create_line(self.old_x, self.old_y, event.x, event.y,
width=self.line_width, fill=self.paint_color,
capstyle=ROUND, smooth=TRUE, splinesteps=36)
self.old_x = event.x
self.old_y = event.y
def reset(self, event):
self.old_x, self.old_y = None, None
def __init__(self):
self.root = tk.Tk()
self.pen_button = Button(self.root, text='pen', command=self.use_pen)
self.pen_button.grid(row=0, column=0)
self.brush_button = Button(self.root, text='brush', command=self.use_brush)
self.brush_button.grid(row=0, column=1)
self.color_button = Button(self.root, text='color', command=self.choose_color)
self.color_button.grid(row=0, column=2)
self.eraser_button = Button(self.root, text='eraser', command=self.use_eraser)
self.eraser_button.grid(row=0, column=3)
self.choose_size_button = Scale(self.root, from_=1, to=10, orient=HORIZONTAL)
self.choose_size_button.grid(row=0, column=4)
self.c = Canvas(self.root, bg='white', width=600, height=600)
self.c.grid(row=1, columnspan=5)
self.setup()
self.root.mainloop()
ABC()
Learn simple OOP principles! Hope that's helpful!
After changing the font size of the widget text increases , how to make it static?
I'm giving you all the code so you can run the program. So do not swear
from tkinter import*
import tkinter as tk
from tkinter import Toplevel, Listbox, StringVar, BooleanVar, TclError
from tkinter import filedialog, scrolledtext,Menu,END,messagebox
from tkinter.ttk import Checkbutton, Frame, Label, Button, Scrollbar, Style, Entry
from tkinter.font import families, Font
from locale import getdefaultlocale
import PIL
from PIL import Image, ImageTk
__version__ = "2.0.2"
# --- translation
EN = {"Cancel": "Cancel", "Bold": "Bold", "Italic": "Italic",
"Underline": "Underline", "Overstrike": "Strikethrough"}
FR = {"Cancel": "Annuler", "Bold": "Gras", "Italic": "Italique",
"Underline": "Souligné", "Overstrike": "Barré"}
LANGUAGES = {"fr": FR, "en": EN}
if getdefaultlocale()[0][:2] == "fr":
TR = LANGUAGES["fr"]
else:
TR = LANGUAGES["en"]
class FontChooser(Toplevel):
""".Font chooser dialog."""
def __init__(self, master, font_dict={}, text="Abcd", title="Font Chooser",
**kwargs):
"""
Create a new FontChooser instance.
Arguments:
master: master window
font_dict: dictionnary, like the one returned by the .actual
method of a Font object:
{'family': 'DejaVu Sans',
'overstrike': False,
'size': 12,
'slant': 'italic' or 'roman',
'underline': False,
'weight': 'bold' or 'normal'}
text: text to be displayed in the preview label
title: window title
**kwargs: additional keyword arguments to be passed to
Toplevel.__init__
"""
Toplevel.__init__(self, master, **kwargs)
self.title(title)
self.resizable(False, False)
self.protocol("WM_DELETE_WINDOW", self.quit)
self._validate_family = self.register(self.validate_font_family)
self._validate_size = self.register(self.validate_font_size)
# --- variable storing the chosen font
self.res = ""
style = Style(self)
style.configure("prev.TLabel", background="white")
bg = style.lookup("TLabel", "background")
self.configure(bg=bg)
# --- family list
self.fonts = list(set(families()))
self.fonts.append("TkDefaultFont")
self.fonts.sort()
for i in range(len(self.fonts)):
self.fonts[i] = self.fonts[i].replace(" ", "\ ")
max_length = int(2.5 * max([len(font) for font in self.fonts])) // 3
self.sizes = ["%i" % i for i in (list(range(6, 17)) + list(range(18, 32, 2)))]
# --- font default
font_dict["weight"] = font_dict.get("weight", "normal")
font_dict["slant"] = font_dict.get("slant", "roman")
font_dict["underline"] = font_dict.get("underline", False)
font_dict["overstrike"] = font_dict.get("overstrike", False)
font_dict["family"] = font_dict.get("family",
self.fonts[0].replace('\ ', ' '))
font_dict["size"] = font_dict.get("size", 10)
# --- creation of the widgets
# ------ style parameters (bold, italic ...)
options_frame = Frame(self, relief='groove', borderwidth=2)
self.font_family = StringVar(self, " ".join(self.fonts))
self.font_size = StringVar(self, " ".join(self.sizes))
self.var_bold = BooleanVar(self, font_dict["weight"] == "bold")
b_bold = Checkbutton(options_frame, text=TR["Bold"],
command=self.toggle_bold,
variable=self.var_bold)
b_bold.grid(row=0, sticky="w", padx=4, pady=(4, 2))
self.var_italic = BooleanVar(self, font_dict["slant"] == "italic")
b_italic = Checkbutton(options_frame, text=TR["Italic"],
command=self.toggle_italic,
variable=self.var_italic)
b_italic.grid(row=1, sticky="w", padx=4, pady=2)
self.var_underline = BooleanVar(self, font_dict["underline"])
b_underline = Checkbutton(options_frame, text=TR["Underline"],
command=self.toggle_underline,
variable=self.var_underline)
b_underline.grid(row=2, sticky="w", padx=4, pady=2)
self.var_overstrike = BooleanVar(self, font_dict["overstrike"])
b_overstrike = Checkbutton(options_frame, text=TR["Overstrike"],
variable=self.var_overstrike,
command=self.toggle_overstrike)
b_overstrike.grid(row=3, sticky="w", padx=4, pady=(2, 4))
# ------ Size and family
self.var_size = StringVar(self)
self.entry_family = Entry(self, width=max_length, validate="key",
validatecommand=(self._validate_family, "%d", "%S",
"%i", "%s", "%V"))
self.entry_size = Entry(self, width=4, validate="key",
textvariable=self.var_size,
validatecommand=(self._validate_size, "%d", "%P", "%V"))
self.list_family = Listbox(self, selectmode="browse",
listvariable=self.font_family, highlightthickness=0, exportselection=False, width=max_length)
self.list_size = Listbox(self, selectmode="browse",
listvariable=self.font_size, highlightthickness=0, exportselection=False, width=4)
scroll_family = Scrollbar(self, orient='vertical', command=self.list_family.yview)
scroll_size = Scrollbar(self, orient='vertical', command=self.list_size.yview)
self.preview_font = Font(self, **font_dict)
if len(text) > 30:
text = text[:30]
self.preview = Label(self, relief="groove", style="prev.TLabel", text=text, font=self.preview_font, anchor="center")
self.list_family.configure(yscrollcommand=scroll_family.set)
self.list_size.configure(yscrollcommand=scroll_size.set)
self.entry_family.insert(0, font_dict["family"])
self.entry_family.selection_clear()
self.entry_family.icursor("end")
self.entry_size.insert(0, font_dict["size"])
try:
i = self.fonts.index(self.entry_family.get().replace(" ", "\ "))
except ValueError:
i = 0
self.list_family.selection_clear(0, "end")
self.list_family.selection_set(i)
self.list_family.see(i)
try:
i = self.sizes.index(self.entry_size.get())
self.list_size.selection_clear(0, "end")
self.list_size.selection_set(i)
self.list_size.see(i)
except ValueError:
pass
self.entry_family.grid(row=0, column=0, sticky="ew", pady=(10, 1), padx=(10, 0))
self.entry_size.grid(row=0, column=2, sticky="ew", pady=(10, 1), padx=(10, 0))
self.list_family.grid(row=1, column=0, sticky="nsew", pady=(1, 10), padx=(10, 0))
self.list_size.grid(row=1, column=2, sticky="nsew", pady=(1, 10), padx=(10, 0))
scroll_family.grid(row=1, column=1, sticky='ns', pady=(1, 10))
scroll_size.grid(row=1, column=3, sticky='ns', pady=(1, 10))
options_frame.grid(row=0, column=4, rowspan=2, padx=10, pady=10, ipadx=10)
self.preview.grid(row=2, column=0, columnspan=5, sticky="eswn", padx=10, pady=(0, 10), ipadx=4, ipady=4)
button_frame = Frame(self)
button_frame.grid(row=3, column=0, columnspan=5, pady=(0, 10), padx=10)
Button(button_frame, text="Ok", command=self.ok).grid(row=0, column=0, padx=4, sticky='ew')
Button(button_frame, text=TR["Cancel"], command=self.quit).grid(row=0, column=1, padx=4, sticky='ew')
self.list_family.bind('<<ListboxSelect>>', self.update_entry_family)
self.list_size.bind('<<ListboxSelect>>', self.update_entry_size, add=True)
self.list_family.bind("<KeyPress>", self.keypress)
self.entry_family.bind("<Return>", self.change_font_family)
self.entry_family.bind("<Tab>", self.tab)
self.entry_size.bind("<Return>", self.change_font_size)
self.entry_family.bind("<Down>", self.down_family)
self.entry_size.bind("<Down>", self.down_size)
self.entry_family.bind("<Up>", self.up_family)
self.entry_size.bind("<Up>", self.up_size)
self.bind_class("TEntry", "<Control-a>", self.select_all)
self.wait_visibility(self)
self.grab_set()
self.entry_family.focus_set()
self.lift()
def select_all(self, event):
event.widget.selection_range(0, "end")
def keypress(self, event):
key = event.char.lower()
l = [i for i in self.fonts if i[0].lower() == key]
if l:
i = self.fonts.index(l[0])
self.list_family.selection_clear(0, "end")
self.list_family.selection_set(i)
self.list_family.see(i)
self.update_entry_family()
def up_family(self, event):
try:
i = self.list_family.curselection()[0]
self.list_family.selection_clear(0, "end")
if i <= 0:
i = len(self.fonts)
self.list_family.see(i - 1)
self.list_family.select_set(i - 1)
except TclError:
self.list_family.selection_clear(0, "end")
i = len(self.fonts)
self.list_family.see(i - 1)
self.list_family.select_set(i - 1)
self.list_family.event_generate('<<ListboxSelect>>')
def up_size(self, event):
"""Navigate in the size listbox with up key."""
try:
s = self.var_size.get()
if s in self.sizes:
i = self.sizes.index(s)
elif s:
sizes = list(self.sizes)
sizes.append(s)
sizes.sort(key=lambda x: int(x))
i = sizes.index(s)
else:
i = 0
self.list_size.selection_clear(0, "end")
if i <= 0:
i = len(self.sizes)
self.list_size.see(i - 1)
self.list_size.select_set(i - 1)
except TclError:
i = len(self.sizes)
self.list_size.see(i - 1)
self.list_size.select_set(i - 1)
self.list_size.event_generate('<<ListboxSelect>>')
def down_family(self, event):
"""Navigate in the family listbox with down key."""
try:
i = self.list_family.curselection()[0]
self.list_family.selection_clear(0, "end")
if i >= len(self.fonts):
i = -1
self.list_family.see(i + 1)
self.list_family.select_set(i + 1)
except TclError:
self.list_family.selection_clear(0, "end")
self.list_family.see(0)
self.list_family.select_set(0)
self.list_family.event_generate('<<ListboxSelect>>')
def down_size(self, event):
"""Navigate in the size listbox with down key."""
try:
s = self.var_size.get()
if s in self.sizes:
i = self.sizes.index(s)
elif s:
sizes = list(self.sizes)
sizes.append(s)
sizes.sort(key=lambda x: int(x))
i = sizes.index(s) - 1
else:
s = len(self.sizes) - 1
self.list_size.selection_clear(0, "end")
if i < len(self.sizes) - 1:
self.list_size.selection_set(i + 1)
self.list_size.see(i + 1)
else:
self.list_size.see(0)
self.list_size.select_set(0)
except TclError:
self.list_size.selection_set(0)
self.list_size.event_generate('<<ListboxSelect>>')
def toggle_bold(self):
"""Update font preview weight."""
b = self.var_bold.get()
self.preview_font.configure(weight=["normal", "bold"][b])
def toggle_italic(self):
"""Update font preview slant."""
b = self.var_italic.get()
self.preview_font.configure(slant=["roman", "italic"][b])
def toggle_underline(self):
"""Update font preview underline."""
b = self.var_underline.get()
self.preview_font.configure(underline=b)
def toggle_overstrike(self):
"""Update font preview overstrike."""
b = self.var_overstrike.get()
self.preview_font.configure(overstrike=b)
def change_font_family(self, event=None):
"""Update font preview family."""
family = self.entry_family.get()
if family.replace(" ", "\ ") in self.fonts:
self.preview_font.configure(family=family)
def change_font_size(self, event=None):
"""Update font preview size."""
size = int(self.var_size.get())
self.preview_font.configure(size=size)
def validate_font_size(self, d, ch, V):
"""Validation of the size entry content."""
l = [i for i in self.sizes if i[:len(ch)] == ch]
i = None
if l:
i = self.sizes.index(l[0])
elif ch.isdigit():
sizes = list(self.sizes)
sizes.append(ch)
sizes.sort(key=lambda x: int(x))
i = min(sizes.index(ch), len(self.sizes))
if i is not None:
self.list_size.selection_clear(0, "end")
self.list_size.selection_set(i)
deb = self.list_size.nearest(0)
fin = self.list_size.nearest(self.list_size.winfo_height())
if V != "forced":
if i < deb or i > fin:
self.list_size.see(i)
return True
if d == '1':
return ch.isdigit()
else:
return True
def tab(self, event):
"""Move at the end of selected text on tab press."""
self.entry_family = event.widget
self.entry_family.selection_clear()
self.entry_family.icursor("end")
return "break"
def validate_font_family(self, action, modif, pos, prev_txt, V):
"""Completion of the text in the entry with existing font names."""
if self.entry_family.selection_present():
sel = self.entry_family.selection_get()
txt = prev_txt.replace(sel, '')
else:
txt = prev_txt
if action == "0":
txt = txt[:int(pos)] + txt[int(pos) + 1:]
return True
else:
txt = txt[:int(pos)] + modif + txt[int(pos):]
ch = txt.replace(" ", "\ ")
l = [i for i in self.fonts if i[:len(ch)] == ch]
if l:
i = self.fonts.index(l[0])
self.list_family.selection_clear(0, "end")
self.list_family.selection_set(i)
deb = self.list_family.nearest(0)
fin = self.list_family.nearest(self.list_family.winfo_height())
index = self.entry_family.index("insert")
self.entry_family.delete(0, "end")
self.entry_family.insert(0, l[0].replace("\ ", " "))
self.entry_family.selection_range(index + 1, "end")
self.entry_family.icursor(index + 1)
if V != "forced":
if i < deb or i > fin:
self.list_family.see(i)
return True
else:
return False
def update_entry_family(self, event=None):
"""Update family entry when an item is selected in the family listbox."""
# family = self.list_family.get("#%i,%i" % (event.x , event.y))
family = self.list_family.get(self.list_family.curselection()[0])
self.entry_family.delete(0, "end")
self.entry_family.insert(0, family)
self.entry_family.selection_clear()
self.entry_family.icursor("end")
self.change_font_family()
def update_entry_size(self, event):
"""Update size entry when an item is selected in the size listbox."""
# size = self.list_size.get("#%i,%i" % (event.x , event.y))
size = self.list_size.get(self.list_size.curselection()[0])
self.var_size.set(size)
self.change_font_size()
def ok(self):
"""Validate choice."""
self.res = self.preview_font.actual()
self.quit()
def get_res(self):
"""Return chosen font."""
return self.res
def quit(self):
self.destroy()
def askfont(master=None, text="Abcd", title="Font Chooser", **font_args):
chooser = FontChooser(master, font_args, text, title)
chooser.wait_window(chooser)
return chooser.get_res()
def edit_font():
font = askfont(root, title="Choose a font")
if font:
font['family'] = font['family'].replace(' ', '\ ')
font_str = "%(family)s %(size)i %(weight)s %(slant)s" % font
if font['underline']:
font_str += ' underline'
if font['overstrike']:
font_str += ' overstrike'
text.configure(font=font_str)
root=tk.Tk()
root.geometry("1423x800")
# added weights so the widget resizes correctly with window
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
image = ImageTk.PhotoImage(file="0.png")
lab=tk.Label(root, image = image)
lab.grid(row=0, column=0)
text=tk.Text(root,width = 60,height=15, font=Font(family="Helvetica", size=10))
text.grid(row=0, column=0)
king=tk.Menu(root)
root.config(menu=king)
view=tk.Menu(king, tearoff=0)
view2=tk.Menu(view, tearoff=0)
view2.add_command(label='Font',command=edit_font)
view.add_cascade(label='Text', menu=view2)
king.add_cascade(label='View', menu=view)
root.mainloop()
This is the code you will most likely need to fix my problem:
def askfont(master=None, text="Abcd", title="Font Chooser", **font_args):
chooser = FontChooser(master, font_args, text, title)
chooser.wait_window(chooser)
return chooser.get_res()
def edit_font():
font = askfont(root, title="Choose a font")
if font:
font['family'] = font['family'].replace(' ', '\ ')
font_str = "%(family)s %(size)i %(weight)s %(slant)s" % font
if font['underline']:
font_str += ' underline'
if font['overstrike']:
font_str += ' overstrike'
text.configure(font=font_str)
root=tk.Tk()
root.geometry("1423x800")
# added weights so the widget resizes correctly with window
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
image = ImageTk.PhotoImage(file="0.png")
lab=tk.Label(root, image = image)
lab.grid(row=0, column=0)
text=tk.Text(root,width = 60,height=15, font=Font(family="Helvetica", size=10))
text.grid(row=0, column=0)
king=tk.Menu(root)
root.config(menu=king)
view=tk.Menu(king, tearoff=0)
view2=tk.Menu(view, tearoff=0)
view2.add_command(label='Font',command=edit_font)
view.add_cascade(label='Text', menu=view2)
king.add_cascade(label='View', menu=view)
root.mainloop()
This will probably include setting the frame size and frame, as well as banning distribution, one of my friends said. Hope this helps you
If you give the Text widget a fixed height and width and wrap it in a Frame with the same width and height and use grid_propagate(False), when the text is made bigger the Text widget stays the same size.
import tkinter as tk
def fontUp():
text.config(font = ("30"))
root = tk.Tk()
root.geometry("800x800")
frm = tk.Frame(root, height = 500, width = 500)
frm.grid(row = 0, column = 0)
frm.grid_propagate(False)
text = tk.Text(frm, height = 500, width = 500)
text.grid(row = 0, column = 0)
btn = tk.Button(root, text="Font bigger", command = fontUp)
btn.grid(row = 2, column = 0)
This code is fine, but I would like to scroll the page using the mousewheel just like we do with Chrome, when the pointer of the mouse is in the middle of the page.
import tkinter as tk
from random import randint
class ScrolledFrame(tk.Frame):
def __init__(self, parent, vertical=True, horizontal=False):
super().__init__(parent)
self._canvas = tk.Canvas(self)
self._canvas.grid(row=0, column=0, sticky='news') # changed
self._vertical_bar = tk.Scrollbar(self, orient='vertical', command=self._canvas.yview)
if vertical:
self._vertical_bar.grid(row=0, column=1, sticky='ns')
self._canvas.configure(yscrollcommand=self._vertical_bar.set)
self._horizontal_bar = tk.Scrollbar(self, orient='horizontal', command=self._canvas.xview)
if horizontal:
self._horizontal_bar.grid(row=1, column=0, sticky='we')
self._canvas.configure(xscrollcommand=self._horizontal_bar.set)
self._vertical_bar.config(command=self._canvas.yview)
self.inner = tk.Frame(self._canvas, bg='red')
self._window = self._canvas.create_window((0, 0), window=self.inner, anchor='nw')
self.columnconfigure(0, weight=1) # changed
self.rowconfigure(0, weight=1) # changed
self.inner.bind('<Configure>', self.resize)
self._canvas.bind('<Configure>', self.frame_width)
def frame_width(self, event):
canvas_width = event.width
self._canvas.itemconfig(self._window, width=canvas_width)
def resize(self, event=None):
self._canvas.configure(scrollregion=self._canvas.bbox('all'))
class Question:
def __init__(self, parent, question, answer):
self.parent = parent
self.question = question
self.answer = answer
self.create_widgets()
def get_input(self):
value = self.entry.get()
print('value:', value)
if value == self.answer:
print("Right it's " + self.answer)
self.label['text'] = self.question + "Right it's " + self.answer
else:
self.label['text'] = "Sorry, it was " + self.answer
def create_widgets(self):
self.labelframe = tk.LabelFrame(self.parent, text="Domanda:")
self.labelframe.pack(fill="both", expand=True)
self.label = tk.Label(self.labelframe, text=self.question)
self.label.pack(expand=True, fill='both')
self.entry = tk.Entry(self.labelframe)
self.entry.pack()
self.entry.bind("<Return>", lambda x: self.get_input())
root = tk.Tk()
root.title("Quiz")
root.geometry("400x300")
window = ScrolledFrame(root)
window.pack(expand=True, fill='both')
for i in range(10):
one = randint(1, 10)
two = randint(1, 10)
Question(window.inner, "How is the result of {} + {} ?".format(one, two), str(one + two))
root.mainloop()
I found how to make it
Ok, I had some problems asking how to make it, but thanks to https://code.activestate.com/recipes/580640-scrolling-frame-with-mouse-wheel-support/ I succeded in making the mousewheel work as I intended. If it can help, the example is here.
import tkinter as tk
from random import randint
# --- classes ---
try:
from Tkinter import Canvas, Frame
from ttk import Scrollbar
from Tkconstants import *
except ImportError:
from tkinter import Canvas, Frame
from tkinter.ttk import Scrollbar
from tkinter.constants import *
import platform
OS = platform.system()
class Mousewheel_Support(object):
# implemetation of singleton pattern
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = object.__new__(cls)
return cls._instance
def __init__(self, root, horizontal_factor=2, vertical_factor=2):
self._active_area = None
if isinstance(horizontal_factor, int):
self.horizontal_factor = horizontal_factor
else:
raise Exception("Vertical factor must be an integer.")
if isinstance(vertical_factor, int):
self.vertical_factor = vertical_factor
else:
raise Exception("Horizontal factor must be an integer.")
if OS == "Linux":
root.bind_all('<4>', self._on_mousewheel, add='+')
root.bind_all('<5>', self._on_mousewheel, add='+')
else:
# Windows and MacOS
root.bind_all("<MouseWheel>", self._on_mousewheel, add='+')
def _on_mousewheel(self, event):
if self._active_area:
self._active_area.onMouseWheel(event)
def _mousewheel_bind(self, widget):
self._active_area = widget
def _mousewheel_unbind(self):
self._active_area = None
def add_support_to(self, widget=None, xscrollbar=None, yscrollbar=None, what="units", horizontal_factor=None, vertical_factor=None):
if xscrollbar is None and yscrollbar is None:
return
if xscrollbar is not None:
horizontal_factor = horizontal_factor or self.horizontal_factor
xscrollbar.onMouseWheel = self._make_mouse_wheel_handler(widget, 'x', self.horizontal_factor, what)
xscrollbar.bind('<Enter>', lambda event, scrollbar=xscrollbar: self._mousewheel_bind(scrollbar))
xscrollbar.bind('<Leave>', lambda event: self._mousewheel_unbind())
if yscrollbar is not None:
vertical_factor = vertical_factor or self.vertical_factor
yscrollbar.onMouseWheel = self._make_mouse_wheel_handler(widget, 'y', self.vertical_factor, what)
yscrollbar.bind('<Enter>', lambda event, scrollbar=yscrollbar: self._mousewheel_bind(scrollbar))
yscrollbar.bind('<Leave>', lambda event: self._mousewheel_unbind())
main_scrollbar = yscrollbar if yscrollbar is not None else xscrollbar
if widget is not None:
if isinstance(widget, list) or isinstance(widget, tuple):
list_of_widgets = widget
for widget in list_of_widgets:
widget.bind('<Enter>', lambda event: self._mousewheel_bind(widget))
widget.bind('<Leave>', lambda event: self._mousewheel_unbind())
widget.onMouseWheel = main_scrollbar.onMouseWheel
else:
widget.bind('<Enter>', lambda event: self._mousewheel_bind(widget))
widget.bind('<Leave>', lambda event: self._mousewheel_unbind())
widget.onMouseWheel = main_scrollbar.onMouseWheel
#staticmethod
def _make_mouse_wheel_handler(widget, orient, factor=1, what="units"):
view_command = getattr(widget, orient + 'view')
if OS == 'Linux':
def onMouseWheel(event):
if event.num == 4:
view_command("scroll", (-1) * factor, what)
elif event.num == 5:
view_command("scroll", factor, what)
elif OS == 'Windows':
def onMouseWheel(event):
view_command("scroll", (-1) * int((event.delta / 120) * factor), what)
elif OS == 'Darwin':
def onMouseWheel(event):
view_command("scroll", event.delta, what)
return onMouseWheel
class Scrolling_Area(Frame, object):
def __init__(self, master, width=None, anchor=N, height=None, mousewheel_speed=2, scroll_horizontally=True, xscrollbar=None, scroll_vertically=True, yscrollbar=None, background=None, inner_frame=Frame, **kw):
Frame.__init__(self, master, class_="Scrolling_Area", background=background)
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
self._width = width
self._height = height
self.canvas = Canvas(self, background=background, highlightthickness=0, width=width, height=height)
self.canvas.grid(row=0, column=0, sticky=N + E + W + S)
if scroll_vertically:
if yscrollbar is not None:
self.yscrollbar = yscrollbar
else:
self.yscrollbar = Scrollbar(self, orient=VERTICAL)
self.yscrollbar.grid(row=0, column=1, sticky=N + S)
self.canvas.configure(yscrollcommand=self.yscrollbar.set)
self.yscrollbar['command'] = self.canvas.yview
else:
self.yscrollbar = None
if scroll_horizontally:
if xscrollbar is not None:
self.xscrollbar = xscrollbar
else:
self.xscrollbar = Scrollbar(self, orient=HORIZONTAL)
self.xscrollbar.grid(row=1, column=0, sticky=E + W)
self.canvas.configure(xscrollcommand=self.xscrollbar.set)
self.xscrollbar['command'] = self.canvas.xview
else:
self.xscrollbar = None
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
self.innerframe = inner_frame(self.canvas, **kw)
self.innerframe.pack(anchor=anchor)
self.canvas.create_window(0, 0, window=self.innerframe, anchor='nw', tags="inner_frame")
self.canvas.bind('<Configure>', self._on_canvas_configure)
Mousewheel_Support(self).add_support_to(self.canvas, xscrollbar=self.xscrollbar, yscrollbar=self.yscrollbar)
#property
def width(self):
return self.canvas.winfo_width()
#width.setter
def width(self, width):
self.canvas.configure(width=width)
#property
def height(self):
return self.canvas.winfo_height()
#height.setter
def height(self, height):
self.canvas.configure(height=height)
def set_size(self, width, height):
self.canvas.configure(width=width, height=height)
def _on_canvas_configure(self, event):
width = max(self.innerframe.winfo_reqwidth(), event.width)
height = max(self.innerframe.winfo_reqheight(), event.height)
self.canvas.configure(scrollregion="0 0 %s %s" % (width, height))
self.canvas.itemconfigure("inner_frame", width=width, height=height)
def update_viewport(self):
self.update()
window_width = self.innerframe.winfo_reqwidth()
window_height = self.innerframe.winfo_reqheight()
if self._width is None:
canvas_width = window_width
else:
canvas_width = min(self._width, window_width)
if self._height is None:
canvas_height = window_height
else:
canvas_height = min(self._height, window_height)
self.canvas.configure(scrollregion="0 0 %s %s" % (window_width, window_height), width=canvas_width, height=canvas_height)
self.canvas.itemconfigure("inner_frame", width=window_width, height=window_height)
class Question:
def __init__(self, parent, question, answer):
self.parent = parent
self.question = question
self.answer = answer
self.create_widgets()
def get_input(self):
value = self.entry.get()
print('value:', value)
if value == self.answer:
print("Right it's " + self.answer)
self.label['text'] = self.question + "Right it's " + self.answer
else:
self.label['text'] = "Sorry, it was " + self.answer
def create_widgets(self):
self.labelframe = tk.LabelFrame(self.parent, text="Domanda:")
self.labelframe.pack(fill="both", expand=True)
self.label = tk.Label(self.labelframe, text=self.question)
self.label.pack(expand=True, fill='both')
self.entry = tk.Entry(self.labelframe)
self.entry.pack()
self.entry.bind("<Return>", lambda x: self.get_input())
# self.button = tk.Button(self.labelframe, text="Click", command=self.get_input)
# self.button.pack()
# --- main ---
root = tk.Tk()
root.title("Quiz")
root.geometry("400x300")
window = Scrolling_Area(root)
window.pack(expand=True, fill='both')
for i in range(10):
one = randint(1, 10)
two = randint(1, 10)
Question(window.innerframe, "How is the result of {} + {} ?".format(one, two), str(one + two))
domande = [("Qual è la prima leva del marketing mix? (prodotto o prezzo?", "prodotto")]
for d, r in domande:
Question(window.innerframe, d, r)
root.mainloop()
Sorry for the mess
so I am making a seating chart, and I cant seem to get it working properly... again. I am trying to make the label reset every time i press the run button, any ideas?
#commands: add name , Run
#imports
import random
from time import sleep
from tkinter import *
#Console and background Handlers
Tables = 6
Names = []
def AddNames():
NewNames = e.get("1.0", 'end -1c')
if NewNames in Names:
print("Name Already exists")
elif NewNames == "":
print("Empty")
else:
Names.append(NewNames)
print(Names)
e.delete(1.0, END)
def Random():
RandomNum = random.randrange(Tables)
if RandomNum == 0:
RandomNum = random.randrange(Tables)
return RandomNum
def run():
X = 0
for i in Names:
#print(Names[X])
print("Table: " + str(Random()))
X += 1
#text = Label(popup, text = "")
text = Label(popup, text= Names[X] + "\n" + "Table: " + str(Random()))
text.pack()
#GUI Handler
root = Tk()
root.geometry("1024x768")
e = Text(root, bd = 10, font=("Comic Sans MS", 50) ,width = 15, height = 2)
e.pack()
popup = Toplevel()
popup.title("Seating Chart")
AddNameButton = Button(root, text = ("Add Name"), width = 15, height = 5, command = AddNames)
AddNameButton.pack()
RunButton = Button(root, text = ("Run"), width = 15, height = 5, command = run)
RunButton.pack()
root.mainloop()
I am trying to reset text every time the user presses the run button
import tkinter
from tkinter import ttk
import random
class MyApp:
def __init__(self):
self.root = tkinter.Tk()
self.seatwindow = None
self.root.title('Add Names')
self.currentname = tkinter.StringVar()
self._maxtables = tkinter.StringVar()
self.addednames = []
self.commandframe = ttk.Labelframe(self.root, text='Commands')
self.nameentry = ttk.Entry(self.root, textvariable=self.currentname)
self.addbutton = ttk.Button(self.root, text='Add Name', command=self.addname)
self.maxtablabel = ttk.Label(self.root, text='Tables: ')
self.maxtabentry = ttk.Entry(self.root, textvariable=self._maxtables)
self.genbutton = ttk.Button(self.commandframe, text='Run', command=self.generate)
self.resetbutton = ttk.Button(self.commandframe, text='Reset', command=self.reset)
self._maxtables.set('6')
self.nameentry.grid(row=0, column=0)
self.addbutton.grid(row=0, column=1, sticky='nsew')
self.maxtabentry.grid(row=1, column=1, sticky='nsw')
self.maxtablabel.grid(row=1, column=0, sticky='nse')
self.genbutton.grid(row=0, column=0, sticky='nsew')
self.resetbutton.grid(row=0, column=1, sticky='nsew')
self.commandframe.grid(row=2, column=0, columnspan=2, sticky='nsew')
self.nameentry.bind('<Return>', self.addname)
self.root.bind('<Control-Return>', self.generate)
def addname(self, event=None):
name = self.currentname.get()
if not(name == '' or name in self.addednames):
self.addednames.append(name)
self.currentname.set('')
else:
self.currentname.set('Name already added!')
def generate(self, event=None):
if not self.seatwindow == None:
self.seatwindow.destroy()
self.currentname.set('')
self.seatwindow = tkinter.Toplevel()
random.shuffle(self.addednames)
tables = []
for i in range(self.maxtables):
tableframe = ttk.Labelframe(self.seatwindow, text='Table ' + str(i + 1) + ':')
tableframe.grid(column=i, row=0, sticky='nsew')
tables.append(tableframe)
for index, name in enumerate(self.addednames):
namelabel = ttk.Label(tables[index%self.maxtables], text=name)
namelabel.grid(column=0, row=index//self.maxtables + 1)
def reset(self):
self.currentname.set('')
self.maxtables = 6
self.addednames = []
def run(self):
self.root.mainloop()
#property
def maxtables(self):
return int(self._maxtables.get())
MyApp().run()
I tried this:
self.btnquit = button(calc_frame, "Quit", tk.destroy)
self.btnquit.pack(side = LEFT)
before self.input = ...
But it came out invalid syntax. And the backspace only works if its in front of the number but I want it to be able to ackspace the last number entered, clear the last equation and then:
from tkinter import *
from tkinter.font import Font
def button(frame, text, command=None):
ft = Font(family=('Verdana'), size=14)
return Button(frame, text=text, font=ft, width=3, command=command)
def frame(frame, side=LEFT, bg="black"):
f = Frame(frame, background=bg, padx=5, pady=5)
f.pack(side=side, expand=YES, fill=BOTH)
return f
class App:
def __init__(self, tk):
ft = Font(family=('Verdana'), size=14)
main = frame(tk)
l_frame = frame(main)
r_frame = frame(main)
calc_frame = frame(l_frame)
self.input = Entry(calc_frame, font=ft, width=15, background="white")
self.input.pack(side=TOP)
self.btn_frame = frame(calc_frame)
x, y = 0, 0
for key in ("()%C", "+-*/", "1234", "5678", "90.="):
for c in key:
if c == "=":
btn = button(self.btn_frame, c, self.equalAction)
elif c == "C":
btn = button(self.btn_frame, c, self.cleanAction)
else:
btn = button(self.btn_frame, c, lambda i=c: self.input.insert(INSERT, i))
btn.grid(row=x, column=y)
y += 1
x += 1
y = 0
self.log = Text(r_frame, font=Font(family=('Verdana'), size=10), width=25, height=14, background="yellow")
self.log.pack(side=RIGHT)
def cleanAction(self):
self.input.delete(0, END)
def equalAction(self):
tmp = self.input.get()
try:
result = tmp + "=" + str(eval(tmp))
self.log.insert(1.0, result + "\n");
print(result)
except Exception:
self.log.insert(1.0, "Wrong expression\n");
if __name__ == '__main__':
root = Tk()
root.title("Calculator")
root.geometry()
app = App(root)
root.mainloop()
You can bind function to BackSpace in __init__
only when cursor (focus) is in Entry
self.input.bind_all('<BackSpace>', self.cleanInput)
or for all situations
main.bind_all('<BackSpace>', self.cleanInput)
and than you can delete text in Entry and Text
def cleanInput(self, event):
self.input.delete(0, END)
self.log.delete(1.0, END)
BTW: the same way you can bind other keys - for example digits
else:
btn = button(self.btn_frame, c, lambda i=c: self.input.insert(INSERT, i))
main.bind_all(c, lambda event, i=c:self.input.insert(INSERT, i))
EDIT:
full working code:
(issue: at that moment when cursor is in Entry numbers are inserted twice - normaly and by binding)
# python 2.x
#from Tkinter import *
#from tkFont import Font
# python 3.x
from tkinter import *
from tkinter.font import Font
class App:
def __init__(self, tk):
self.tk = tk
self.tk.title("Calculator")
#self.tk.geometry()
self.button_font = Font(family=('Verdana'), size=14)
main_frame = self.create_frame(self.tk)
left_frame = self.create_frame(main_frame)
right_frame = self.create_frame(main_frame)
calc_frame = self.create_frame(left_frame)
self.btnquit = self.create_button(calc_frame, "Quit", self.tk.destroy)
self.btnquit.pack(side = LEFT)
self.log = Text(right_frame, font=Font(family=('Verdana'), size=10), width=25, height=14, background="yellow")
self.log.pack(side=RIGHT)
self.input_text = StringVar()
self.input = Entry(calc_frame, font=self.button_font, width=15, background="white", textvariable=self.input_text)
self.input.pack(side=TOP)
btn_frame = self.create_frame(calc_frame)
for x, key in enumerate( ("()%C", "+-*/", "1234", "5678", "90.=") ):
for y, c in enumerate(key):
if c == "=":
btn = self.create_button(btn_frame, c, self.equalAction)
elif c == "C":
btn = self.create_button(btn_frame, c, self.cleanAction)
else:
btn = self.create_button(btn_frame, c, lambda number=c: self.insertNumber(number))
#main.bind_all(c, lambda event, number=c: self.insertNumber(number))
btn.grid(row=x, column=y)
self.btn_backspace = self.create_button(btn_frame, "<-", self.deleteLastDigit)
self.btn_backspace.grid(row=5, column=2, columnspan=2, sticky="we")
self.btn_loop = self.create_button(btn_frame, "LOOP", self.loopAction)
self.btn_loop.grid(row=5, column=0, columnspan=2, sticky="we")
main_frame.bind_all('<BackSpace>', self.cleanAction)
main_frame.bind_all('<Escape>', self.deleteLastDigit)
def loopAction(self):
bedmas = [ "()", "x^n", "*/", "+-" ]
for element in bedmas:
self.log.insert(INSERT,"\n"+element)
# event=None to use function in command= and in binding
def deleteLastDigit(self, event=None):
self.input_text.set( self.input_text.get()[:-1] )
def insertNumber(self, number):
self.input_text.set( self.input_text.get() + number )
def cleanAction(self):
self.input_text.set("")
self.log.delete(1.0, END)
def equalAction(self):
tmp = self.input_text.get()
try:
result = tmp + "=" + str(eval(tmp))
self.log.insert(1.0, result + "\n");
print(result)
except Exception:
self.log.insert(1.0, "Wrong expression\n");
def create_button(self, frame, text, command=None):
return Button(frame, text=text, font=self.button_font, width=3, command=command)
def create_frame(self, frame, side=LEFT, bg="black"):
f = Frame(frame, background=bg, padx=5, pady=5)
f.pack(side=side, expand=YES, fill=BOTH)
return f
def run(self):
self.tk.mainloop()
#---------------------------------------------------------------------
if __name__ == '__main__':
App(Tk()).run()