How to bind multiple mouse buttons to a widget? - python

I'm trying to make the Minesweeper game. For each undifferentiated square I created a button.
my_list = [[0 for i in range(9)] for j in range(9)]
all_buttons = []
def creaMatriz():
for y, row in enumerate(my_list):
buttons_row = []
for x, element in enumerate(row):
boton2 = Button(root, text="", width=6, height=3, command=lambda a=x, b=y: onButtonPressed(a, b))
boton2.grid(row=y, column=x)
buttons_row.append(boton2)
all_buttons.append(buttons_row)
def onButtonPressed(x, y):
all_buttons[y][x]['text'] = str(qwer[x][y]) # Some action!!!
....
When i press the left mouse button on a undifferentiated square, I'm calling the function onButtonPressed(x, y), and a digit or a mine appears on the square.
How can I call another function when pressing the right mouse button on a undifferentiated square. I want see 'M' on the square.
full code: http://pastebin.com/cWGS4fBp

You need to bind keys you wish in order to get this functionality. Here's a simple concept:
from tkinter import *
root = Tk()
def left(event):
label.config(text="Left clicked")
def right(event):
label.config(text="Right clicked")
label = Label(root, text="Nothing")
label.pack()
label.focus_set()
label.bind("<1>", left)
label.bind("<3>", right)
Let us know if it is what you're looking for.

There's nothing special you need to do, you simply need to bind each mouse button separately rather than using the command attribute.
For example, let's create a callback for the left and right mouse buttons:
def onLeftClick(x, y):
print("you clicked on %x,%y" % (x, y))
def onRightClick(x, y):
print("you clicked on %x,%y" % (x, y))
Next, we can bind to each of those functions separately using the bind method. Since we're adding custom bindings, we do not want to set the command attribute of the button.
def creaMatriz():
for y, row in enumerate(my_list):
buttons_row = []
for x, element in enumerate(row):
button = Button(root, text="", width=6, height=3)
...
button.bind("<1>", lambda event, x=x, y=y: onLeftClick(x,y))
button.bind("<3>", lambda event, x=x, y=y: onRightClick(x,y))

Related

Assign a value to a button in tkinter

I am writing a chess program where each square is a button. Right now I am writing the command to make the pieces be able to move (which is executed when one is clicked) but it is telling me I am missing an argument (squareposition) when clicking.
How can I bind a value to each button within Game.movepiece ?
here is the code I used to create the buttons:
def drawboard(self):
x=0
y=0
for column in range(self.n):
self.changecolours()
x=x+1
y=0
for row in range(self.n):
y=y+1
colour = self.colours[self.colourindex]
position=(x,9-y)
buttons=(tk.Button(self.boardframe, padx=10, text=self.placepieces(position), bg=colour, borderwidth=2, relief="solid", font=self.piecefont, command=lambda:Game.movepiece(position) ))
buttons.grid(column=(x-1), row=(y-1), sticky="W"+"E"+"N"+"S" )
self.changecolours()
and here is the button's command function:
def movepiece(self, squareposition):
if self.square==(-10,-10):
self.square=squareposition
Game.movepiece(position) is calling the method at the class level, so position is used for the self parameter then squareposition is missing. You need to use an instance of Game to be able to call the method properly. Maybe you already instantiate it elsewhere in your code ?
Then as #Reblochon Masque said you can replace the command with command=lambda pos=position :self.movepiece(pos)
def __init__():
self.game = Game()
def drawboard(self):
[...]
position = (x,9-y)
buttons = tk.Button(self.boardframe, padx=10, text=self.placepieces(position),
bg=colour, borderwidth=2, relief="solid", font=self.piecefont,
command=lambda pos=position :self.movepiece(pos))

How to properly use and define attributes within a class. tkinter sticky grid of buttons that reacts to a function individually

I am trying to create a stretchy grid of buttons that change color when pressed. Using tkinter to create the grid, I think I am having issues with calling the correct root or formatting. Creating the resizing grid is not an issue, however getting the code to react to the function is providing me with problems.
Any push in the right direction will greatly be appreciated.
from tkinter import *
gx = 4
gy = 4
class trisector:
def __init__(self, master): #starts the index and root of function
Grid.rowconfigure(master, 0, weight=1) #
Grid.columnconfigure(master, 0, weight=1)
frame=Frame(master)
frame.grid(row=0,column=0,sticky=N+S+E+W)
for x in range(gx):
Grid.rowconfigure(frame, x , weight=1)
for y in range(gy):
Grid.columnconfigure(frame, y, weight=1)
self.btn = Button(frame, command=lambda widget=self.btn:
self.color_change(widget))
self.btn.grid(row=x, column=y, sticky=N+E+W+S)
self.btn.position=(x,y)
def color_change(self,widget):
x,y = widget.position
print("Changing", (x,y))
swidget.configure(bg="red")
root = Tk()
bob = trisector(root)
root.mainloop()
First you will need to split out the assignment of command to self.btn, since you're trying to pass the instance of the button itself:
self.btn = Button(frame)
self.btn['command'] = lambda widget=self.btn: self.color_change(widget)
And then fix the typo in color_change():
def color_change(self,widget):
x,y = widget.position
print("Changing", (x,y))
widget.configure(bg="red") # <-- change swidget to widget

How to use write a loop for list append

from Tkinter import *
import csv
root = Tk()
def click(event):
global x,y
x, y= event.x,event.y
frame = Frame(root, width=100, height=100)
frame.bind("<Button-1>", click)
frame.pack()
root.mainloop()
row=[]
col=[]
row.append(x)
col.append(y)
Please! How do I write a loop, so that the two list can contain all x, and y that I clicked.
There's no reason to use an explicit loop here, one is already provided by root.mainloop, which calls your handler for you on every click event. Writing:
from Tkinter import *
root = Tk()
row = []
col = []
def click(event):
row.append(event.x)
col.append(event.y)
frame = Frame(root, width=100, height=100)
frame.bind("<Button-1>", click)
frame.pack()
root.mainloop()
will leave row and col populated with all of the x and y coordinates from each click once root.mainloop completes. There's also no reason to make x and y global: their global values will just always hold the values from the last call to click (or give you an undefined variable error if you never clicked at all).
As it is, you are only appending x and y once. You can make the append happen on click event - no loop required!
from tkinter import *
import csv
root = Tk()
coords = []
def click(event):
global x,y
x, y= event.x,event.y
coords.append([x, y])
print("Clicked at: ", x, y)
frame = Frame(root, width=100, height=100)
frame.bind("<Button-1>", click)
frame.pack()
root.mainloop()

Array of buttons in python

I want to create a grid of buttons that will toggle colour when they are clicked. At the moment every button will trigger the bottom right button instead. Below is the code. Two questions, why is it doing this and how do I correct it?
def main(self):
root = Tk()
frame=Frame(root)
frame.grid(row=0,column=0)
self.btn= [[0 for x in xrange(20)] for x in xrange(60)]
for x in range(60):
for y in range(20):
self.btn[x][y] = Button(frame,command= lambda: self.color_change(x,y))
self.btn[x][y].grid(column=x, row=y)
root.mainloop()
def color_change(self,x,y):
self.btn[x][y].config(bg="red")
print x,y
I figured it out. Replace:
self.btn[x][y] = Button(frame,command= lambda: self.color_change(x,y))
With:
self.btn[x][y] = Button(frame,command= lambda x1=x, y1=y: self.color_change(x1,y1))
Sorry if this was a nuisance to any one.

how to find tags near to mouse click in tkinter python gui

How can i identify a tag near to mouse click. here my definition "identify" should identify tag very near to mouse click.
from Tkinter import *
root = Tk()
f=Frame(root)
f.grid()
w=Canvas(f)
line1=w.create_line(50,50,150,150, width=5, tags="line1")
line2=w.create_line(100,100,100,350, width=3, tags="line2")
line3=w.create_line(150,150,150,450, width=3, tags="lines")
w.grid(row=0, column=0)
w.bind("<Button-1>", identify)
def identify(event): ## this should identify the tag near to click
u=Frame(f)
u.grid(row=0, column=1)
root.mainloop()
Thanks
Use find_closest and gettags:
def identify(event):
item = w.find_closest(event.x, event.y)[0]
tags = w.gettags(item)
print tags
By the way, you have to define the function before you bind it to the event.
Canvas provides a bunch of find_* methods. Here, find_closest fit your need.
def identify(event):
closest = w.find_closest(event.x,event.y)[0]
Note that if you change the viewport of the canvas (pan, zoom...), you will have to convert from event coordinate to canvas coordinate
def callback(event):
canvas = event.widget
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)
print canvas.find_closest(x, y)
(copied from effbot.org)
You can directly get the item in the canvas and find its associated tags
def find_item(event):
item = canvas.find_withtag('current')[0]
print(canvas.gettags(item))

Categories