Try to Put Functions into one Button Tkinter - python

plz can someone help, i try to put functions into one button Tkinter but it didn't work. i try to do image color conversion manually with opencv formula. But when i try to run it with tkinter button it didn't nothing.
def convertBGRtoHSV(image):
path = filedialog.askopenfilename()
image = cv2.imread(path)
rows = image.shape[0]
cols = image.shape[1]
sample = (image * (1/255.0))
B,G,R = cv2.split(sample)
V = np.zeros((rows, cols)[:2],dtype=np.float64)
S = np.zeros((rows, cols)[:2],dtype=np.float64)
H = np.zeros((rows, cols)[:2],dtype=np.float64)
for i in range(rows):
for j in range(cols):
V[i,j] = max(B[i,j],G[i,j],R[i,j])
Min_RGB = min(B[i,j],G[i,j],R[i,j])
if V[i,j] != 0.0:
S[i,j] = ((V[i,j] - Min_RGB) / V[i,j])
else:
S[i,j] = 0.0
if V[i,j] == R[i,j]:
H[i,j] = 60*(G[i,j] - B[i,j])/(V[i,j] - Min_RGB)
elif V[i,j] == G[i,j]:
H[i,j] = 120 + 60*(B[i,j] - R[i,j])/(V[i,j] - Min_RGB)
elif V[i,j] == B[i,j]:
H[i,j] = 240 + 60*(R[i,j] - G[i,j])/(V[i,j] - Min_RGB)
if H[i,j] < 0:
H[i,j] = H[i,j] + 360
V = 255.0 * V
S = 255.0 * S
H = H/2
hsv = np.round(cv2.merge((H,S,V)))
return hsv.astype(np.uint8)
percobaan = convertBGRtoHSV(image)
H = crophsv[:,:,0] #Mengambil Nilai H pada Gambar
S = crophsv[:,:,1] #Mengambil Nilai S pada Gambar
V = crophsv[:,:,2] #Mengambil Nilai V pada Gambar
data = (H)
print(data)
btn = Button(gui, text='Select A Image', width=15,height=3, bd='5', command=[convertBGR2HSV()])
btn.place(x=500, y=650)
btn.pack
when i try running with opencv library tkinter button works and get all hue
the mode hue is all 0
when im using library opencv it work.may god bless anyone who help me. Because im beginner.

What you're passing for command (i.e. [convertBGR2HSV()]) doesn't make any sense. Think about what it's doing: calling the function convertBGR2HSV and putting its return value in a list, which is then used as command.
command is the function that you want to be called when the button is pressed, so that the code in it is run at that time. So, it doesn't make sense for you to call it yourself. Instead you just need to pass the function, e.g.
btn = Button(gui, text='Select A Image', width=15,height=3, bd='5', command=convertBGR2HSV)
If you want to do multiple things when the button is pressed, then write a function that does that and pass that as command, e.g.
def do_several_things():
do_thing_1()
do_thing_2()
do_thing_3()
...
button = Button(..., command=do_several_things)

Related

Error object has no attribute in Paint app

This is the code, I got it from here https://www.youtube.com/watch?v=uW-NLL9dlBs
After many attempts, I solved some issues, but I still couldnt get it to work.
Its supposed to be an app for painting. I wanted it to have very large pixels with invisible grid too, so painting in it would create low resolution pixel art, similar to this. I dont know how to do that, as I couldnt find it anywhere. pixel image
from tkinter import *
from tkinter.ttk import Scale
from tkinter import colorchooser,filedialog,messagebox
import PIL.ImageGrab as ImageGrab
class Paint():
def __init__(self,root):
self.root = root
self.root.title("Paint")
self.root.geometry("800x520")
self.root.configure(background='white')
self.root.resizable(0,0)
self.pen_color = "black"
self.eraser_color = "white"
self.color_frame = LabelFrame(self.root,text='Color',font = ('arial',15),bd=5,relief=RIDGE,bg='white')
self.color_frame.place(x=0,y=0,width=70,height=185)
colors = ['#ff0000','#ff4dd2','#ffff33','#000000','#0066ff','#660033','#4dff4d','#b300b3','#00ffff','#808080','#99ffcc','#336600','#ff9966','#ff99ff','#00cc99']
i=j=0
for color in 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)
i+=1
if i==6:
i=0
j=1
self.eraser_button = Button(self.root,text="ERASER",bd=4,bg='white',command=self.eraser,width=8,relief=RIDGE)
self.eraser_button.place(x=0,y=187)
self.clear_button = Button(self.root, text="Clear",bd=4,bg='white',command=lambda : self.canvas.delete("all"),width=8,relief=RIDGE)
self.clear_button.place(x=0,y=217)
self.save_button = Button(self.root,text="Save",bd=4,bg='white',command=self.save_paint,width=8,relief=RIDGE)
self.save_button.place(x=0,y=247)
self.canvas_color_button = Button(self.root,text="Canvas", bd=4 , bg='white', command=self.canvas_color(),width=8,relief=RIDGE)
self.canvas_color_button.place(x=0, y=277)
self.pen_size_scale_frame = LabelFrame(self.root,text="size",bd=5,bg='white',font=('arial',15,'bold'),relief=RIDGE)
self.pen_size_scale_frame.place(x=0,y=310,height=200,width=70)
self.pen_size = Scale(self.pen_size_scale_frame,orient=VERTICAL,from_ = 50, to = 0,length=170)
self.pen_size.set(1)
self.pen_size.grid(row=0,column=1,padx=15)
self.canvas = Canvas(self.root,bg='white',bd=5,relief=GROOVE,height=500,width=700)
self.canvas.place(x=80,y=0)
self.canvas.bind("<B1-Motion>",self.paint)
def paint(self,event):
x1,y1 = (event.x-2),(event.y-2)
x2,y2 = (event.x + 2),(event.y + 2)
self.canvas.create_oval(x1,y1,x2,y2,fill=self.pen_color,outline=self.pen_color,width=self.pen_size.get())
def select_color(self,col):
self.pen_color = self.eraser_color
def eraser(self):
self.pen_color = "white"
def canvas_color(self):
color = colorchooser.askcolor()
self.canvas.configure(background=color[1])
self.eraser_color = color[1]
def save_paint(self):
try:
filename = asksaveasfilename(defaultextension='.jpg')
x = self.root.winfo_rooty() + self.canvas.winfo_x()
y = self.root.winfo_rooty() + self.canvas.winfo_y()
x1 = x + self.canvas.winfo_width()
y1 = y + self.canvas.winfo_height()
ImageGrab.grab().crop((x,y,x1,y1)).save(filename)
messagebox.showinfo('paint says','image is saved as ' + str(filename))
except:
messagebox.showerror("paint says","unable to save image ,\n something went wrong")
if __name__ == "__main__":
root = Tk()
p = Paint(root)
root.mainloop()
In order to get your paint program working, the following bugs need to be addressed.
The self.canvas_color_button command has a bug. Just remove the parens to make it work.
There's a problem with color selection methods.
Here is the solution.
def select_color(self,col):
self.pen_color = col
def eraser(self):
self.pen_color = self.eraser_color
When saving a drawing, the image is not cropped correctly due to other widgets.
self.color_frame has a width of 70.
Your canvas is defined with a borderwidth(5) and a highlightthickness(2).
These values must be taken into account.
Here is one solution to crop your saved images correctly.
xoffset = self.color_frame.winfo_width()
yoffset = int(self.canvas["borderwidth"]) + int(self.canvas["highlightthickness"])
x = self.root.winfo_rooty() + self.canvas.winfo_x()
y = self.root.winfo_rooty() + self.canvas.winfo_y() + yoffset
x1 = x + self.canvas.winfo_width() - xoffset
y1 = y + self.canvas.winfo_height() - (yoffset * 2)

Why does my program require me to press the enter key before continuing (python tkinter)

I am making a program, using python tkinter, which simply prints some circles to the screen (I call it a board in this program). The program moves on to a different "board" once the mouse cursor moves over the button. The problem I have is that I simply call the "create_board" function 3 times using a for loop however in-between each iteration of the loop the "enter" key must be pressed. This isn't a massive deal but I'm trying to understand why and if there is a way to remove this requirement and have the next board load automatically.
I'm certain it has something to do with the tkinter windows and triggering the command "destroy" once the buttons (circles) are pressed however I'm still learning how to effectively use tkinter and any help would be very much appreciated.
def create_board(user_name, board):
# define the name of tkinter window
win = Tk()
# get the size of the displace for position and size calculations
app = wx.App(False)
w, h = wx.GetDisplaySize()
name = user_name
# define variables based on board number
if board == 0:
gx_pos = int(w/8) # locations of circles
gy_pos = int(h/8)
bx_pos = (w/8)*5
by_pos = (h/8)*5
board_num = str(1)
elif board == 1:
gx_pos = int(w/12)
gy_pos = int(h/12)
bx_pos = (w/6)*5
by_pos = (h/6)*5
board_num = str(2)
elif board == 2:
gx_pos = int(w/3)
gy_pos = int(h/3)
bx_pos = (w/3)*2
by_pos = (h/3)*2
board_num = str(3)
# records the mouse cursor position into a file along with time taken
def record_pos(x, y, board_num, s):
filename = name + "_" + board_num + ".txt"
try:
os.path.isfile('./'+filename)
except:
open(filename, 'r')
with open(filename, 'a') as f:
f.write(str(x) + "," + str(y) + "," + str(s) + "\n")
# determining when left click should be made
def mouse_pos():
flags, hcursor, (x, y) = win32gui.GetCursorInfo()
time_taken = time.time()
record_pos(x, y, board_num, time_taken)
mouse.click('left')
win.after(500, mouse_pos)
# wait 3 seconds before loading first board
time.sleep(3)
geometry = "%dx%d" % (w,h)
win.geometry(geometry)
win.attributes('-fullscreen', True)
win.config(cursor="circle")
# get the grid image
bg = Image.open("grid_image.png")
img = bg.resize((w, h))
grid_img=ImageTk.PhotoImage(img)
image_label = Label(win, image=grid_img)
image_label.place(x=0, y=0, relwidth=1, relheight=1)
# print an image of a green circle
gw = int(w/26)
gh = int(h/15)
g_circle = Image.open('green_circle.png')
g_img = g_circle.resize((gw,gh))
g_circle_image=ImageTk.PhotoImage(g_img)
g_label = Label(win, image=g_circle_image)
g_label.place(x = gx_pos,y = gy_pos)
g_btn = Button(win, image=g_circle_image, command = win.destroy)
g_btn.place(x= gx_pos , y= gy_pos)
# print an image of a blue circle
bw = int(w/26)
bh = int(h/15)
b_circle = Image.open('circle.png')
b_img = b_circle.resize((bw,bh))
b_circle_image=ImageTk.PhotoImage(b_img)
b_label = Label(win, image=b_circle_image)
b_label.place(x=bx_pos, y=by_pos)
b_btn = Button(win, image=b_circle_image, command = win.destroy)
b_btn.place(x=bx_pos, y=by_pos)
# record mouse position
mouse_pos()
win.mainloop()
EDIT: I added the simple for loop that I'm using to iterate through the boards.
for i in range(3):
create_board(user_name, i)
The issue was caused by using time.sleep() in tkinter. After removing this the code runs with out requiring an enter key press each time.

Is there a way to update Tkinter canvas live with text?

I am trying to visualise the backtracking algorithm to solve sudoku puzzles using Tkinter (Example video: https://www.geeksforgeeks.org/building-and-visualizing-sudoku-game-using-pygame/)
def play_puzzle(self):
self.play_frame.pack_forget()
self.home_frame.pack_forget()
self.play_frame.pack(fill=BOTH, expand=1)
self.canvas = Canvas(self.play_frame, width=WIDTH, height=HEIGHT)
self.canvas.grid(row=0, column=0, columnspan=9, rowspan=9)
self.canvas.bind("<Button-1>", self.cell_clicked)
self.canvas.bind("<Key>", self.key_pressed)
solution_btn = ttk.Button(self.play_frame, text='Solution', command=self.solve_puzzle)
home_btn = ttk.Button(self.play_frame, text='Home', command=lambda: self.return_home('play'))
clear = ttk.Button(self.play_frame, text='clear', command = lambda: self.canvas.delete('numbers'))
view_solution_btn = ttk.Button(self.play_frame, text='View Solution', command=self.view_solution)
solution_btn.grid(row= 1, column = 11)
home_btn.grid(row = 3, column = 11)
clear.grid(row=5, column = 11)
view_solution_btn.grid(row=7, column = 11)
self.draw_grid()
self.draw_puzzle()
def view_solution(self):
find = self.game.find_empty()
if not find:
print('Solution found')
return True
else:
e_row, e_col = find
for i in range(1,10):
if self.game.is_valid(i, e_row, e_col):
self.game.puzzle[e_row][e_col] = i
self.play_puzzle()
time.sleep(1)
if self.view_solution():
return True
self.game.puzzle[e_row][e_col] = 0
return False
def draw_puzzle(self):
self.canvas.delete("numbers")
for i in range(9):
for j in range(9):
answer = self.game.puzzle[i][j]
if answer != 0:
x = MARGIN + j * SIDE + SIDE / 2
y = MARGIN + i * SIDE + SIDE / 2
original = self.game.start_puzzle[i][j]
color = "black" if answer == original else "sea green"
self.canvas.create_text(x, y, text=answer, tags="numbers", fill=color)
def draw_grid(self):
for i in range(10):
color = 'blue' if i%3==0 else 'gray'
x0 = MARGIN + i*SIDE
y0 = MARGIN
x1 = MARGIN + i*SIDE
y1 = HEIGHT - MARGIN
self.canvas.create_line(x0,y0,x1,y1, fill=color)
x0 = MARGIN
y0 = MARGIN + i*SIDE
x1 = WIDTH-MARGIN
y1 = MARGIN + i*SIDE
self.canvas.create_line(x0,y0,x1,y1, fill=color)
When I call the view_solution function in the above snippet(by clicking the view solution button), it doesn't update the canvas every time it runs but outputs the answer/fills the puzzle with solution after it completes the entire loop. Is there a way that I could make this work like the one in the video shown?
I have tried using .after() function in Tkinter but I am not sure how to implement it perfectly.
Entire code here - https://github.com/ssram4298/sudoku_gui_tkinter
There are a few ways to update the canvas while processing it.
root.update() #self.parent.update() in your code
root.update_idletasks() #self.parent.update_idletasks() in your code
You can also update individual widgets by calling update() on them (myButton.update()).
If you need to process a change on a widget it needs to be updated before it will be rendered.

Generator for placing images on tkinter canvas

I have a list of paths to around 90 images, now I want to place all of them on the canva,but only let's say 30 in one "row", but if I use
from tkinter import *
def createCanvaImages(paths):
paths = ['list with the paths']
mainWin = Tk()
canva = Canvas(mainWin, width = 900, height = 300).pack()
for x in range(0, len(paths),):
if x <= 30: #not sure if this places only 30 in one row
y=x/3
elif x > 30
y=(x+24)/3
elif x >= 60
y=(x+48)/3
img = PhotoImage(file = paths[x])
canva.create_image(x+24, y, image = img)
mainWin.mainloop()
it only shows the image from the last path
EDIT
now shows all images on the canvas if the canvas isn't in a frame(thanks to Novel) but doesn't work if the canva is in a frame
from tkinter import *
def createImagePaths(dct):
paths=[]
for i in range(len(masteries)):
if dct.get(masteries[i]) == 0:
file = masteries[i]+'.png'
path = os.path.join(path_gray, file)
paths.append(path)
#create canvas image fnc
if dct.get(masteries[i]) != 0:
file = masteries[i]+'.png'
path = os.path.join(path_colored, file)
paths.append(path)
return createCanvaImages(paths)
def createCanvaImages(paths):
img_refs = []
canva = Canvas(masteryFrame, height = 400).pack()
for i, path in enumerate(paths):
col,row = divmod(i,30)
img = PhotoImage(file=path)
canva.create_image( row*24, col*24, image = img, anchor = 'nw')
img_refs.append(img)
root = Tk()
mainFrame = Frame(root)
mainFrame.grid(column=0,row=0, sticky=(N,W,E,S))
masteryFrame = Frame(root)
masteryFrame.grid(row=1,column=0, sticky=(N,W,E,S))
root.mainloop()
You need to save your image references. The easiest way to do that is to just add them to a list. As a guess:
from tkinter import *
def createCanvaImages(paths):
canva = Canvas(masteryFrame, width = 900, height = 300)
canva.pack()
canva.img_refs = []
for i, path in enumerate(paths):
row, col = divmod(i, 30)
img = PhotoImage(file = path)
canva.create_image(col*24, row*24, image = img, anchor='nw') # each image is 24x24
canva.img_refs.append(img)
Also, make sure you never put a widget initialization and layout on the same line. IOW, don't ever do this: Widget(master).pack(). Always put those on separate lines.
You should also learn about OOP and classes very soon. Using functions to build the UI like this will get very messy and buggy very quickly.

Making Tkinter Photoimage crashes python program

I'm writing a minesweeper game using tkinter, and everything appears to function alright, but python crashes every time after a number of clicks, and I believe it is because I've added images for the "flags" used to flag where a mine is. Below is the function that draws all of the cells, which is called with each move/click.
def draw_cake_cell(canvas, row, col):
# draws different cells on the board (blank cell, numbers, cake flags)
margin = 5
cellSize = 30
board = canvas.data['board']
mask = canvas.data['mask']
cake_count = canvas.data['cake_count']
player_board = canvas.data['player_board']
left = margin + col*cellSize
top = margin + row*cellSize
bottom = top + cellSize
right = left+cellSize
flag_img = PhotoImage(file="flag.gif")
flag_label = Label(image = flag_img)
flag_label.image = flag_img
cake_img = PhotoImage(file = "cakeflag.gif")
cake_label = Label(image = cake_img)
cake_label.image = cake_img
canvas.create_rectangle(left,top, right, bottom, fill = 'gray')
if board[row][col] == -1:
if canvas.data['isGameOver'] == True:
canvas.create_image((left+right)/2,(top+bottom)/2,image = cake_img)
elif mask[row][col] == -2:
canvas.create_image((left+right)/2,(top+bottom)/2,image = flag_img)
else:
if cake_count[row][col] > 0 and player_board[row][col] == 1:
value = cake_count[row][col]
canvas.create_rectangle(left,top,right,bottom, fill = 'white')
canvas.create_text((left+right)/2,(top+bottom)/2 , text = str(value), font = ('Helvetica',12))
if mask[row][col] == -2:
canvas.create_image((left+right)/2,(top+bottom)/2,image = flag_img)
if cake_count[row][col] == 0 and player_board[row][col] == 1:
canvas.create_rectangle(left,top,right,bottom, fill = 'white')
Since you are using python3, (left+right)/2 is float, not an int. maybe that's the problem - use (left+right)//2.

Categories