Issues clearing tkinter canvas - python-3.x

I wrote a program to draw some plots. I want to clear the screen and reuse the same canvas to draw different plot. How should i go about it? ocanvas is my outer canvas to which i'm attaching a scrollbar. innerCanvas is the canvas I do my drawing on. The first time I press "Go" I call the function drawGraph. I want the innerCanvas to be cleared the next time I press "Go" and then call drawGraph2. Is there a way to accomplish this?. Below is my code:
(I'm a beginner in Python and thus I don't know all the concepts/functions present.)
from tkinter import *
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
def on_configure(event=None):
canvas.configure(scrollregion=canvas.bbox("all"))
def drawGraph(innerCanvas):
for i in range(5):
f = Figure(figsize=(5,5), dpi=100)
a = f.add_subplot(111)
a.plot([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],[5,6,1,3,8,9,3,5,9,7,6,5,7,3,2,9,3,5])
canvas = FigureCanvasTkAgg(f, innerCanvas)
canvas.draw()
canvas.get_tk_widget().pack(side=LEFT, fill=BOTH, expand=True)
def drawGraph2(innerCanvas):
for i in range(5):
f = Figure(figsize=(5,5), dpi=100)
a = f.add_subplot(111)
a.plot([1,2,3,4,5,6,7,8,9,10,11,12,13,14],[3,4,5,6,8,9,0,1,23,44,4,5,17,5])
canvas = FigureCanvasTkAgg(f, innerCanvas)
canvas.draw()
canvas.get_tk_widget().pack(side=LEFT, fill=BOTH, expand=True)
root=Tk()
ocanvas=Canvas(root)
innerCanvas=Canvas(canvas)
xscrollbar=Scrollbar(ocanvas, orient=HORIZONTAL)
xscrollbar.config(command=ocanvas.xview)
button=Button(root, text='Go',command= lambda: drawGraph(frame))
button.pack()
ocanvas.configure(scrollregion=ocanvas.bbox("all"))
ocanvas.config(xscrollcommand=xscrollbar.set)
xscrollbar.pack(side=BOTTOM, fill=X)
ocanvas.bind("<Configure>", on_configure)
ocanvas.pack(fill=BOTH, expand=True)
ocanvas.create_window((0,0),window=innerCanvas, anchor='nw')
root.geometry('500x500')
root.mainloop()
Any help would be appreciated.

To clear innerCanvas You can destroy its children before calling drawGraph2.
for figureCanvas in innerCanvas.winfo_children():
figureCanvas.destroy()

Related

Customtkinter/Tkinter canvas objects jumping around

I am fairly new to tkinter and I've been working on this feature of my project that allows a user to drag and drop canvas objects around, however when I move around the canvas and try to move the canvas object again, it behaves weirdly. It's somewhat hard to explain so I left a video below for context and the code as well. Any kind of help is appreciated :)
import customtkinter
from tkinter import Canvas
from PIL import Image, ImageTk
def move(event):
my_canvas.moveto(my_image,event.x-50,event.y-50)
def scan(event):
my_canvas.scan_mark(event.x, event.y)
def drag(event):
my_canvas.scan_dragto(event.x, event.y, gain=2)
def display_coords(event):
my_label.configure(text=f"X: {event.x} Y:{event.y}")
app = customtkinter.CTk()
frame1 = customtkinter.CTkFrame(master=app)
frame1.pack(padx=10,pady=10, expand=True, fill="both")
my_canvas = Canvas(master=frame1, height=100, width=100, bg="black")
my_canvas.pack(expand=True, fill="both")
#Resize image(originally 512 x 512)
img = Image.open("assets/computadora.png")
resized_image = img.resize((100,100))
image = ImageTk.PhotoImage(resized_image)
frame1.image = image
my_image = my_canvas.create_image(0, 0, image=image, anchor="nw")
my_canvas.tag_bind(my_image,"<Button1-Motion>", move, add="+")
my_canvas.bind("<Button-3>", scan)
my_canvas.bind("<Button3-Motion>", drag)
#Provides X-Y coordinates of mouse cursor when canvas object is selected
my_label = customtkinter.CTkLabel(master=my_canvas, text="X: None Y: None")
my_label.pack(padx="10px", pady="10px", anchor="se")
my_canvas.tag_bind(my_image, "<Button1-Motion>", display_coords, add="+")
my_canvas.configure(scrollregion=my_canvas.bbox(my_image))
app.mainloop()
here

How can I fix my button positions on python tkinter?

I want to fix the position of my two buttons like if I resize my window the buttons will remain in their positions. Or My buttons dynamically resize with the window size. I have positioned my buttons using place. But I ain't getting success. Here's the code so far.
import turtle
import tkinter as tk
##wn=turtle.Screen()
wn=tk.Tk()
image=tk.PhotoImage(file="MS-3.PNG")
wn.geometry("700x700")
label1=tk.Label(wn,image=image)
label1.pack(side="top",fill="both",expand="yes")
label1.grid_rowconfigure(0, weight=1)
label1.grid_columnconfigure(0, weight=1)
label1.grid_rowconfigure(1, weight=1)
def callback1():
import Detection1
def callback():
import detection
button1=tk.Button(label1,text="Health Identification", command=callback, bd=12,bg="grey",font="caliber")
button1.place(x=100,y=500 )
label1.image=image
button2=tk.Button(label1,text="Disease Classification", command=callback1, bd=10,bg="grey",font="caliber")
button2.place(x=400, y=500 )
label1.image=image
wn.mainloop()
Sadia: If I understood your question correctly, you could make your windows non-resizable with wn.resizable(False, False). Then place your buttons exactly where you want them to be. If you are new to tkinter and python, making every object resizable might be a bit too complex to begin with.
Hopefully this helps.
import turtle
import tkinter as tk
from PIL import Image, ImageTk
##wn=turtle.Screen()
wn = tk.Tk()
wn.geometry("700x700")
wn.resizable(False, False)
img = ImageTk.PhotoImage(Image.open("MS-3.PNG"))
label1 = tk.Label(wn, image=img)
label1.pack(side="top", fill="both", expand="yes")
# label1.grid_rowconfigure(0, weight=1)
# label1.grid_columnconfigure(0, weight=1)
# label1.grid_rowconfigure(1, weight=1)
def callback1():
import Detection1
def callback():
import detection
button1 = tk.Button(label1, text="Health Identification", command=callback, bd=12, bg="grey", font="caliber")
button1.place(x=100, y=500)
button2 = tk.Button(label1, text="Disease Classification", command=callback1, bd=10, bg="grey", font="caliber")
button2.place(x=400, y=500)
wn.mainloop()

Scrollbar doesn't scroll widgets inside a frame which is inside a canvas

I have the canvas and the scrollbar are on the Tk.
I have a frame on the canvas.
I adding into this frame new frames with the widgets on it and I want to scroll these widgets.
The scrollbar doesn't scroll the widgets at all, and when I add widgets which go below the window than the scrollbar turn into gray and I can't use it at all.
I am new to tkinter and python. I just don't know yet what am I doing. I didn't try to make it with a class(Should I?). I tried to use the ttk, and looked around sites for a non class answers but none of them worked.
from tkinter import *
from tkinter.ttk import *
actor_number=0
global tk
def new_actor_button_command():
global menu_frame
global actor_number
global canvas
new_actor_frame=Frame(menu_frame,width=500,height=200)
new_actor_frame.grid(row=1+actor_number,column=0,pady=20)
actor_name_label=Label(new_actor_frame,text="Actor Name")
new_actor_frame.place(relx=0.0, rely=0.0, anchor=CENTER)
delete_actor_button=Button(new_actor_frame,text="Delete
Actor",command=delete_actor_button_command)
new_actor_frame.grid(row=1+actor_number,column=1)
actor_name_label.grid(row=2+actor_number,column=1)
delete_actor_button.grid(row=2+actor_number,column=2)
actor_number+=1
canvas.update_idletasks()
scrollbar.config(command=canvas.yview)
canvas.configure(scrollregion=canvas.bbox("all"))
def make_new_actor():
global canvas
global menu_frame
new_actor_button=Button(menu_frame,text="Add New
Actor",command=new_actor_button_command)
new_actor_button.grid(row=0,column=0)
def new_command():
global actor_number
actor_number=0
make_new_actor()
tk=Tk()
tk.geometry("1200x800")
menubar=Menu(tk)
filemenu=Menu(menubar,tearoff=0)
filemenu.config(font=("Verdana",16))
filemenu.add_command(label="New",font=("Verdana",16),command=new_command)
menubar.add_cascade(label="File", menu=filemenu)
global scrollbar
canvas=Canvas(tk,width=1000,height=1000)
scrollbar=Scrollbar(tk,orient="vertical",command = canvas.yview)
menu_frame=Frame(canvas,width=1000,height=1000)
canvas.create_window(0,0,window=menu_frame)
canvas.configure(yscrollcommand=scrollbar.set)
canvas.configure(scrollregion=canvas.bbox("all"))
canvas.place(relx=0.0, rely=0.0)
menu_frame.pack(side=LEFT,expand=True)
scrollbar.pack(side=RIGHT,fill=Y)
tk.config(menu=menubar)
tk.mainloop()
It should scroll the vidgets inside"menu_frame".
Scrolling Canvas is not easy.
It scroll items (if you add enough items in menu_frame) but it may need other changes in new_actor_frame
from tkinter import *
from tkinter.ttk import *
def new_actor_button_command():
new_actor_frame = Frame(menu_frame, width=500, height=200)
new_actor_frame.grid(row=actor_number, column=0)
actor_name_label = Label(new_actor_frame, text="Actor Name")
actor_name_label.grid(row=0, column=1)
delete_actor_button=Button(new_actor_frame,text="Delete Actor")#, command=delete_actor_button_command)
delete_actor_button.grid(row=0, column=2)
def new_command():
global actor_number
actor_number += 1
new_actor_button = Button(menu_frame, text="Add New Actor", command=new_actor_button_command)
new_actor_button.grid(row=actor_number, column=0)
def update_canvas(event=None):
canvas.configure(scrollregion=canvas.bbox("all"))
actor_number=0
tk = Tk()
tk.geometry("1200x800")
menubar = Menu(tk)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="New", command=new_command)
menubar.add_cascade(label="File", menu=filemenu)
tk.config(menu=menubar)
canvas = Canvas(tk, background='white')#, width=1000, height=1000)
canvas.pack(side='left', fill='both', expand=True)
scrollbar = Scrollbar(tk, orient="vertical", command=canvas.yview)
scrollbar.pack(side='right', fill='y')
menu_frame = Frame(canvas)
canvas.create_window(0, 0, window=menu_frame, anchor='nw')
canvas.configure(yscrollcommand=scrollbar.set)
canvas.bind('<Configure>', update_canvas) # update when change size
tk.mainloop()

Adding padding query insert to Listbox

I have read a number of threads and other resources to try to find the correct way to handle this but I have not found anything that works with my application.
Here is what I am trying to accomplish.
When a query is completed and the insert of the data to a Listbox is done I cannot seem to get it to margin the data insert by 1 character space.
I am using pack() and I have read the tkinter manual for this and have tried each example available along with others found on various threads here.
The widget:
output = tkinter.Listbox(window_2, height = 20, font='Times 10',
width=42, bd=1, bg = '#FFD599', fg = '#9A0615', selectmode=SINGLE)
output.pack()
output.place(x=210, y=195)
I have tried padx and pady with pack() without success, although this works successfully with the Text widget. I have also attempted to use a few alternatives that I have found here on the site but all without success in margining the Listbox when the data is inserted.
Any advice?
pack's padx/pady and ipadx/ipady options don't affect the data that is inside the listbox. The listbox itself doesn't have any options to add an internal margin.
To get a margin around the inside of the listbox, what I normally do is give it a zero borderwidth and highlightthickness, and then place it in a frame with the same background color and let the frame be the border. You can then add any padding you want between the border and the listbox.
This is also convenient because you can put a scrollbar inside the frame, giving it the appearance that it is inside the listbox without actually being inside the listbox.
Example:
import tkinter as tk
root = tk.Tk()
root.configure(background="gray")
listbox_border = tk.Frame(root, bd=1, relief="sunken", background="white")
listbox_border.pack(padx=10, pady=10, fill=None, expand=False)
listbox = tk.Listbox(listbox_border, width=20, height=10,
borderwidth=0, highlightthickness=0,
background=listbox_border.cget("background"),
)
vsb = tk.Scrollbar(listbox_border, orient="vertical", command=listbox.yview)
listbox.configure(yscrollcommand=vsb)
vsb.pack(side="right", fill="y")
listbox.pack(padx=10, pady=10, fill="both", expand=True)
for i in range(100):
listbox.insert("end", "Item #{}".format(i))
root.mainloop()
here is a variation on the much appreciated answer by Bryan Oakley.
it uses ttk widgets instead of tk widgets
the scrollbar tracks your position in the list box when you scroll with the mouse
uses the oStyle.theme_use("clam") because it may look more modern...this can be commented out
'
import tkinter as tk
from tkinter import ttk
try: # allows the text to be more crisp on a high dpi display
from ctypes import windll
windll.shcore.SetProcessDpiAwareness(1)
except:
pass
root = tk.Tk()
oStyle = ttk.Style()
oStyle.theme_use("clam")
oStyle.configure('LB.TFrame', bd=1, relief="sunken", background="white")
listbox_border = ttk.Frame(root, style='LB.TFrame')
listbox_border.pack(padx=4, pady=4, fill=None, expand=False)
vsb = ttk.Scrollbar(listbox_border)
vsb.pack(side="right", fill="y")
listbox = tk.Listbox(listbox_border, width=20, height=10, borderwidth=0,
highlightthickness=0, selectmode=tk.SINGLE,
activestyle=tk.NONE)
listbox.pack(padx=6, pady=6, fill="y", expand=True)
listbox.config(yscrollcommand=vsb.set)
vsb.config(command=listbox.yview)
for i in range(100):
listbox.insert("end", "Item #{}".format(i))
root.mainloop()
'
first of all to format chars in a tkinter listbox you need to use a fixed font and .format python funcion....;
So you can do something this
Press Load to load data in the listbox and pay attention to this line code
s = '{0:>8}{1:5}'.format(i[0],i[1])
self.list.insert(tk.END, s)
import tkinter as tk
RS = (('Apple',10),
('Banana',20),
('Peack',8),
('Lemon',6),)
class App(tk.Frame):
def __init__(self,):
super().__init__()
self.master.title("Hello World")
self.init_ui()
def init_ui(self):
self.pack(fill=tk.BOTH, expand=1,)
f = tk.Frame()
sb = tk.Scrollbar(f,orient=tk.VERTICAL)
self.list = tk.Listbox(f,
relief=tk.GROOVE,
selectmode=tk.BROWSE,
exportselection=0,
background = 'white',
font='TkFixedFont',
yscrollcommand=sb.set,)
sb.config(command=self.list.yview)
self.list.pack(side=tk.LEFT,fill=tk.BOTH, expand =1)
sb.pack(fill=tk.Y, expand=1)
w = tk.Frame()
tk.Button(w, text="Load", command=self.on_callback).pack()
tk.Button(w, text="Close", command=self.on_close).pack()
f.pack(side=tk.LEFT, fill=tk.BOTH, expand=0)
w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=0)
def on_callback(self,):
for i in RS:
s = '{0:>8}{1:5}'.format(i[0],i[1])
self.list.insert(tk.END, s)
def on_close(self):
self.master.destroy()
if __name__ == '__main__':
app = App()
app.mainloop()

python expression to latex

I'm trying to display equations by using GUI. I use latex and canvas. However, I'm getting an error message ValueError: KeyPress event keysym=Return keycode=36 char='\r' x=266 y=8
it should be working because I have already converted python expressions into Latex's.
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib
import matplotlib.pyplot as plt
from tkinter import *
from sympy import *
matplotlib.use('TkAgg')
root=Tk()
frame=Frame(root)
frame.pack()
frame1= Frame()
frame1.pack()
caracter=StringVar()
def result(caracter):
a = str(caracter)
text1=latex(a)
ax.clear()
ax.text(0.2, 0.6, "$"+text1+"$", fontsize = 6)
canvas.draw()
def element(num):
caracter.set(caracter.get()+num)
#-----------------------------SCREEN------------
screen=Entry(frame, width=50, textvariable=caracter)
screen.pack()
screen.grid(row=1, column=1, pady=10, columnspan=5)
#-----------------------BUTTONS-----------------------
go=Button(frame, height=1, text="Go")
go.grid(row=1, column=6)
Buttonx=Button(frame, text="x", width=5, padx=0, pady=2, command=lambda:element("x"))
Buttonx.grid(row=2, column=6)
#--------CANVAS ---------------
label = Label(frame1)
label.pack()
fig = matplotlib.figure.Figure(figsize=(5, 4), dpi=100)
ax = fig.add_subplot(111)
canvas = FigureCanvasTkAgg(fig, master=label)
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
root.bind('<Return>', result)
root.mainloop()
This is the shortest code to reproduce the issue. Any help or hint will be appreciated. Thank you very much in advance
You are passing the char associated with <RETURN> to your function result. Because the parameter is named caracter, this shadows the variable caracter declared earlier as a tk.StringVar.
something like this should give you the expected result:
def result(dummy_c):
a = caracter.get()
text1 = latex(a)
ax.clear()
ax.text(0.2, 0.6, "$"+text1+"$", fontsize = 6)
canvas.draw()

Resources