Tkinter, issues with image disapearing and "buttons" not capturing click - python

probalby those are two separate issues, but i can not find help for any of them
I am doing an basic interface with TKINTER that work both on PC and raspberry with LCD screen, plenty of lines to raise this. Interface is basic, just a image with some bottons on top, buttons are made with shapes (i.e. create rectangle)
issue come first that background image is only displayed briefly and the disapear, but not on debuggin mode (Visual Studio code and F5 step by step), and second, buttons do not capture click of mouse if I do not add button backgroud, if added border (as bellow example), only get hitted on the border.
codesnipet:
import tkinter as tk
...
self.canvas = tk.Canvas(self, bg=self.backgroundColor, bd=0, highlightthickness=0, relief='ridge')
self.canvas.config(cursor="circle")
self.canvas.pack(fill=tk.BOTH, expand=1)
self.canvas.bind("<Key>", event_keypress)
for i_v in range(2):
for i_h in range (5):
tagName = "pad_button_" + str(i_v * 5 + i_h)
self.canvas.tag_bind(tagName,"<Button-1>", lambda event, arg=tagName: event_callback(event, arg) )
self.canvas.create_image(10,10, image = myImg, anchor = "nw")
sleep(1)
keysize = 10
buttonsWidth = 2
colorOutline = 'red'
color = '' # <-
for i_v in range (0,2):
for i_h in range (0,5):
v_position = i_v * (keysize)
h_position = i_h * (keysize)
tagName = "pad_button_" + str(i_v * 5 + i_h)
self.canvas.create_rectangle( h_position
, v_position
, h_position + keysize
, v_position + keysize
, width=buttonsWidth
, fill=color
, outline=colorOutline
, tags=["pad_button",tagName] )
self.canvas.update()
I know I am not very good, I am learning, and I got stuck with that for several days, looking help haven't been able to come forward
I tested the "in_function_scope", does not seem to be the thing as it disvanice also in:
myImg = ...
img1=tk_canvas.create_image(4,4, image = myImg, anchor = "nw")
tk_canvas.pack()
tk_canvas.update()
time.sleep(0.3)
myImg = ...
img2=tk_canvas.create_image(40,40, image = myImg, anchor = "nw")
tk_canvas.pack()
tk_canvas.update()
(not sure what I am doing with the pack as it does not have any effect)

Related

Is it possible to have a mouse left click after 2 seconds of inactivity - Tkinter

I am making a GUI in Tkinter, python, which can be navigated using a mouse cursor but no buttons/keys.
I am trying to solve a current problem of having the mouse left click without anyone pressing the physical mouse button or a key on the keyboard. I would like to have the mouse auto click after 2 seconds of inactivity.
For example i hover over a button and wait two seconds then the button is pressed.
I would like to say i have tried everything but i cant find anything to try. I thought about using the .invoke() function with a timing loop but i cant get it to run while my gui is open. ill show my gui code. Maybe i am doing something wrong, but if i place the .invoke function after the win.mainloop then it wont even run untill i close the gui tk window.
win = Tk()
# get the dimensions of the primary screen
app = wx.App(False)
w, h = wx.GetDisplaySize()
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=w/8, y=h/8)
g_btn = Button(win, image=g_circle_image, command=win.destroy)
g_btn.place(x=(w/8), y=(h/8))
# 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=(w/8)*5, y=(h/8)*5)
b_btn = Button(win, image=b_circle_image, command=win.destroy)
b_btn.place(x=(w/8)*5, y=(h/8)*5)
win.mainloop()
Any help with solving this would be much appreciated.
As you already seem to be confirming the option with tk.Button().invoke() you can use tk.Button.bind('<Enter>', _onhover) to detect the mouse over your button and tk.Button.bind('<Leave>', _onleave)
Define two functions like that:
def _onhover(event):
global _current_button
button = event.widget
_current_button = button
button.after(2000, lambda b=button: _invocation(b))
def _onleave(event):
global _current_button
_current_button = None
def _invocation(button):
if _current_button is button:
button.invoke()

how to scroll a canvas with pictures in python?

I tried to scroll a column of images in a canvas with code bellow, when I run the code, the scrollbar shows up but has nothing to scroll. and images are in the main directory.
CODE(python 3):
import tkinter as tk
root = tk.Tk()
root.configure(bg='#1d1d1d')
root.geometry('100x200')
f = tk.PhotoImage(file = 'folder.png')
d = tk.PhotoImage(file = 'database.png')
can = tk.Canvas(root , bg = 'red' )
scroll = tk.Scrollbar(root , command=can.yview)
for i in range(20):
tk.Label(can , image = f , anchor = 'w').pack( side = 'top')
for i in range(10):
tk.Label(can , image = d , anchor = 'w').pack( side = 'top')
can.pack( side = 'left')
scroll.pack(side = 'right' , fill = 'y')
can.config(yscrollcommand=scroll.set)
can.configure(scrollregion=can.bbox("all"))
root.mainloop()
Does anyone know where the problem is?
The canvas cannot scroll items added with pack, place, or grid. To add something to the canvas that can be scrolled you must use one of the create_* methods (create_window, create_image, etc).

How to make each button display a different image on click using tkinter (python)

I am creating a GUI with a ".grid" of buttons. And I want to make each of those buttons display a different image on press. So when I click button 1, it will bring up "image1", on the bottom of the buttons. When I click button 2, it will bring up "image2" and etc.
Through some research, I was able to make the buttons run a function that takes in a parameter through the method below. However, I can't seem to make the button display the image. rather, it just makes an empty white space underneath the buttons, when I press any buttons.
Disclaimer:
- I do not want there to be loads of images, there will only be 1 image, and it will change depending on what button i press.
Here's the code:
from tkinter import *
def funct(numimg):
image = PhotoImage(file="image"+str(numimg)+".png")
label = Label(image=image)
label.grid(row = row_no+1, column = 0, columnspan = num_of_cols)
def make_funct(number):
return (lambda: funct(number))
root= Tk()
row_no = -1
buttons = []
num_of_cols = 3
root.resizable(0, 0)
numfiles = 6
for x in range(0, numfiles):
if(x % num_of_cols is 0):
row_no+=1
buttons.append(Button(root, text = "Button "+str(x), bg = '#4098D3', width = 30,height = 13,command = make_funct(x)))
buttons[x].grid(row = row_no, column = x % num_of_cols)
root.mainloop()
So my question is, how do you make each individual button, display a different image when it is pressed? this program right here just leaves an empty white space in replace of the image, and the image is not shown.
There are two major problems with the code you posted.
The first is basically the same as in this question: Why does Tkinter image not show up if created in a function?. You should keep a reference to the PhotoImage object, else it will be garbage collected and it will not show.
The second is that you create a new Label on every button click. You should only make one Label and change the image with the label.config() method.
I would (without wrapping your GUI in a class, which might be a nicer solution) load all images on initialization, save them in a list as attribute of the label and only change the image upon a button click.
I also removed your make_funct function and replaced it with a lambda, which is the most used way to pass variables to a function on callback.
from tkinter import *
def funct(numimg):
label.config(image=label.images[numimg])
root= Tk()
row_no = -1
buttons = []
num_of_cols = 3
root.resizable(0, 0)
numfiles = 3
for x in range(0, numfiles):
if(x % num_of_cols is 0):
row_no+=1
buttons.append(Button(root, text = "Button "+str(x), bg = '#4098D3', width = 30,height = 13, command = lambda n=x: funct(n)))
buttons[x].grid(row = row_no, column = x % num_of_cols)
label = Label(root)
label.grid(row = row_no+1, column = 0, columnspan = num_of_cols)
label.images=[]
for x in range(0, numfiles):
label.images.append(PhotoImage(file="image"+str(x)+".png"))
root.mainloop()

Buttons overriding set height/width (appearing too big) when creating them in a for loop

I have a method that creates an array of buttons (simulating a grid). The user can click the buttons and a "marker" (image) will appear on it. The problem I have is that even though I'm setting height and width within my method, when it is called, the buttons appear way too big. Important to note that when the user clicks the button, it "shrinks" to the size I specified... Weird. Here is my method:
def create_grid(self, leng) :
try:
global board
board = grid.Grid(leng)
frame = tkinter.Frame(self.main_window)
buttons = []
for row_index in range(0,leng) :
row = []
for column_index in range(0,leng) :
button = tkinter.Button(frame, height=36, \
width = 36, text = " ", \
command=lambda row=row_index, \
column=column_index: \
self.button_clicked(row,column))
button.grid(row=row_index, column=column_index)
row.append(button)
buttons.append(row)
self.gomuko_buttons = buttons
return frame.grid(row=0, column=0)
except TypeError:
return
Also, the function that executes when the button is pressed is the following:
def button_clicked(self,row,column) :
global turns
grid.Comp = False
board.place_marker(row, column)
button = self.gomuko_buttons[row][column]
button['image'] = self.photo1
button['state'] = 'disabled'
turns = turns + 1
Any hint? :(
EDIT:
I solved it thanks to Bryan Oakley's response. Turns out the behaviour for width and height is different for images and text. I solved the problem by simply adding a blank image to the loop, like the following:
button = tkinter.Button(frame, height=0, \
width = 0, text = " ", image = self.blank, \
command=lambda row=row_index, \
column=column_index: \
self.button_clicked(row,column))
Thanks!
My guess is, you think you are giving the button a width of 36 pixels, but you are actually giving it a width of 36 characters. In your callback I'm guessing you're giving the button an image, which causes the button to shrink.
In Tkinter, the width option is interpreted differently depending on whether the button has an image or text. If it has just text, it specifies a width in "average sized characters" (actually, the width of the 0 (zero). If you give the button an image, the width option is interpreted as pixels.
This behavior is documented. See, for example, http://effbot.org/tkinterbook/button.htm#Tkinter.Button.config-method

Why those buttons won't get the text in the same position? (Relative to each button)

Im trying to make a script generate buttons out of a txt file lines (Each line will be a button). It works ok (generates the buttons, same as the number of rows, each with the row as caption) but the text inside the buttons will be in different position (all but the last one will be in the upper side of the button, and the last one is well placed in the center of the button) but all of them share the same code. Interestingly enough, the values I get from the line:
print AuxName
Will be a number, which is the same number for all the loop but the starting one. The full code is this:
from Tkinter import *
from PIL import Image, ImageTk
master = Tk()
master.wm_title("Window Title")
master.geometry("400x400")
tk_rgb = "#%02x%02x%02x" % (128,128,128)
master.config( bg = tk_rgb)
filehandle = open('test.txt','r')
List = filehandle.readlines()
ListSize = len(List)
filehandle.close()
for x in range ( ListSize ):
yy = 20*(x+1)
AuxName = 'btn'+str(x)
AuxName = Button(master, text=List[x], font=("arial", 10))
tk_rgb = "#%02x%02x%02x" % (0,0,0)
AuxName["fg"] = tk_rgb
tk_rgb = "#%02x%02x%02x" % (255,255,255)
AuxName["bg"] = tk_rgb
AuxName.place(x=10, y=yy , height=20, width=200)
print AuxName
print yy
mainloop()
Summary question: How can I make all the buttons have the caption in the center of the button instead of in different position relative to itself as it happens now?
The code as posted works fine.
A guess as to why you're seeing what you're seeing is that the data in your file is causing the problem. Is it possible some lines have lots of leading or trailing whitespace?

Categories

Resources