How to use write a loop for list append - python

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()

Related

Finding widgets in an array Tkinter

I am attempting to work with Tkinter, and the mouse events should change the text of the button clicked.
Through testing, this works with right click () and middle click (). However, (left click) uses a function, which should find the "coordinates" of the widget in the array (I need these numbers for later calculations). The bottom row of the grid works, but any other button leads to the bottom-right button being selected.
from tkinter import *
from random import *
win = Tk()
win.geometry("380x410")
win.grid()
buttons = []
def search(event):
for j in range(10):
for i in range(10):
#print(event.widget)
if buttons[j][i] == event.widget:
break
print(i,j)
buttons[j][i].config(text="1")
for y in range(10):
temp = []
for x in range(10):
button = Button(win,text="",width=4,height=2)
button.grid(row=y,column=x)
button.bind("<Button-1>",search)
button.bind("<Button-2>",lambda event: event.widget.config(text=""))
button.bind("<Button-3>",lambda event: event.widget.config(text="R"))
temp.append(button)
buttons.append(temp)
I have tried messing about with lambdas, but I believe the problem lies within the function.
Any help would be appreciated.
Question: Finding widgets in an array Tkinter
Simpler solution
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
for y in range(10):
for x in range(10):
button = tk.Button(self, text="", width=4, height=2)
button._coords = x, y
button.grid(row=y, column=x)
button.bind("<Button-1>", self.on_button_1_click)
def on_button_1_click(self, event):
print('on_button_1_click:{}'.format(event.widget._coords))
if __name__ == '__main__':
App().mainloop()
Maybe this is somewhat close to what you're looking for:
from tkinter import *
from random import *
win = Tk()
win.geometry("380x410")
win.grid()
buttons = []
def search(event):
i2 = 0
j2 = 0
for j in range(10):
for i in range(10):
#print(event.widget)
if buttons[j][i] == event.widget:
i2 = i
j2 = j
event.widget.config(text="1")
break
print(i2,j2)
#buttons[j][i].config(text="1")
for y in range(10):
temp = []
for x in range(10):
button = Button(win,text="",width=4,height=2)
button.grid(row=y,column=x)
button.bind("<Button-1>", lambda event: search(event))
button.bind("<Button-2>",lambda event: event.widget.config(text=""))
button.bind("<Button-3>",lambda event: event.widget.config(text="R"))
temp.append(button)
buttons.append(temp)
win.mainloop()
Are you sure you need coordinates or just the index of the Button in the buttons list?
If you just need to accurately interact with each button try using the index value in a lambda.
from tkinter import *
win = Tk()
win.geometry("380x410")
buttons = []
def search(btn, ndex):
if btn == '1':
buttons[ndex].config(text='1')
if btn == '2':
buttons[ndex].config(text='')
if btn == '3':
buttons[ndex].config(text='R')
for y in range(10):
for x in range(10):
buttons.append(Button(win, text="", width=4, height=2))
ndex = len(buttons) - 1
buttons[-1].bind("<Button-1>", lambda e, z=ndex: search('1', z))
buttons[-1].bind("<Button-2>", lambda e, z=ndex: search('2', z))
buttons[-1].bind("<Button-3>", lambda e, z=ndex: search('3', z))
buttons[-1].grid(row=y, column=x)
win.mainloop()

How to move a rectangle to the mouse position with Tkinter/Python?

I'm using Tkinter/Python's Canva class' coord() method to move a rectangle. What should I pass as paramters in order to make it work?
from tkinter import *
root = Tk()
def key(event):
print ("pressed", repr(event.char))
def callback(event):
position = (event.x,event.y)
event.widget.coords(item, position)
canvas= Canvas(root, width=100, height=100)
canvas.bind("<Key>", key)
canvas.bind("<Button-1>", callback)
item = canvas.create_rectangle(10,10,5,5)
canvas.pack()
move widget using mouse
from tkinter import *
import pyautogui
def on_move(event):
component=event.widget
locx, locy = component.winfo_x(), component.winfo_y()
w , h =master.winfo_width(),master.winfo_height()
mx ,my =component.winfo_width(),component.winfo_height()
xpos=(locx+event.x)-(15)
ypos=(locy+event.y)-int(my/2)
if xpos>=0 and ypos>=0 and w-abs(xpos)>=0 and h-abs(ypos)>=0 and xpos<=w-5 and ypos<=h-5:
component.place(x=xpos,y=ypos)
master = Tk()
master.geometry("%dx%d+0+0" % (500,500))
msg = Label(master, text = "Click & Move")
msg.config(bg='lightgreen', font=('times', 24, 'italic'))
msg.bind('<B1-Motion>',on_move)
msg.place(x=10,y=20)
mainloop()
This seems your first post. Welcome to SO :D
Updated answer: After some research and testing, it seems that you just need to pass the coordenates without the tuple. Storing x and y in a tuple is a problem, but also not providing the values for x2 and y2.
def callback(event):
event.widget.coords(item, event.x + 5, event.y + 5, event.x, event.y)
You can learn more here
Original wrong answer:
You can't move items on tk. Maybe try to clean the canvas and create the item at the new coordinates.
canvas.delete("all")
canvas.create_rectangle(event.x + 5,event.y + 5, position)

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 bind multiple mouse buttons to a widget?

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))

Scrolling through multiple labels in Tkinter

I am trying to make a simple application launcher using Tkinter ( for the games that I have made using pygame). The code for the same is below.It runs in full screen mode(without any maximize or minimize buttons).
import Tkinter as tk
from Tkinter import *
import random
import os
import subprocess
def call(event,x):
print "begin"
if x==0:
p = subprocess.Popen("python C:\Users\Akshay\Desktop\i.py")
p.wait()
print "end"
root = tk.Tk()
root.geometry("1368x768+30+30")
root.overrideredirect(True)
root.geometry("{0}x{1}+0+0".format(root.winfo_screenwidth(), root.winfo_screenheight()))
games = ['Game1','Game2','Game3','Game4','Game5','Game6','Game7','Game8']
labels = range(8)
for i in range(8):
ct = [random.randrange(256) for x in range(3)]
brightness = int(round(0.299*ct[0] + 0.587*ct[1] + 0.114*ct[2]))
ct_hex = "%02x%02x%02x" % tuple(ct)
bg_colour = '#' + "".join(ct_hex)
l = tk.Label(root,
text=games[i],
fg='White' if brightness < 120 else 'Black',
bg=bg_colour)
l.place(x = 320, y = 30 + i*150, width=700, height=100)
l.bind('<Button-1>', lambda event, arg=i: call(event, arg))
root.mainloop()
There is no issue with this piece of code but I want a scroll bar at the right side or a way to scroll/move down using the arrow keys so that if I add more number of labels , they also become visible.
I tried to understand some code snippets from the internet and read the Tkinter documentations as well but didn't understood anything. Also tried to follow one more stackoverflow discussion and understood about the frame and canvas methods.
Python Tkinter scrollbar for frame
Frame , canvas and all is getting a bit complicated. I just want to keep it simple.Can something be added to the code snippet above to make the scroll thing work and all the labels become visible?
Something like the above but with a scroll bar!!
Here is an MCVE of how to add a scrollbar to a tkinter app, hide the scrollbar, and scroll with the up/down arrows or the mouse wheel.
from tkinter import *
parent=Tk() # parent object
canvas = Canvas(parent, height=200) # a canvas in the parent object
frame = Frame(canvas) # a frame in the canvas
# a scrollbar in the parent
scrollbar = Scrollbar(parent, orient="vertical", command=canvas.yview)
# connect the canvas to the scrollbar
canvas.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side="right", fill="y") # comment out this line to hide the scrollbar
canvas.pack(side="left", fill="both", expand=True) # pack the canvas
# make the frame a window in the canvas
canvas.create_window((4,4), window=frame, anchor="nw", tags="frame")
# bind the frame to the scrollbar
frame.bind("<Configure>", lambda x: canvas.configure(scrollregion=canvas.bbox("all")))
parent.bind("<Down>", lambda x: canvas.yview_scroll(3, 'units')) # bind "Down" to scroll down
parent.bind("<Up>", lambda x: canvas.yview_scroll(-3, 'units')) # bind "Up" to scroll up
# bind the mousewheel to scroll up/down
parent.bind("<MouseWheel>", lambda x: canvas.yview_scroll(int(-1*(x.delta/40)), "units"))
labels = [Label(frame, text=str(i)) for i in range(20)] # make some Labels
for l in labels: l.pack() # pack them
parent.mainloop() # run program
This is a better answer to my question.Yes I know I can't make the scroll bars work properly but yes as I asked now through this code one can move down/scroll via arrow keys without a scroll bar actually being there. This is the way I used to make menu for my pygame made games and the same technique I applied here.It works but only in fullscreen mode.
import Tkinter as tk
from Tkinter import *
import random
import os
import subprocess
class stat:
j=0
def call(event,x):
print "begin"
if x==0:
p = subprocess.Popen("python C:\Users\Akshay\Desktop\i.py")
p.wait()
print "end"
def OnEntryDown(event):
stat.j=stat.j+1
print stat.j
xmain()
def OnEntryUp(event):
stat.j=stat.j-1
print stat.j
xmain()
def xmain():
root = tk.Tk()
root.geometry("1368x768+30+30")
root.overrideredirect(True)
root.geometry("{0}x{1}+0+0".format(root.winfo_screenwidth(), root.winfo_screenheight()))
root.bind("<Down>", OnEntryDown)
root.bind("<Up>", OnEntryUp)
languages = ['Game1','Game2','Game3','Game4','Game5','Game6','Game7','Game8']
labels = range(8)
k=0
print stat.j
for i in range(stat.j,stat.j+5):
ct = [random.randrange(256) for x in range(3)]
brightness = int(round(0.299*ct[0] + 0.587*ct[1] + 0.114*ct[2]))
ct_hex = "%02x%02x%02x" % tuple(ct)
bg_colour = '#' + "".join(ct_hex)
l = tk.Label(root,
text=languages[i],
fg='White' if brightness < 120 else 'Black',
bg=bg_colour)
l.place(x = 320, y = 30 + k*150, width=700, height=100)
l.bind('<Button-1>', lambda event, arg=stat.j: call(event, arg))
k=k+1
root.mainloop()
xmain()

Categories