How to make my Matplotlib graph embed in a Tkinter GUI - python

I have been messing around with Tkinter and embedded graphs and from a tutorial I found on the net, I have been able to make the following snippet of code work perfectly:
from tkinter import *
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg # NavigationToolbar2TkAgg
from matplotlib.figure import Figure
root = Tk()
# Typical matplotlib code
f = Figure(figsize = (4,3), dpi = 100)
a = f.add_subplot(111)
a.plot([1,2,4,3,5,7,6,7,8,8,9,6,7,8,7,5,6,4,3,4,3,2,1])
canvas = FigureCanvasTkAgg(f, root)
canvas.draw()
canvas.get_tk_widget().pack()
canvas._tkcanvas.pack()
root.mainloop()
The problem is I have not been able to incorporate the idea into a program I have been working on (Collatz Conjecture algorithm). What I'm trying to do is to plot a graph of the iteration data points but the graph does not display, notwithstanding the fact that the relevant portions of code in my script and the example snippet are identical. See my code below:
#!/usr/local/bin/env python3
# -*- coding: utf-8 -*-
from tkinter import *
from tkinter import messagebox
root=Tk()
root.title("Collatz Conjecture")
import textwrap
# Matplotlib imports
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg # NavigationToolbar2TkAgg
from matplotlib.figure import Figure
# Functions
lst = []
def collatz(num):
lst.clear()
while num != 1:
lst.append(num)
if num % 2 == 0:
num = int(num / 2)
else:
num = int(3 * num + 1)
def main(event):
num = int(input.get())
collatz(num)
output1.delete(1.0, END)
output1.insert(END, lst)
output2.delete(1.0, END)
output2.insert(END, "Number of iterations: " + str(len(lst)))
lbl1 = Label(root, width = 20, text = "Type in number\n & press Enter")
lbl1.grid(row = 1, column = 0, sticky = W)
lbl2 = Label(root, width = 40, text = "THE COLLATZ CONJECTURE")
lbl2.grid(row = 4, column = 0)
input = Entry(root, width = 20, bg = "light grey")
input.grid(row = 1, padx = 6, sticky = E)
input.get()
input.bind("<Return>", main)
# Matplotlib Graph - typical code
f = Figure(figsize = (4,3), dpi = 100) # Create the figure
a = f.add_subplot(111) # Add subplot
a.plot(lst)
# Plot data in background
# Canvas
canvas = FigureCanvasTkAgg(f, root)
canvas.draw()
canvas.get_tk_widget().grid(row = 6, column = 0)
canvas._tkcanvas.grid(row = 6, column = 0)
# canvas = Canvas(root, width= 350, height= 350, bg = "white")
# canvas.grid(row = 6, column = 0, padx = (5,5), pady = (5,5))
bt1 = Button(root, width = 10, text = "About")
bt1.grid(row = 7, column = 0, pady = (5,7))
output1 = Text(root, wrap = WORD, width = 50, height = 7, bg = "light grey") # Note word wrap attribute
output1.grid(row = 3, column = 0, padx = (5,1), sticky = W)
output2 = Text(root, width = 50, height = 1, bg = "white")
output2.grid(row = 2, column = 0, sticky = W)
def about():
messagebox.showinfo("About", "The Collatz conjecture states that if you pick any positive whole number, and if its even, you divide it by two and if its odd, you multiply it by three and add one, and if you repeat this procedure often enough, the number that you started with will eventually reduce to one and if you play this game for long enough, your friends will eventually stop calling to see if you want to hang out ")
btn1 = Button(root, text = "About", command = about)
btn1.grid(row = 7, column = 0, pady = (5,7))
root.mainloop()
I'm pretty sure its an indent problem and that I'm going to be very embarrassed when someone points out my novice mistake but I've tried moving the code around in seeminlgly every possible way but without success.
Could someone please have a look at it and tell me not only where I went wrong but more importantly, WHY its wrong.

The issue is fundamental. Your tkinter window loop keeps refreshing the plot canvas so you don't get to see the data. What you could do instead is take the canvas out of your window loop and stick it in the main function.
Obviously there are other/better solutions but I hope this one highlights the issue you are facing.
# -*- coding: utf-8 -*-
from tkinter import *
from tkinter import messagebox
root=Tk()
root.title("Collatz Conjecture")
import textwrap
# Matplotlib imports
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg # NavigationToolbar2TkAgg
from matplotlib.figure import Figure
# Functions
lst = []
def collatz(num):
lst.clear()
while num != 1:
lst.append(num)
if num % 2 == 0:
num = int(num / 2)
else:
num = int(3 * num + 1)
def main(event):
num = int(inp_ut.get())
collatz(num)
output1.delete(1.0, END)
output1.insert(END, lst)
output2.delete(1.0, END)
output2.insert(END, "Number of iterations: " + str(len(lst)))
# Generate the data and populate the canvas once.
f = Figure(figsize = (4,3), dpi = 100) # Create the figure
a = f.add_subplot(111) # Add subplot
a.plot(lst)
canvas = FigureCanvasTkAgg(f, root)
canvas.draw()
canvas.get_tk_widget().grid(row = 6, column = 0)
canvas._tkcanvas.grid(row = 6, column = 0)
lbl1 = Label(root, width = 20, text = "Type in number\n & press Enter")
lbl1.grid(row = 1, column = 0, sticky = W)
lbl2 = Label(root, width = 40, text = "THE COLLATZ CONJECTURE")
lbl2.grid(row = 4, column = 0)
inp_ut = Entry(root, width = 20, bg = "light grey")
inp_ut.grid(row = 1, padx = 6, sticky = E)
inp_ut.get()
inp_ut.bind("<Return>", main)
# Canvas
# canvas = Canvas(root, width= 350, height= 350, bg = "white")
# canvas.grid(row = 6, column = 0, padx = (5,5), pady = (5,5))
bt1 = Button(root, width = 10, text = "About")
bt1.grid(row = 7, column = 0, pady = (5,7))
output1 = Text(root, wrap = WORD, width = 50, height = 7, bg = "light grey") # Note word wrap attribute
output1.grid(row = 3, column = 0, padx = (5,1), sticky = W)
output2 = Text(root, width = 50, height = 1, bg = "white")
output2.grid(row = 2, column = 0, sticky = W)
def about():
messagebox.showinfo("About", "The Collatz conjecture states that if you pick any positive whole number, and if its even, you divide it by two and if its odd, you multiply it by three and add one, and if you repeat this procedure often enough, the number that you started with will eventually reduce to one and if you play this game for long enough, your friends will eventually stop calling to see if you want to hang out ")
btn1 = Button(root, text = "About", command = about)
btn1.grid(row = 7, column = 0, pady = (5,7))
root.mainloop()

Related

Update matplotlib plot correctly - tkinter

Evening,
I want to insert a data point externally into an existing plot (f(x) = x, g(x) = x**2). To do this, the x and y coordinates can be entered in entry fields. The user can then press a button to insert the point.
Assuming a data point (x1, y1) is inserted and the user trys to enter a new data point (x2,y2). In this case the GUI should only display the curves (f(x), g(x)) and the point (x2, y2). The last point (x1,y1) should be deleted.
My solution only partially works: Additional points (x,y) can be created, but the old ones are not deleted...
Does any of you know an approach to solve the problem described above.
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import numpy as np
fig = Figure(figsize = (9, 6), facecolor = "white")
axis = fig.add_subplot(111)
x_values = np.array([1,2,3,4,5,6,7])
axis.plot(x_values, x_values, "-r")
axis.plot(x_values, x_values ** 2, "--g")
axis.grid()
root = tk.Tk()
Label(root, text = "x =" ).grid(row = 0, column = 0)
Label(root, text = "y =" ).grid(row = 1, column = 0)
x = DoubleVar()
y = DoubleVar()
x_entry = Entry(root, textvariable = x).grid(row = 0, column = 1)
y_entry = Entry(root, textvariable = y).grid(row = 1, column = 1)
def plotgraphs():
axis.plot(x.get(), y.get(), "ko")
canvas = FigureCanvasTkAgg(fig, master = root)
canvas._tkcanvas.grid(row = 2, column = 1)
Button(root, text = "New Graphs", command = plotgraphs).grid(row = 0, column = 2)
canvas = FigureCanvasTkAgg(fig, master = root)
canvas._tkcanvas.grid(row = 2, column = 1)
root.mainloop()
You need to delete existing point to get the desired behavior. Below would do - what you are looking for. I did enhanced it a bit.
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import numpy as np
from tkinter import *
fig = Figure(figsize = (9, 6), facecolor = "white")
axis = fig.add_subplot(111)
x_values = np.array([1,2,3,4,5,6,7])
axis.plot(x_values, x_values, "-r", label = 'f(X) = x')
axis.plot(x_values, x_values ** 2, "--g", label = 'f(x) = x\N{SUPERSCRIPT TWO}')
axis.grid()
axis.legend()
root = tk.Tk()
Label(root, text = "x =" ).grid(row = 0, column = 0)
Label(root, text = "y =" ).grid(row = 1, column = 0)
x = DoubleVar()
y = DoubleVar()
x_entry = Entry(root, textvariable = x).grid(row = 0, column = 1)
y_entry = Entry(root, textvariable = y).grid(row = 1, column = 1)
def plotgraphs():
if (len(axis.lines)) == 3: # Count existing plotted lines and delete if already existing
del (axis.lines[2])
axis.plot(x.get(), y.get(), "ko", label = 'Input point')
else:
axis.plot(x.get(), y.get(), "ko", label = 'Input point')
axis.legend()
canvas = FigureCanvasTkAgg(fig, master = root)
canvas._tkcanvas.grid(row = 2, column = 1)
Button(root, text = "New Graphs", command = plotgraphs).grid(row = 0, column = 2)
canvas = FigureCanvasTkAgg(fig, master = root)
canvas._tkcanvas.grid(row = 2, column = 1)
root.mainloop()

tkinter, Image does not show up unless some function added

I have written a code for a basic game but the image and shape don't show up unless I add something like item.pack() or win.mainloop() [which doesn't really make sense] but then the lines below it don't run.
When I don't have anything, the buttons show up but the image doesn't show up.
import tkinter as tk
import random
from tkinter import messagebox
win = tk.Tk()
my_label = tk.Label(win, text="Color of the Baloon Game")
my_label.pack()
my_canvas = tk.Canvas(win, width=400, height=600)
my_canvas.pack()
background_image=tk.PhotoImage(file = "CS_Game_menu.png")
background_label = tk.Label(my_canvas, image=background_image)
background_label.photo = background_image
background_label.grid(row = 0, rowspan = 10, column = 0, columnspan = 10)
def drawCircle():
color = "green"
x1 = 265
y1 = 80
diameter = 90
my_canvas.destroy()
circle_button.destroy()
quit_button.destroy()
my_label.destroy()
my_label1 = tk.Label(win, text="What is the Color of the Baloon?", font="Purisa")
my_label1.pack()
my_canvas1 = tk.Canvas(win, width=400, height=600)
my_canvas1.pack()
image1 = r"CS_Game_baloon.png"
photo1 = tk.PhotoImage(file=image1)
item = my_canvas1.create_image(200, 350, image=photo1)
shape = my_canvas1.create_oval(x1, y1, x1 + diameter, y1 + diameter+20, fill=color)
item.pack()
game1_button = tk.Button(my_canvas1, text = "Green")
game1_button.grid(row= 8, column = 3)
game1_button["command"] = lambda: messagebox.showinfo("Congratulations!", "Correct Answer!")
game2_button = tk.Button(my_canvas1, text = "Blue")
game2_button.grid(row= 8, column = 5)
game2_button["command"] = lambda: messagebox.showinfo("Sorry!", "Incorrect Answer!")
game3_button = tk.Button(my_canvas1, text = "Red")
game3_button.grid(row= 8, column = 7)
game3_button["command"] = lambda: messagebox.showinfo("Sorry", "Incorrect Answer!")
circle_button = tk.Button(win, text="New Game")
circle_button.pack()
circle_button["command"] = drawCircle
quit_button = tk.Button(win, text="Quit")
quit_button.pack()
quit_button['command'] = win.destroy
You are using both the create_... methods and grid methods on your canvas object. It won't behave as you expected.
To achieve what you want, you can create a Frame, put your buttons in it, and then use create_window method on your canvas:
def drawCircle():
...
shape = my_canvas1.create_oval(x1, y1, x1 + diameter, y1 + diameter+20, fill=color)
frame = tk.Frame(my_canvas1)
game1_button = tk.Button(frame, text = "Green")
game1_button.grid(row= 8, column = 3)
game1_button["command"] = lambda: messagebox.showinfo("Congratulations!", "Correct Answer!")
game2_button = tk.Button(frame, text = "Blue")
game2_button.grid(row= 8, column = 5)
game2_button["command"] = lambda: messagebox.showinfo("Sorry!", "Incorrect Answer!")
game3_button = tk.Button(frame, text = "Red")
game3_button.grid(row= 8, column = 7)
game3_button["command"] = lambda: messagebox.showinfo("Sorry", "Incorrect Answer!")
my_canvas1.create_window(200,500,window=frame)
And of course, add win.mainloop() to the bottom of your program if you haven't already.

My Matplotlib graph displays as expected but stops the script until I close it, then the script continues

I wrote a script for the Collatz Conjecture within a Tkinter GUI and displaying a Matplotlib graph of the result of the algorithm. Everything works OK except, the graph displays perfectly but then stops the script without populating the data field which displays the data points on which the graph is based. Only when I close the graph does is the data field populated.
I'm sure I'm doing something wrong in the script (probably indents) but I've tried everything but can't make it work. The script is added below:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from tkinter import *
from tkinter import messagebox
root=Tk()
root.title("Collatz Conjecture")
import matplotlib.pyplot as plt
import textwrap
from IPython import get_ipython
# sget_ipython().run_line_magic('matplotlib', 'qt')
#import matplotlib.backends.tkagg as tkagg
#from matplotlib.backends.backend_agg import FigureCanvasAgg
# Functions
lst = []
def collatz(num):
lst.clear()
while num != 1:
lst.append(num)
if num % 2 == 0:
num = int(num / 2)
else:
num = int(3 * num + 1)
def main(event):
num = int(input.get())
collatz(num)
plt.plot(lst)
plt.show()
output1.delete(1.0, END)
output1.insert(END, lst)
output2.delete(1.0, END)
output2.insert(END, "Number of iterations: " + str(len(lst)))
lbl1 = Label(root, width = 20, text = "Type in number\n & press Enter")
lbl1.grid(row = 1, column = 0, sticky = W)
lbl2 = Label(root, width = 40, text = "THE COLLATZ CONJECTURE")
lbl2.grid(row = 4, column = 0)
input = Entry(root, width = 20, bg = "light grey")
input.grid(row = 1, padx = 6, sticky = E)
input.get()
input.bind("<Return>", main)
canv = Canvas(root, width= 350, height= 350, bg = "white")
canv.grid(row = 6, column = 0, padx = (5,5), pady = (5,5))
img = PhotoImage(file = "/Users/andrehuman/Desktop/collatz_conjecture.png") # Tip to get full path: pull file into terminal!
canv.create_image(25, 25, image = img, anchor = NW)
bt1 = Button(root, width = 10, text = "About")
bt1.grid(row = 7, column = 0, pady = (5,7))
output1 = Text(root, wrap = WORD, width = 50, height = 7, bg = "light grey") # Note word wrap attribute
output1.grid(row = 3, column = 0, padx = (5,1), sticky = W)
output2 = Text(root, width = 50, height = 1, bg = "white")
output2.grid(row = 2, column = 0, sticky = W)
def about():
messagebox.showinfo("About", "The Collatz conjecture states that if you pick any positive whole number, and if its even, you divide it by two and if its odd, you multiply it by three and add one, and if you repeat this procedure often enough, the number that you started with will eventually reduce to one and if you play this game for long enough, your friends will eventually stop calling to see if you want to hang out ")
btn1 = Button(root, text = "About", command = about)
btn1.grid(row = 7, column = 0, pady = (5,7))
root.mainloop()
Any help would be appreciated.
Andre
PS, I'm not a professional coder or student coder as such... I'm doing this as a hobby and to inform myself about coding.

How to display output of print() in GUI python

I am new in creating GUI. I am doing it in Python with Tkinter. In my program I calculate following characteristics
def my_myfunction():
my code ...
print("Centroid:", centroid_x, centroid_y)
print("Area:", area)
print("Angle:", angle)
I would like to ask for any help/tips how to display those values in GUI window or how to save them in .txt file so that I can call them in my GUI
Thanks in advance
Tkinter is easy and an easy way to do a GUI, but sometimes it can be frustrating. But you should have read the docs before.
However, you can do in this way.
from tkinter import *
yourData = "My text here"
root = Tk()
frame = Frame(root, width=100, height=100)
frame.pack()
lab = Label(frame,text=yourData)
lab.pack()
root.mainloop()
There are several ways to display the results of any operation in tkiner.
You can use Label, Entry, Text, or even pop up messages boxes. There are some other options but these will probably be what you are looking for.
Take a look at the below example.
I have a simple adding program that will take 2 numbers and add them together. It will display the results in each kind of field you can use as an output in tkinter.
import tkinter as tk
from tkinter import messagebox
class App(tk.Frame):
def __init__(self, master):
self.master = master
lbl1 = tk.Label(self.master, text = "Enter 2 numbers to be added \ntogether and click submit")
lbl1.grid(row = 0, column = 0, columnspan = 3)
self.entry1 = tk.Entry(self.master, width = 5)
self.entry1.grid(row = 1, column = 0)
self.lbl2 = tk.Label(self.master, text = "+")
self.lbl2.grid(row = 1, column = 1)
self.entry2 = tk.Entry(self.master, width = 5)
self.entry2.grid(row = 1, column = 2)
btn1 = tk.Button(self.master, text = "Submit", command = self.add_numbers)
btn1.grid(row = 2, column = 1)
self.lbl3 = tk.Label(self.master, text = "Sum = ")
self.lbl3.grid(row = 3, column = 1)
self.entry3 = tk.Entry(self.master, width = 10)
self.entry3.grid(row = 4, column = 1)
self.text1 = tk.Text(self.master, height = 1, width = 10)
self.text1.grid(row = 5, column = 1)
def add_numbers(self):
x = self.entry1.get()
y = self.entry2.get()
if x != "" and y != "":
sumxy = int(x) + int(y)
self.lbl3.config(text = "Sum = {}".format(sumxy))
self.entry3.delete(0, "end")
self.entry3.insert(0, sumxy)
self.text1.delete(1.0, "end")
self.text1.insert(1.0, sumxy)
messagebox.showinfo("Sum of {} and {}".format(x,y),
"Sum of {} and {} = {}".format(x, y, sumxy))
if __name__ == "__main__":
root = tk.Tk()
myapp = App(root)
root.mainloop()

Tkinter: scrollable Frame in Canvas: Auto-resize binding error

This script when run, opens a window that is divided into 3 frames:
A big frame into which data will be shown (label widgets).
A smaller frame underneath it with user input widgets.
A small frame in the bottom-right corner with a textbox widget.
The big frame will have a lot of data (= label-widgets) so I need it to be scrollable (vertically).
This I have done by creating a canvas widget alonside a scrollbar widget. In the canvas, a frame widget is placed.
Everything seems to be working, however my resizing function does not.
My frame widget does not get its dimensions updated! This is probably because of an error that I can't manage to fix.
Fundamental question:
The script gives an error on the "lambda: resize_frame(self)" command on line 43. How do i fix this?
Side-note: My issue probably has more to do with an improper binding on the canvas widget. Because I'm not sure I wanted to give enough context (script).
Many thanks in advance.
from Tkinter import *
import math
class Processing(Toplevel):
def __init__(self, master, *args, **kwargs):
Toplevel.__init__(self, master)
self.master = master
self.title("Process Window")
for r in range(6):
self.rowconfigure(r, weight = 1)
for c in range(4):
self.columnconfigure(c, weight = 1)
### WINDOW size and position definitions ###
ScreenSizeX = master.winfo_screenwidth()
ScreenSizeY = ( master.winfo_screenheight() - 75 ) #about 75pixels for taskbar on bottom of screen (Windows)
ScreenRatio = 0.9
FrameSizeX = int(ScreenSizeX * ScreenRatio)
FrameSizeY = int(ScreenSizeY * ScreenRatio)
FramePosX = (ScreenSizeX - FrameSizeX)/2
FramePosY = (ScreenSizeY - FrameSizeY)/2
self.geometry("%sx%s+%s+%s"%(FrameSizeX,FrameSizeY,FramePosX,FramePosY))
### Creating 3 "sub-frames" ###
# Frame 1 - canvas container with scrollbar#
self.Canvas1 = Canvas(self, bg = "white")
self.Canvas1.grid(row = 0, column = 0, rowspan = 5, columnspan = 4, sticky = N+E+S+W)
self.Canvas1.rowconfigure(1, weight = 1)
self.Canvas1.columnconfigure(1, weight = 1)
self.myscrollbar=Scrollbar(self, orient = "vertical", command = self.Canvas1.yview)
self.Canvas1.configure(yscrollcommand = self.myscrollbar.set)
self.myscrollbar.grid(row = 0, column = 4, rowspan = 5, sticky = N+S)
# Frame 1 - Frame widget in canvas #
self.Frame1 = Frame(self.Canvas1, bg = "white")
self.Frame1.rowconfigure(0, weight = 1)
for c in range(2):
self.Frame1.columnconfigure(1 + (2 * c), weight = 1)#1,3 - columns for small icons in the future
for cb in range(3):
self.Frame1.columnconfigure((cb * 2), weight = 9)#0,2,4 - columns for data
self.CFrame1 = self.Canvas1.create_window(0, 0, window = self.Frame1, width = FrameSizeX, anchor = N+W)
self.Canvas1.bind("<Configure>", lambda: resize_frame(self)) # !!!!! Doesn't work & gives error !!!!!! #
self.Frame1.bind("<Configure>", lambda: scrollevent(self))
self.Canvas1.config(scrollregion=self.Canvas1.bbox("all"))
# Frame 2 #
self.Frame2 = Frame(self, bg= "yellow")
self.Frame2.grid(row = 5, column = 0, rowspan = 1, columnspan = 3, sticky = W+E+N+S)
for r in range(3):
self.Frame2.rowconfigure(r, weight=1)
for c in range(3):
self.Frame2.columnconfigure(c, weight = 1)
# Frame 3 #
self.Frame3 = Frame(self)
self.Frame3.grid(row = 5, column = 3, rowspan = 1, columnspan = 2, sticky = W+E+N+S)
self.Frame3.rowconfigure(0, weight = 1)
self.Frame3.columnconfigure(0, weight = 1)
# Propagation #
#self.grid_propagate(False) # All widgets (the 3 subframes) need to fit in Toplevel window. Minimal window size will be implemented later.
self.Canvas1.grid_propagate(False) # canvas works with scrollbar, widgets dont need to fit in window size.
#self.Frame1.grid_propagate(False) # Frame1 should resize to hold all data (label-widgets)
self.Frame2.grid_propagate(False) # fixed frame dimensions
self.Frame3.grid_propagate(False) # fixed textbox dimensions
self.Frame1.update_idletasks() # just to make sure
### Widgets for the multiple frames ###
# Frame1 - further populated by button command in frame 2#
self.lblaa = Label(self.Frame1, bg="white", text = "Processing...", justify = "left")
self.lblaa.grid(row = 0, column = 0, sticky = N+W)
self.LSlabelsr = []
self.LSlabelsa = []
self.LSlabelsb = []
# Frame 2 #
self.Wbuttontest=Button(self.Frame2, text="Start listing test", command = lambda: refresh(self))
self.Wbuttontest.grid(row = 0, column = 0, columnspan = 3)
self.Wentry = Entry(self.Frame2)
self.Wentry.grid(row = 2, column = 0, columnspan = 3, sticky = E+W, padx = 10)
self.Wentry.delete(0, END)
self.Wentry.insert(0, "user input here")
# Frame3 #
self.Wtext = Text(self.Frame3)
self.Wscrollb = Scrollbar(self.Frame3)
self.Wscrollb.config(command = self.Wtext.yview)
self.Wtext.config(yscrollcommand = self.Wscrollb.set)
self.Wtext.grid(row = 0, column = 0, sticky = N+E+W+S)
### Test-Lists ### Last character in the left column is "ez" !! ###
self.LSa = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
self.LSb = [1, 2, 3, 4, 66, 6, 7, 8, 9, 67, 11, 12, 13, 14, 68]
self.LSr = []
ib = 0
prefix = ""
for i in range(104):
if ib > 25:
prefix = chr(ord("a") + (i/ib - 1))
ib = 0
else:
pass
self.LSr.append(prefix + chr(97+ib))
ib += 1
### FUNCTIONS ###
def resize_frame(self, event):
self.Canvas1.itemconfig(self.CFrame1, width = e.width) #height of frame should depend on the contents.
def scrollevent(event):
self.Canvas1.configure(scrollregion=self.Canvas1.bbox("all"),width=200,height=200)
def refresh(self): ### Button-command: data will be shown ###
if self.lblaa.winfo_exists() == 1:
self.lblaa.destroy()
for i in range(len(self.LSr)):
self.Frame1.rowconfigure(i, weight = 0)
del self.LSlabelsr[:] # remove any previous labels from if the callback was called before
del self.LSlabelsa[:] # remove any previous labels from if the callback was called before
del self.LSlabelsb[:] # remove any previous labels from if the callback was called before
Vlabelheight = 1
# Left List #
for i in range(len(self.LSr)):
self.LSlabelsr.append(Label(self.Frame1, text = str(self.LSr[i]), bg = "LightBlue", justify = "left", height = Vlabelheight))
self.LSlabelsr[i].grid(row = i, column = 0, sticky = E+W)
# Middle List #
for i in range(len(self.LSa)):
self.LSlabelsa.append(Label(self.Frame1, text = str(self.LSa[i]), bg = "LightBlue", fg = "DarkViolet", justify = "left", height = Vlabelheight))
self.LSlabelsa[i].grid(row = i, column = 2, sticky = E+W)
# Right List #
for i in range(len(self.LSb)):
self.LSlabelsb.append(Label(self.Frame1, text = str(self.LSb[i]), bg = "LightBlue", fg = "DarkGreen", justify = "left", height = Vlabelheight))
self.LSlabelsb[i].grid(row = i, column = 4, sticky = E+W)
self.Frame1.update()
self.Frame1.update_idletasks()
print("done")
if __name__ == "__main__":
root = Tk()
root.title("Invisible")
root.resizable(FALSE,FALSE)
root.withdraw()
app = Processing(root)
root.mainloop()
Working version after suggestions by R4PH4EL:
Proper indentation: the functions were defined as part of the init.
Some tweaks on the lambda commands on line 43/107 & 44/110.
from Tkinter import *
import math
class Processing(Toplevel):
def __init__(self, master, *args, **kwargs):
Toplevel.__init__(self, master)
self.master = master
self.title("Process Window")
for r in range(6):
self.rowconfigure(r, weight = 1)
for c in range(4):
self.columnconfigure(c, weight = 1)
### WINDOW size and position definitions ###
ScreenSizeX = master.winfo_screenwidth()
ScreenSizeY = ( master.winfo_screenheight() - 75 ) #about 75pixels for taskbar on bottom of screen (Windows)
ScreenRatio = 0.9
FrameSizeX = int(ScreenSizeX * ScreenRatio)
FrameSizeY = int(ScreenSizeY * ScreenRatio)
FramePosX = (ScreenSizeX - FrameSizeX)/2
FramePosY = (ScreenSizeY - FrameSizeY)/2
self.geometry("%sx%s+%s+%s"%(FrameSizeX,FrameSizeY,FramePosX,FramePosY))
### Creating 3 "sub-frames" ###
# Frame 1 - canvas container with scrollbar#
self.Canvas1 = Canvas(self, bg = "white")
self.Canvas1.grid(row = 0, column = 0, rowspan = 5, columnspan = 4, sticky = N+E+S+W)
self.Canvas1.rowconfigure(1, weight = 1)
self.Canvas1.columnconfigure(1, weight = 1)
self.myscrollbar=Scrollbar(self, orient = "vertical", command = self.Canvas1.yview)
self.Canvas1.configure(yscrollcommand = self.myscrollbar.set)
self.myscrollbar.grid(row = 0, column = 4, rowspan = 5, sticky = N+S)
# Frame 1 - Frame widget in canvas #
self.Frame1 = Frame(self.Canvas1, bg = "white")
self.Frame1.rowconfigure(0, weight = 1)
for c in range(2):
self.Frame1.columnconfigure(1 + (2 * c), weight = 1)#1,3 - columns for small icons in the future
for cb in range(3):
self.Frame1.columnconfigure((cb * 2), weight = 9)#0,2,4 - columns for data
self.CFrame1 = self.Canvas1.create_window(0, 0, window = self.Frame1, width = FrameSizeX, anchor = N+W)
self.Canvas1.bind("<Configure>", lambda event: self.resize_frame(event)) # !!!!! Doesn't work & gives error !!!!!! #
self.Frame1.bind("<Configure>", lambda event: self.scrollevent(event))
self.Canvas1.config(scrollregion=self.Canvas1.bbox("all"))
# Frame 2 #
self.Frame2 = Frame(self, bg= "yellow")
self.Frame2.grid(row = 5, column = 0, rowspan = 1, columnspan = 3, sticky = W+E+N+S)
for r in range(3):
self.Frame2.rowconfigure(r, weight=1)
for c in range(3):
self.Frame2.columnconfigure(c, weight = 1)
# Frame 3 #
self.Frame3 = Frame(self)
self.Frame3.grid(row = 5, column = 3, rowspan = 1, columnspan = 2, sticky = W+E+N+S)
self.Frame3.rowconfigure(0, weight = 1)
self.Frame3.columnconfigure(0, weight = 1)
# Propagation #
#self.grid_propagate(False) # All widgets (the 3 subframes) need to fit in Toplevel window. Minimal window size will be implemented later.
self.Canvas1.grid_propagate(False) # canvas works with scrollbar, widgets dont need to fit in window size.
#self.Frame1.grid_propagate(False) # Frame1 should resize to hold all data (label-widgets)
self.Frame2.grid_propagate(False) # fixed frame dimensions
self.Frame3.grid_propagate(False) # fixed textbox dimensions
self.Frame1.update_idletasks() # just to make sure
### Widgets for the multiple frames ###
# Frame1 - further populated by button command in frame 2#
self.lblaa = Label(self.Frame1, bg="white", text = "Processing...", justify = "left")
self.lblaa.grid(row = 0, column = 0, sticky = N+W)
self.LSlabelsr = []
self.LSlabelsa = []
self.LSlabelsb = []
# Frame 2 #
self.Wbuttontest=Button(self.Frame2, text="Start listing test", command = lambda: self.refresh())
self.Wbuttontest.grid(row = 0, column = 0, columnspan = 3)
self.Wentry = Entry(self.Frame2)
self.Wentry.grid(row = 2, column = 0, columnspan = 3, sticky = E+W, padx = 10)
self.Wentry.delete(0, END)
self.Wentry.insert(0, "user input here")
# Frame3 #
self.Wtext = Text(self.Frame3)
self.Wscrollb = Scrollbar(self.Frame3)
self.Wscrollb.config(command = self.Wtext.yview)
self.Wtext.config(yscrollcommand = self.Wscrollb.set)
self.Wtext.grid(row = 0, column = 0, sticky = N+E+W+S)
### Test-Lists ### Last character in the left column is "ez" !! ###
self.LSa = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
self.LSb = [1, 2, 3, 4, 66, 6, 7, 8, 9, 67, 11, 12, 13, 14, 68]
self.LSr = []
ib = 0
prefix = ""
for i in range(104):
if ib > 25:
prefix = chr(ord("a") + (i/ib - 1))
ib = 0
else:
pass
self.LSr.append(prefix + chr(97+ib))
ib += 1
### FUNCTIONS ###
def resize_frame(self, e):
self.Canvas1.itemconfig(self.CFrame1, width = e.width) #height of frame should depend on the contents.
def scrollevent(self, event):
self.Canvas1.configure(scrollregion=self.Canvas1.bbox("all"),width=200,height=200)
def refresh(self): ### Button-command: data will be shown ###
if self.lblaa.winfo_exists() == 1:
self.lblaa.destroy()
for i in range(len(self.LSr)):
self.Frame1.rowconfigure(i, weight = 0)
del self.LSlabelsr[:] # remove any previous labels from if the callback was called before
del self.LSlabelsa[:] # remove any previous labels from if the callback was called before
del self.LSlabelsb[:] # remove any previous labels from if the callback was called before
Vlabelheight = 1
# Left List #
for i in range(len(self.LSr)):
self.LSlabelsr.append(Label(self.Frame1, text = str(self.LSr[i]), bg = "LightBlue", justify = "left", height = Vlabelheight))
self.LSlabelsr[i].grid(row = i, column = 0, sticky = E+W)
# Middle List #
for i in range(len(self.LSa)):
self.LSlabelsa.append(Label(self.Frame1, text = str(self.LSa[i]), bg = "LightBlue", fg = "DarkViolet", justify = "left", height = Vlabelheight))
self.LSlabelsa[i].grid(row = i, column = 2, sticky = E+W)
# Right List #
for i in range(len(self.LSb)):
self.LSlabelsb.append(Label(self.Frame1, text = str(self.LSb[i]), bg = "LightBlue", fg = "DarkGreen", justify = "left", height = Vlabelheight))
self.LSlabelsb[i].grid(row = i, column = 4, sticky = E+W)
self.Frame1.update()
self.Frame1.update_idletasks()
print("done")
if __name__ == "__main__":
root = Tk()
root.title("Invisible")
root.resizable(FALSE,FALSE)
root.withdraw()
app = Processing(root)
root.mainloop()
Either your indentation is wrong or your getting something wrong in general.
All of your functions are defined inside your __init__ function
Second: if you want to call a class function, you call it by obj.function
Your error on lambda: resize(self) may occur as it should be lambda: self.resize.
Give it a shot with this one and try it.
And please make sure your indentations are correct.
I totally agree with Bryan here - ommiting the lambdas it would be (my personal opinion) easier to read and kind of "better" in a meaning of more structured and pragmatic coding style.

Categories