So I am making an Tkinter painting application but I keep getting a Value:Error which is blocking me from proceeding and I don't know how to solve it.
here is my code
from tkinter import *
from tkinter import Scale
from tkinter import colorchooser, filedialog, messagebox
import PIL.ImageGrab as ImageGrab
class Paint(): # the class adds the screen for all the widgets to be added on
def __init__(self,root):
global color
self.root = root
self.root.title("Paint")
self.root.geometry("800x520")
self.root.configure(background='white')
self.root.resizable(100,100)
self.pen_color ="black"
self.eraser_color = "white"
# Adding the widgets
self.color_frame = LabelFrame(self.root, text='Color Palette', font=("Lucida's Caligraphy",15),bd=10, relief=RIDGE, bg='pink')
self.color_frame.place(x=0,y=0,width=145,height=190)
colors = ["#ff00ff", "#ff0000", "#ffa600", "#ffff00", "#80ff80", "#00ff00", "#09ff90", "#0ff8c0", "#00d0ff", "#00ffff", "#ffffff", "#fff3d4", "#808080", "#404040", "#202020", "#000000"]
i=j=0
for color in colors: # this is the creation for the positioning of the colors
Button(self.color_frame,bg=color,bd=2,relief=RIDGE,width=3,command=lambda col=color:self.select_color(col)).grid(row=i,column=j) # this is the creation for the color buttons
i+=1
if i==4:
i=0
j+=1
self.eraser_button = Button(self.root,text='Eraser',bg='violet',bd=2,relief=GROOVE,width=3,command=self.eraser) # this is the creation for the eraser button
self.eraser_button.place(x=0, y=187, width=60, height=30)
self.clear_button = Button(self.root,text='Clear',bg='light blue',bd=2,relief=GROOVE,width=3,command=lambda : self.canvas.delete("all")) # this is the creation for the clear button
self.clear_button.place(x=0, y=217, width=60, height=30)
self.save_button = Button(self.root,text='Save',bg='light green',bd=2,relief=GROOVE,width=3,command=self.save_paint) # this is the creation for the save button
self.save_button.place(x=0, y=247, width=60, height=30)
self.canvas_button = Button(self.root,text="Canvas",bg='light cyan', bd=4, width=8,relief=GROOVE,command=self.canvas_color) # this is the creation for the canvas button
self.canvas_button.place(x=0, y=277)
self.pen_scale_frame = LabelFrame(self.root,text='size', bg='white', bd=5, font=('arial', 15), relief=RIDGE,) # this is the creation for the box that contains the colors
self.pen_scale_frame.place(x=0, y=310, width=70, height=200)
self.pen_scale = Scale(self.pen_scale_frame, orient=VERTICAL,from_=100, to=0,length=150) # this is the creation for the scale
self.pen_scale.set(1)
self.pen_scale.place(x=5,y=10)
self.canvas = Canvas(self.root, bg='light cyan', bd=4, relief=GROOVE, width=1105, height=630) # this is the creation for the canvas
self.canvas.place(x=150, y=0)
self.canvas.bind("<B1-Motion>",self.paint) # this binds the mouse motion with the canvas
def paint(self,event): # this is the function for the ink to be shown on the canvas
x1,y1 = (event.x-0),(event.y-0)
x2,y2 = (event.x+0), (event.y+0)
self.canvas.create_oval(x1,y1,x2,y2,fill=self.pen_color,outline=self.pen_color,width=self.pen_scale.get())
def select_color(self, col): # this is the function for selecting colors for my pen
self.pen_color = col
def eraser(self): # this is the function for copying the colors that my canvas has for my eraser
self.pen_color = self.eraser_color
def canvas_color(self): # this is the function for selecting colors for my canvas
color = colorchooser.askcolor()
self.canvas.configure(background=color[1])
self.eraser_color = color[1]
self.pen_color = color[1]
def save_paint(self): # this is the function for screenshotting whatever is on the canvas
global filename
filename = filedialog.asksaveasfilename(initialdir='C:/',filetypes=[('All files','.*'), ('Picture Files','.png*')])
print(filename)
cx = self.root.winfo_rootx() + self.canvas.winfo_x()
print(cx, self.root.winfo_rootx())
cy = self.root.winfo_rooty() + self.canvas.winfo_y()
print(cy)
cx1 = cx + self.canvas.winfo_width()
print(cx1)
cy1 = cy + self.canvas.winfo_height()
print(cy1)
filename = filename + '.jpeg'
ImageGrab.grab().crop((cx1, cy1, cx, cy)).save(filename) # <-- The value:Error redirects me here
messagebox.showinfo('paint sys','image is saved as '+ str(filename))
if __name__ == "__main__":
root = Tk()
p = Paint(root)
root.mainloop()
the error
**ImageGrab.grab().crop((cx1, cy1, cx, cy)).save(filename) line 1171, in crop
raise ValueError("Coordinate 'right' is less than 'left'")
ValueError: Coordinate 'right' is less than 'left'
**
Whats wrong with my code?
Related
I have a hard time implementing a scrollbar into my Tkinter project. I've been through numerous articles and answered questions on how to implement a scrollbar, but I'm just unable to implement a working solution after an entire day of researching this one 'simple' matter.
My current code looks like this:
import tkinter as tk
from tkinter import Button, ttk
from PIL import ImageTk, Image
from functools import partial
import queue as qu
import math
import re
import os
window = tk.Tk()
queue = qu.Queue()
#Basic values
#the window size
windowSize = "700x1000"
#picture and container size
x, y = 200, 300
#tmp
sidepanelsize = 200
window.geometry(windowSize)
#button identifier
def change(i):
print(I)
#temporary content generator
for g in range(12):
for item in os.listdir("."):
if re.search(r"\.(jpg|png)$", item):
queue.put(item)
n = queue.qsize()
#other panels that are going to be used later
frameLeft = tk.Frame(master=window, width=sidepanelsize, relief=tk.RIDGE)
frameLeft.pack(fill=tk.Y, side=tk.LEFT)
label1 = tk.Label(master=frameLeft, text="Left Panel")
label1.pack()
buttonLeft1 = tk.Button(master=frameLeft, text="Button 1", command=lambda: print("I'm a side button!"))
buttonLeft1.pack()
frameMain = tk.Frame(master=window, relief=tk.GROOVE, borderwidth=1)
frameMain.pack(side=tk.TOP, fill=tk.X, expand=1)
# SCROLLBAR IF YOU DISABLE THIS SECTION AND PUTS SOME PICTURES IN THE FOLDER WHITH THE FILE THE CODE WORKS #
myCanvas = tk.Canvas(master=frameMain)
myCanvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
myScrollbar = ttk.Scrollbar(master=frameMain, orient=tk.VERTICAL, command=myCanvas.yview)
myScrollbar.pack(side=tk.RIGHT, fill=tk.Y)
myCanvas.configure(yscrollcommand=myScrollbar.set)
myCanvas.bind('<Configure>', lambda e: myCanvas.configure(scrollregion=myCanvas.bbox("all")))
secondFrame = tk.Frame(master=myCanvas)
myCanvas.create_window((0, 0), window=secondFrame, anchor=tk.NW)
############################ END OF SCROLLBAR ############################
noOfImgPerRow = math.floor((int(windowSize.split("x")[0])-sidepanelsize+100)/x)
imgs = []
#generates the grid
for i in range(n):
o = i
i = (o % noOfImgPerRow) + 1
j = math.floor(o/noOfImgPerRow) + 1
frameMain.columnconfigure(i, weight = 1, minsize=x+15)
frameMain.rowconfigure(i, weight = 1, minsize=y+50)
frameBox = tk.Frame(
master=frameMain,
relief=tk.RAISED,
borderwidth=1,
width = x,
height = y
)
# here the error references to
frameBox.grid(row=j, column=i, padx=5, pady=5)
img = Image.open(queue.get()).convert("RGBA")
width, height = img.size
if width/x >= height/y:
left = width/2-(round((height*x)/y))/2
right = width/2+(round((height*x)/y))/2
upper = 0
lower = height
else:
left = 0
right = width
upper = height/2-(round((width*y)/x))/2
lower = height/2+(round((width*y)/x))/2
img2 = img.crop([left, upper, right, lower])
img2 = img2.resize((x, y), Image.Resampling.LANCZOS)
imgs.append(ImageTk.PhotoImage(img2))
label = tk.Label(master = frameBox, image = imgs[-1])
label.pack()
mainButton = Button(master=frameBox, text="Start", command=partial(change, o))
mainButton.pack()
window.mainloop()
I've tried to highlight the only thing of concern, that being the scrollbar, everything else is working at the moment, I just wanted to post the whole code for better understanding if it would help in any way.
My problem is whenever I implement the scrollbar, it throws back an error stating:
Traceback (most recent call last):
File "e:\Python\starter\main.py", line 85, in <module>
frameBox.grid(row=j, column=i, padx=5, pady=5)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.1264.0_x64__qbz5n2kfra8p0\lib\tkinter\__init__.py", line 2522, in grid_configure
self.tk.call(
_tkinter.TclError: cannot use geometry manager grid inside .!frame2 which already has slaves managed by pack
This error seems pretty self-explanatory, just grid the canvas instead of packing it, but when after a lot of small tweaking and doing things a roundabouts things
My second thought was if it has a problem with the grid to wrap the gridded frame in another bigger packed frame, like so:
yetAnotherFrame = tk.Frame(frameMain)
yetAnotherFrame.pack()
noOfImgPerRow = math.floor((int(windowSize.split("x")[0])-sidepanelsize+100)/x)
imgs = []
for i in range(n):
o = i
i = (o % noOfImgPerRow) + 1
j = math.floor(o/noOfImgPerRow) + 1
yetAnotherFrame.columnconfigure(i, weight = 1, minsize=x+15)
yetAnotherFrame.rowconfigure(i, weight = 1, minsize=y+50)
frameBox = tk.Frame(
master=yetAnotherFrame,
relief=tk.RAISED,
borderwidth=1,
width = x,
height = y
)
frameBox.grid(row=j, column=i, padx=5, pady=5)
This actually runs to my surprise, but the scrollbar still isn't working and the layout is broken again.
Solution
In your code frameBox's parent is frameMain. Instead you need to have the canvas as parent or the secondFrame which have the canvas as its parent.
Example
This is basically your code with fixes, but some of the unnecessary parts are removed.
import tkinter as tk
from tkinter import ttk
window = tk.Tk()
window.geometry("400x400")
frameLeft = tk.Frame(master=window, width=400, height=400, relief=tk.RIDGE)
frameLeft.pack(fill=tk.Y, side=tk.LEFT)
myCanvas = tk.Canvas(master=frameLeft)
myCanvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
myScrollbar = ttk.Scrollbar(master=frameLeft, orient=tk.VERTICAL, command=myCanvas.yview)
myScrollbar.pack(side=tk.RIGHT, fill=tk.Y)
myCanvas.configure(yscrollcommand=myScrollbar.set)
myCanvas.bind('<Configure>', lambda e: myCanvas.configure(scrollregion=myCanvas.bbox("all")))
secondFrame = tk.Frame(master=myCanvas)
myCanvas.create_window((0, 0), window=secondFrame, anchor=tk.NW)
for i in range(100):
lbl = tk.Label(secondFrame, text=f"Label {i}")
lbl.grid(column=0, row=i, sticky=tk.W)
window.mainloop()
I am trying to create a "movie" style credit reel using tkinter's canvas. I'd like to iterate through a list of names and have them scroll across the window. While I've successfully gotten a single name to scroll, I'm struggling to iterate over several names.
I appreciate your help and apologies for any gross oversights on my part.
from tkinter import *
import time
window = Tk()
window.geometry("1920x1080")
window.title("Window 1")
canvas1 = Canvas(window, width=1920, height=1080, bg="green", bd=0, highlightthickness=0, relief='ridge')
canvas1.pack()
class CreditList:
def __init__(self, text):
self.text = text
self.location = 1080
def credit_roll_function(self):
text = canvas1.create_text(960,self.location, text=self.text, anchor=S, fill="black",
font="Time 40")
while True:
canvas1.move(text, 0, -3)
window.update()
time.sleep(.03)
credit_list = ["First Name", "Second Name", "Third Name"]
for credit in credit_list:
item = CreditList(credit)
item.credit_roll_function()
window.mainloop()
Here's a simple way to do it that uses the universal widget after() method instead of calling time.sleep() which interferes with tkinter's mainloop(). Each time the class' roll_credits() method is called, it moves the text upward a little and schedules another call to itself if the text isn't at the top of the window yet.
import tkinter as tk
from tkinter.constants import *
class CreditList:
def __init__(self, lines):
self.location = HEIGHT
self.text = canvas.create_text(0, 0, text='\n'.join(lines), justify=CENTER,
anchor=NW, fill='black', font='Time 40')
xl, yt, xr, yb = canvas.bbox(self.text)
txtwidth = xr - xl
xpos = (WIDTH-txtwidth) // 2 # To center text horizontally.
canvas.move(self.text, xpos, self.location)
def roll_credits(self):
xl, yt, xr, yb = canvas.bbox(self.text)
if yb <= 0: # Completely off top of screen?
canvas.pack_forget()
tk.Button(text='Done', font=('Courier New', 20), relief=GROOVE, bg='orange',
command=window.quit).place(x=WIDTH/2, y=HEIGHT/2)
return # Stop.
canvas.move(self.text, 0, -3)
window.after(DELAY, self.roll_credits) # Keep going.
DELAY = 25 # Millisecs.
window = tk.Tk()
window.attributes('-fullscreen', True)
window.update_idletasks()
WIDTH, HEIGHT = window.winfo_width(), window.winfo_height() # Get screen size.
window.geometry(f'{WIDTH}x{HEIGHT}+0+0')
window.title('Window 1')
canvas = tk.Canvas(window, width=WIDTH, height=HEIGHT, bg='green', bd=0,
highlightthickness=0, relief='ridge')
canvas.pack()
credits = 'First Name', 'Second Name', 'Third Name'
cl = CreditList(credits)
window.after(DELAY, cl.roll_credits) # Start rolling credits "loop".
window.mainloop()
If you give all of your text items the same tag, you can move them all at the same time. Another solution is to create a single text item that is created by joining all of your strings with a newline.
For example, the following code illustrates how to create all of the items with a given tag, then moves them all one pixel at a time every 33 ms until they no longer are visible.
import tkinter as tk
class CreditList(tk.Canvas):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
def roll_credits(self, credit_list):
x = self.winfo_width() // 2
y = self.winfo_height()
temp = self.create_text(0,0,text="Hello")
bbox = self.bbox(temp)
self.delete(temp)
lineheight = bbox[3]-bbox[1]
linespacing = 4
for credit in credit_list:
self.create_text(x, y, text=credit, anchor="n", tags=("credit",))
y += lineheight + linespacing
self._animate()
def _animate(self):
self.move("credit", 0, -1)
x0, y0, x1, y1 = self.bbox("credit")
if y1 > 0:
self.after(33, self._animate)
root = tk.Tk()
credits = CreditList(root)
credits.pack(side="top", fill="both", expand=True)
credit_list = 'First Name', 'Second Name', 'Third Name'
root.after(1000, credits.roll_credits, credit_list)
root.mainloop()
I want to make radiobutton transparent on canvas image to make it look good, I tried passing lots of option parameters to radiobutton to somehow make it look better but nothing works.
Here is the code I am working with...
from tkinter import *
from tkinter import ttk
from tkinter.ttk import *
from PIL import ImageTk, Image
from tkinter import messagebox
class GUI_Prog:
def __init__(self):
root = Tk()
root.title("Risk Analysis")
root.geometry("1100x630")
r = IntVar()
#Setting up Canvas :
my_canvas = Canvas(root, width=1100, height=630)
my_canvas.pack(fill="both", expand=True)
#Background :
img = Image.open("diagnosis.png")
img = img.resize((1100,630), Image.ANTIALIAS)
bg = ImageTk.PhotoImage(img)
my_canvas.create_image(0,0,image=bg,anchor="nw")
#Creating title text :
my_canvas.create_text(540,40,text="Risk Analysis", font=("Times, 30"), fill = "white")
my_canvas.create_text(140,100,text="1) Do you smoke?", font=("helvetica, 15"), fill = "black")
but_1 = Radiobutton(root, text="yes", variable=r, value=1)
my_canvas.create_window(60, 150, window=but_1)
but_2= Radiobutton(root, text="no", variable=r, value=2)
my_canvas.create_window(150, 150, window=but_2)
mainloop()
obj = GUI_Prog()
Well I created my own RadioButton class but it only works on tkinter.Canvas:
from tkinter import *
from tkinter import ttk
from tkinter.ttk import *
from PIL import ImageTk, Image
from tkinter import messagebox
# Taken from: https://stackoverflow.com/a/17985217/11106801
def _create_circle(self, x, y, r, **kwargs):
return self.create_oval(x-r, y-r, x+r, y+r, **kwargs)
Canvas.create_circle = _create_circle
class Radiobutton:
def __init__(self, canvas, text="", variable=None, value=0, radius=10,
fill="black"):
self.canvas = canvas
self.variable = variable
self.fill = fill
self.text = text
self.value = value
self.radius = radius
self.variable.trace("w", self.redraw)
self.circle = None
def put(self, x, y):
self.x = x
self.y = y
self.canvas.create_circle(x, y, self.radius, outline=self.fill)
self.canvas.create_text(x + 2*self.radius, y, text=self.text,
fill=self.fill, anchor="w")
self.redraw()
self.canvas.bind("<Button-1>", self.select, add=True)
def select(self, event):
if (self.x - event.x)**2 + (self.y - event.y)**2 <= self.radius**2:
self.variable.set(self.value)
self.redraw()
def create_circle(self):
self.circle = self.canvas.create_circle(self.x, self.y, self.radius-4,
outline=self.fill,
fill=self.fill)
def redraw(self, *args):
if self.value == self.variable.get():
if self.circle is None:
self.create_circle()
else:
if self.circle is not None:
self.canvas.delete(self.circle)
self.circle = None
class GUI_Prog:
def __init__(self):
root = Tk()
root.title("Risk Analysis")
root.geometry("1100x630")
r = IntVar()
#Setting up Canvas:
my_canvas = Canvas(root, width=1100, height=630)
my_canvas.pack(fill="both", expand=True)
#Background:
img = Image.open("diagnosis.png")
img = img.resize((1100, 630), Image.ANTIALIAS)
bg = ImageTk.PhotoImage(img)
my_canvas.create_image(0, 0, image=bg, anchor="nw")
#Creating title text:
my_canvas.create_text(540, 40, text="Risk Analysis",
font=("Times", 30), fill="white")
my_canvas.create_text(140, 100, text="1) Do you smoke?",
font=("helvetica", 15), fill="black")
but_1 = Radiobutton(my_canvas, text="yes", variable=r, value=1,
fill="white")
but_1.put(60, 150)
but_2 = Radiobutton(my_canvas, text="no", variable=r, value=2,
fill="white")
but_2.put(150, 150)
r.set(1)
root.mainloop()
obj = GUI_Prog()
You create it as normal but you pass in the <tkinter.Canvas> as its master. After that you can just call .put with the position where you want it to be created. This is a very patchy solution so if someone else posts a better solution, I will delete this.
I tried to plot the graph in pop up window. It pops up. But there is an error.
import tkinter as tk
window = tk.Tk()
window.configure(background='white')
label_1 = tk.Label(window, text="Conpyright 123456789123456798", anchor=tk.S)
label_1.pack()
ws = window.winfo_screenwidth()
hs = window.winfo_screenheight()
w = 980 # width for the Tk root
h = 600 # height for the Tk root
x = (ws / 2) - (w / 2)
y = (hs / 2) - (h / 2)
window.geometry('%dx%d+%d+%d' % (w, h, x, y))
canvas = tk.Canvas(window, bg="white", width=980, height=580, highlightthickness=0)
canvas.pack()
canvas_scroll = tk.Scrollbar(canvas, command=canvas.yview)
canvas_scroll.place(relx=1, rely=0, relheight=1, anchor=tk.NE)
canvas.configure(yscrollcommand=canvas_scroll.set, scrollregion=())
minw_var = tk.DoubleVar()
entry_minw_number = tk.Entry(canvas, textvariable=minw_var)
canvas.create_window(220,215, window=entry_minw_number)
maxw_var = tk.DoubleVar()
entry_maxw_number = tk.Entry(canvas, textvariable=maxw_var)
canvas.create_window(355,215, window=entry_maxw_number)
minl_var = tk.DoubleVar()
entry_minl_number = tk.Entry(canvas, textvariable=minl_var)
canvas.create_window(220,240, window=entry_minl_number)
maxl_var = tk.DoubleVar()
entry_maxl_number = tk.Entry(canvas, textvariable=maxl_var)
canvas.create_window(355,240, window=entry_maxl_number)
rect_var = tk.IntVar()
entry_rect_number = tk.Entry(canvas, textvariable=rect_var)
canvas.create_window(290,270, window=entry_rect_number)
And this is the part for matplotlib
-------------------------------------------------------------------------
def plot_sheet(self):
fig,ax = plt.subplots(1)
ax.set_xlim([0, self.W])
ax.set_ylim([0, self.L])
recs = []
for i in range(len(self.rect_list)):
if self.rect_rotate[i]:
ax.add_patch(patches.Rectangle((self.rect_pos[i][0], self.rect_pos[i][1]), self.rect_list[i].l, self.rect_list[i].w,linewidth=3,edgecolor='r'))
else:
ax.add_patch(patches.Rectangle((self.rect_pos[i][0], self.rect_pos[i][1]), self.rect_list[i].w, self.rect_list[i].l,linewidth=3,edgecolor='r'))
#plt.show()
return fig
def plot_sheets(self):
for i in range(len(self.sheets)):
self.sheets[i].plot_sheet()
def cal_culate1():
fig = packing_options[best_index].plot_sheets()
dataPlot = FigureCanvasTkAgg(fig, master = window)
dataPlot.show()
dataPlot.get_tk_widget().pack(side='top', fill='both', expand=1)
window.mainloop()
I wrote dataPlot = FigureCanvasTkAgg(fig, master = window). There is an error in master = window.
File "", line 687, in cal_culate1
dataPlot = FigureCanvasTkAgg(fig, master = window)
File "C:\Users\sel\Anaconda3\lib\site-packages\matplotlib\backends_backend_tk.py", line 204, in init
super(FigureCanvasTk, self).init(figure)
File "C:\Users\sel\Anaconda3\lib\site-packages\matplotlib\backend_bases.py", line 1618, in init
figure.set_canvas(self)
AttributeError: 'NoneType' object has no attribute 'set_canvas'
What should be written there?
You didn't show how you create your class for plotting, so i can only go by assumption here. First create a empty list:
import tkinter as tk
window = tk.Tk()
window.configure(background='white')
figure_holder = []
Then append to the list when you create your figure:
def plot_sheets(self):
for i in range(len(self.sheets)):
a = self.sheets[i].plot_sheet()
figure_holder.append(a)
Retrieve the figure object from the list when you plot it:
def cal_culate1():
fig = figure_holder[0]
dataPlot = FigureCanvasTkAgg(fig, master = window)
#dataPlot.show()
dataPlot.get_tk_widget().pack(side='top', fill='both', expand=1)
I made minimal working example which shows how do this.
it will need changes for your code but I don't know what you have in code and you didn't create minimal working example.
It creates three figures in generate_all_figures (in your code it will be plot_sheets with s) using plot_sheet (without s) and keep on list.
window display first figure from this list.
Buttons remove canvas with figure and create new canvas with next/previous figure from list.
I use grid() instead of pack() because this way I can easily put new canvas in the same place.
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
class MyClass():
def __init__(self):
self.sheets = [[1,2,3], [3,1,2], [1,5,1]]
self.W = 2
self.L = 5
self.all_figures = []
def plot_sheet(self, data):
"""plot single figure"""
fig, ax = plt.subplots(1)
ax.set_xlim([0, self.W])
ax.set_ylim([0, self.L])
ax.plot(data)
return fig
def generate_all_figures(self):
"""create all figures and keep them on list"""
for data in self.sheets:
fig = self.plot_sheet(data)
self.all_figures.append(fig)
def show_figure(number):
global dataPlot
# remove old canvas
if dataPlot is not None: # at start there is no canvas to destroy
dataPlot.get_tk_widget().destroy()
# get figure from list
one_figure = my_class.all_figures[number]
# display canvas with figuere
dataPlot = FigureCanvasTkAgg(one_figure, master=window)
dataPlot.draw()
dataPlot.get_tk_widget().grid(row=0, column=0)
def on_prev():
global selected_figure
# get number of previous figure
selected_figure -= 1
if selected_figure < 0:
selected_figure = len(my_class.all_figures)-1
show_figure(selected_figure)
def on_next():
global selected_figure
# get number of next figure
selected_figure += 1
if selected_figure > len(my_class.all_figures)-1:
selected_figure = 0
show_figure(selected_figure)
# --- main ---
my_class = MyClass()
my_class.generate_all_figures()
window = tk.Tk()
window.rowconfigure(0, minsize=500) # minimal height
window.columnconfigure(0, minsize=700) # minimal width
# display first figure
selected_figure = 0
dataPlot = None # default value for `show_figure`
show_figure(selected_figure)
# add buttons to change figures
frame = tk.Frame(window)
frame.grid(row=1, column=0)
b1 = tk.Button(frame, text="<<", command=on_prev)
b1.grid(row=0, column=0)
b2 = tk.Button(frame, text=">>", command=on_next)
b2.grid(row=0, column=1)
window.mainloop()
Probably it could be done without replacing canvas but by replacing data in plot (fig.data ???, ax.data ??? I don't remember)
I am trying to create a program where you click on a Tkinter canvas and a RawTurtle moves to the mouse, but my code is not working. The canvas has a Button-1 event binded to it to tell the program the coordinates of the mouse.
But, when you click on the canvas, instead of the turtle going to the mouse, it kind of mirrors what you would expect it to do (moves away from the mosue as if another mosue is being mirrored). Both the event and the turtle position coordinates are the same when they are printed out.
Code:
import turtle
from tkinter import *
def move(event):
global t
x = event.x
y = event.y
t.setpos(x,y)
print(t.pos())
print(event)
def penState(event):
global penDown,t
if penDown == True:
t.penup()
penDown = False
else:
t.pendown()
penDown = True
def changeWidth(w):
t.pensize(w)
def changeColour(e=None):
global colourBox
t.color(colourBox.get())
colourBox.configure(fg=colourBox.get())
def doCircle():
global checkFillIsTrue,circleSizeBox
if checkFillIsTrue.get() == 1:
begin_fill()
t.circle(int(circleSizeBox.get()))
end_fill()
else:
circle(int(circleSizeBox.get()))
window = Tk('Paint')
window.title('onionPaint')
root = Frame(window)
root.pack(side=LEFT)
cv = Canvas(window,width=500,height=500)
t = turtle.RawTurtle(cv)
t.resizemode('user')
cv.bind('<Button-1>',move)
cv.bind('<Button-2>',penState)
cv.pack(side=RIGHT)
checkFillIsTrue=IntVar()
penDown = True
#Pen width box
sizeLabel = Label(root, text="Pen Width")
sizeLabel.grid()
sizeScale = Scale( root, variable = \
'var',orient=HORIZONTAL,command=changeWidth )
sizeScale.grid()
#Colour box
colourLabel = Label(root, text="Color(HEX or name):")
colourLabel.grid()
colourFrame = Frame(root)
colourFrame.grid()
colourBox = Entry(colourFrame, bd=1)
colourBox.pack(side=LEFT)
colourSubmit = Button(colourFrame,text="OK",command=changeColour)
colourSubmit.pack(side=RIGHT)
#Fill
fillLabel = Label(root,text='Fill')
fillLabel.grid()
fillFrame = Frame(root)
fillFrame.grid()
beginFill = Button(fillFrame,text='Begin Fill',command=t.begin_fill)
endFill = Button(fillFrame,text='End Fill',command=t.end_fill)
beginFill.pack(side=LEFT)
endFill.pack(side=RIGHT)
#Mmore shapes
Label(root,text='Shapes').grid()
#Circle form
Label(root,text='Circle',font=('Heveltica',8)).grid()
circleSize = Frame(root)
circleSize.grid()
circleSizeBox = Entry(circleSize,bd=1)
circleSizeBox.insert(0,'Radius')
circleSizeBox.pack(side=LEFT)
fillCheck =
Checkbutton(circleSize,text='Fill',variable=checkFillIsTrue).pack(side=LEFT)
circleSizeSubmit =
Button(circleSize,text='Draw',command=doCircle).pack(side=RIGHT)
#Text form
Label(root,text='Text',font=('Heveltica',8)).grid()
textFrame = Frame(root)
textFrame.grid()
window.mainloop()
Any help with this problem would be greatly appreciated.
Your code is a disaster. You should specifically read up on the 'global' keyword in Python and when it must be used. And Python code style in general. I believe the key fix to your program is to introduce a TurtleScreen overlay on the canvas and then switch to turtle event handing rather than tkinter event handing.
I've reworked your code below, fixing as many problems as I could:
import turtle
from tkinter import *
FONT = ('Helvetica', 8)
def move(x, y):
terrapin.setpos(x, y)
print(terrapin.pos())
def penState(x, y):
global penDown
if penDown:
terrapin.penup()
penDown = False
else:
terrapin.pendown()
penDown = True
def changeWidth(w):
terrapin.pensize(w)
def changeColour():
color = colourBox.get()
terrapin.color(color)
colourBox.configure(fg=color)
def doCircle():
radius = int(circleSizeBox.get())
if checkFillIsTrue.get():
terrapin.begin_fill()
terrapin.circle(radius)
terrapin.end_fill()
else:
terrapin.circle(radius)
window = Tk('Paint')
window.title('onionPaint')
root = Frame(window)
root.pack(side=LEFT)
canvas = Canvas(window, width=500, height=500)
screen = turtle.TurtleScreen(canvas)
terrapin = turtle.RawTurtle(screen)
screen.onclick(move, btn=1)
screen.onclick(penState, btn=2)
canvas.pack(side=RIGHT)
checkFillIsTrue = BooleanVar()
penDown = True
# Pen width box
sizeLabel = Label(root, text="Pen Width")
sizeLabel.grid()
sizeScale = Scale(root, variable='var', orient=HORIZONTAL, command=changeWidth)
sizeScale.grid()
# Colour box
colourLabel = Label(root, text="Color(HEX or name):")
colourLabel.grid()
colourFrame = Frame(root)
colourFrame.grid()
colourBox = Entry(colourFrame, bd=1)
colourBox.pack(side=LEFT)
colourSubmit = Button(colourFrame, text="OK", command=changeColour)
colourSubmit.pack(side=RIGHT)
# Fill
fillLabel = Label(root, text='Fill')
fillLabel.grid()
fillFrame = Frame(root)
fillFrame.grid()
beginFill = Button(fillFrame, text='Begin Fill', command=terrapin.begin_fill)
endFill = Button(fillFrame, text='End Fill', command=terrapin.end_fill)
beginFill.pack(side=LEFT)
endFill.pack(side=RIGHT)
# More shapes
Label(root, text='Shapes').grid()
# Circle form
Label(root, text='Circle', font=FONT).grid()
circleSize = Frame(root)
circleSize.grid()
circleSizeBox = Entry(circleSize, bd=1)
circleSizeBox.insert(0, 'Radius')
circleSizeBox.pack(side=LEFT)
fillCheck = Checkbutton(circleSize, text='Fill', variable=checkFillIsTrue).pack(side=LEFT)
circleSizeSubmit = Button(circleSize, text='Draw', command=doCircle).pack(side=RIGHT)
# Text form
Label(root, text='Text', font=FONT).grid()
textFrame = Frame(root)
textFrame.grid()
window.mainloop()