I want to be able to select a button based on what row and column it is in on a grid and the button and control its Text and Relief. I haven't been able to find anything on widgets or cells used in this manner.
Edit:
I changed where root is placed and now it says that I can't use a tuple that I recieved for 'relief' which makes sense, I need to access the widget itself. Any reccomendations
import tkinter
import functools
import random
from time import sleep
width = input('Enter the grid width. ')
height = input('Enter the grid height. ')
numb = input('Enter the number of bombs. ')
Matrix = [[0 for lp in range(int(width))] for fg in range(int(height))]
def ranintx():
return random.randint(0,int(width))
def raninty():
return random.randint(0,int(height))
def placemines():
y = ranintx()
x = raninty()
for ranintformine in range(int(numb)):
x = ranintx()
y = raninty()
Matrix[y-1][x-1] = 1
placemines()
def sunken(event, self, x, y):
button = event.widget
button['relief'] = 'sunken'
if x - 1 < 0 :
return
if x > int(width) + 1 :
return
if y - 1 < 0 :
return
if y > int(height) + 1 :
return
if Matrix[x][y] == 1 :
top = tkinter.Toplevel()
top.title("About this application...")
msg = tkinter.Message(top, text="You Lose")
msg.pack()
button = tkinter.Button(top, text="Dismiss", command=top.destroy)
button.pack()
print('Column = {}\nRow = {}'.format(x, y))
else:
n1 = x - 1
n2 = y - 1
for lp in range(3):
for lp2 in range(3):
abutton = root.grid_location(n1, n2)
abutton['relief'] = ['sunken']
# I want to be able to change and select the button here. This was one of my poor attempt
n2 =+ 1
n1 =+ 1
def push(event, self, x, y):
button = event.widget
if Matrix[x][y] == 1 :
print('Column = {}\nRow = {}'.format(x, y))
class MineSweep(tkinter.Frame):
#classmethod
def main(cls, width, height):
window = cls(root, width, height)
'''placemine()'''
root.mainloop()
def __init__(self, master, width, height):
super().__init__(master)
self.__width = width
self.__height = height
self.__build_buttons()
self.grid()
#def sunken(event):
# button = event.widget
# button['relief'] = 'sunken'
def __build_buttons(self):
self.__buttons = []
for y in range(self.__height):
row = []
for x in range(self.__width):
button = tkinter.Button(self, state='disabled')
button.grid(column=x, row=y)
button['text'] = ' '
print(grid.slaves)
self.checked = True
#button['command'] = functools.partial(self.__push, x, y)
button.bind("<Button-3>",
lambda event, arg=x, brg=y: push(event, self, arg, brg))
button['relief'] = 'raised'
button.bind("<Button-1>",
lambda event, arg=x, brg=y: sunken(event, self, arg, brg))
#button['command'] = sunken
row.append(button)
self.__buttons.append(row)
root = tkinter.Tk()
if __name__ == '__main__':
MineSweep.main(int(width), int(height))
You have a few things wrong with your program. First, sunken should be a method on the class. It's very weird to have it outside the class, and then you pass in self as some other argument. It works, but it makes the code very confusing.
That being said, you're actually very close to making this work. You're already saving a reference to each button in a list of lists, so you should be able to get the widget with self.__buttons[y][x]. However, because sunken is not part of the class, and because you named the variable with two underscores, the variable is not accessible to the sunken function.
If you change the variable to have a single underscore instead of a double, your code should work more-or-less exactly as it is (once you fix the syntax and indentation errors). The other solution is to make sunken a method on the class and fix how you call it (remove the self argument, call it as self.sunken), it will work with two underscores.
Frankly, using two underscores has zero practical benefit. Avoid the temptation to use it. At the very least, don't use it until you have your basic logic working, then you can go back and hide attributes you don't want to be exposed.
Related
Im working with Tkinter currently and im trying to make an draggable canvas image, the code i've "made"/edited from another stack overflow question, the second one to be particular. There code works for me when im using tk.Frame(), but it gives an error for Canvas.create_image(). So i edited it a little but now it seems to to be moving the image at all when i drag it
My code:
from tkinter import *
import pyautogui
x,y=pyautogui.size()
tk = Tk()
c = Canvas(tk, width=x, height=y)
c.place(x=-2,y=-3)
img = ImageTk.PhotoImage(PIL.Image.open(r"Data\backgrounds\background.jpg"))
c.create_image(0, 0, image=img, anchor=NW)
def command6():
print("command6")
def make_draggable(widget,btn="<Button-1>",motion="<B1-Motion>"):
def __draggable__(widget):
c.tag_bind(btn,btn,on_drag_start)
c.tag_bind(motion,motion,on_drag_motion)
def on_drag_start(event):
widget = event.widget
widget._drag_start_x = event.x
widget._drag_start_y = event.y
def on_drag_motion(event):
widget = event.widget
x = widget.winfo_x() - widget._drag_start_x + event.x
y = widget.winfo_y() - widget._drag_start_y + event.y
widget.move(widget,x, y)
__draggable__(widget)
APP_6 = r'apps\File.png'
APP_6 = PIL.Image.open(APP_6)
APP_6 = APP_6.resize((48,48),PIL.Image.ANTIALIAS)
APP_6 = ImageTk.PhotoImage(APP_6)
image_6 = ImageTk.PhotoImage(PIL.Image.open(r"apps\File.png"))
image_id_6 = c.create_image(48,48, image=APP_6)
c.move(image_id_6, 1,y-735)
c.tag_bind(image_id_6, '<Button-1>',command6)
make_draggable(image_id_6)
tk.mainloop()
this gives no errors or any unwanted output in the console.
There are few issues inside make_draggable() function:
first argument of .tag_bind() is the item ID of a canvas item. For your case, it is widget argument of make_draggable(). So the following lines:
c.tag_bind(btn,btn,on_drag_start)
c.tag_bind(motion,motion,on_drag_motion)
should be changed to
c.tag_bind(widget, btn, on_drag_start)
c.tag_bind(widget, motion, on_drag_motion)
Same apply to c.move(...) inside on_drag_motion()
the logic/calculation on moving the canvas item is wrong
Below is the modified make_draggable() function:
def make_draggable(widget, btn="<Button-1>", motion="<B1-Motion>"):
def __draggable__(widget):
c.tag_bind(widget, btn, on_drag_start)
c.tag_bind(widget, motion, on_drag_motion)
c._item_id = widget # save the item ID for later use
def on_drag_start(event):
widget = event.widget
# get the top-left coordinates of the selected item
x, y, *_ = widget.bbox(widget._item_id)
# save the offset of current mouse position from the top-left coordinates
widget._dx = event.x - x
widget._dy = event.y - y
def on_drag_motion(event):
widget = event.widget
# calculate the top-left coordinates of the item that the item to be moved to
x = event.x - widget._dx
y = event.y - widget._dy
# move the item using moveto() instead of move()
widget.moveto(widget._item_id, x, y)
__draggable__(widget)
As the above logic applies only on the item of the last call of make_draggable(). It is better to use class instead of function:
class make_draggable():
def __init__(self, item_id, btn="<Button-1>", motion="<B1-Motion>"):
self.item_id = item_id
c.tag_bind(item_id, btn, self.on_drag_start, add=True)
c.tag_bind(item_id, motion, self.on_drag_motion, add=True)
def on_drag_start(self, event):
x, y, *_ = event.widget.bbox(self.item_id)
self.dx, self.dy = event.x-x, event.y-y
def on_drag_motion(self, event):
event.widget.moveto(self.item_id, event.x-self.dx, event.y-self.dy)
I'm adding tooltips to my program, they should appear if mouse is on the widget more than 1 seconds. But there is a problem that tooltip always appears when mouse simply passes over the widget. I mean they should appear if mouse remains on the widget more than 1 seconds but they also appear when mouse doesn't remains on the widget.
So I decided to add some lines to code that delays 1 seconds when mouse enters the widget and checks if mouse is still on the widget. If mouse is still there, then makes tooltip appear. But I don't know how to check if mouse is on a widget. I've tried widget.focus_get() but it simply gives a dot for output. Which is also gives a dot if mouse wasn't there. So this is useless for me. I've done lot's of research but I wasn't able to find something about this.
I am using Python 3.7.9 and tkinter.ttk
I was copied the code from here and modified a little bit to fade-in and fade-out animations. Here is my code:
label = Label(root, text="Label")
class ToolTip(object):
def __init__(self, widget):
self.widget = widget
self.tipwindow = None
self.id = None
self.x = self.y = 0
def showtip(self, text, widget):
global tw
self.text = text
if self.tipwindow or not self.text:
return
x, y, cx, cy = self.widget.bbox("insert")
x = x + self.widget.winfo_rootx() + 20
y = y + cy + self.widget.winfo_rooty() +20
self.tipwindow = tw = Toplevel(self.widget)
tw.wm_overrideredirect(1)
tw.wm_geometry("+%d+%d" % (x, y))
tw.attributes("-alpha", 0)
label = Label(tw, text=self.text, justify=LEFT, relief=SOLID, borderwidth=1)
label.pack(ipadx=1)
def fade_in():
alpha = tw.attributes("-alpha")
if alpha < root.attributes("-alpha"):
alpha += .1
tw.attributes("-alpha", alpha)
tw.after(10, fade_in)
elif alpha == root.attributes("-alpha"):
tw.attributes("-alpha", root.attributes("-alpha"))
try:
tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w, "help", "noActivates")
except TclError:
pass
fade_in()
def hidetip(self, widget):
tw = self.tipwindow
self.tipwindow = None
def fade_away():
alpha = tw.attributes("-alpha")
if alpha > 0:
alpha -= .1
tw.attributes("-alpha", alpha)
tw.after(10, fade_away)
else:
tw.destroy()
fade_away()
def createToolTip(widget, text):
toolTip = ToolTip(widget)
def enter(event):
time.sleep(1000) #Wait 1 second
if widget.focus_get() == True: #Check if mouse is still on the widget. But not working.
toolTip.showtip(text, widget)
def leave(event):
ToolTipActive = False
toolTip.hidetip(widget)
widget.bind('<Enter>', enter)
widget.bind('<Leave>', leave)
createToolTip(label, "This is a tooltip")
I don't know your goal. You can make a tooltip/ hovertip by yourself.
if you want to make it for yourself, you need to use bind when hovering. Also you can use this:
from idlelib.tooltip import Hovertip
mytip = Hovertip(self, "Info")
Edit for binding: (there are different ways)
from tkinter import *
root = Tk()
root.geometry("400x400")
def hover_this_enter(event): # on enter
hover_lbl.place_configure(x=100, y=170)
hover_lbl.after(1000) #after method (you can change)
def hover_this_leave(event): # if you want destroy, make sure you get this item back, or you get attribute errors
hover_lbl.place_configure(x=-200)
btn = Button(root, text="give me tooltips")
btn.pack(side="left")
btn.bind("<Enter>", hover_this_enter)
btn.bind("<Leave>", hover_this_leave)
hover_lbl = Label(root, text="i was hovered", bg="black", fg="white")
if __name__ == '__main__':
root.mainloop()
I am (still!) writing a Noughts and Crosses program using Tkinter in Python 3.
I wanted to implement a short pause between the player's move and the computer's move, so in the add_move_comp() method implemented self.after() function.
I expected this to pause the program for 1000ms then continue by 'drawing' on the computer's move.
However when I run my code, the program only recognises the computer's move the next move after, causing problems with identifying a 3-in-a-row.
I think this is due to line 62 running after 1000ms while the rest of the program continues running, but I don't know how to stop the whole program and continue running with line 62 after the pause.
from tkinter import *
from functools import partial
from itertools import *
import random
class Window(Frame):
def __init__(self, master = None): # init Window class
Frame.__init__(self, master) # init Frame class
self.master = master # allows us to refer to root as master
self.rows = 3
self.columns = 3
self.guiGrid = [[None for x in range(self.rows)] for y in range(self.columns)] # use this for the computer's moves
self.noText = StringVar(value = '')
self.cross = StringVar(value = 'X')
self.nought = StringVar(value = 'O')
self.button_ij = None
self.myMove = True
self.create_window()
self.add_buttons()
def create_window(self):
self.master.title('Tic Tac Toe')
self.pack(fill = BOTH, expand = 1)
for i in range(0,3): # allows buttons to expand to frame size
self.grid_columnconfigure(i, weight = 1)
self.grid_rowconfigure(i, weight = 1)
def add_buttons(self):
rows = 3
columns = 3
for i in range (rows):
for j in range(columns):
self.button_ij = Button(self, textvariable = self.noText, command = lambda i=i, j=j: self.add_move(i,j))
self.guiGrid[i][j] = self.button_ij
self.button_ij.grid(row = i,column = j, sticky =E+W+S+N)
def add_move(self, i,j):
# player's move
while self.myMove:
pressedButton = self.guiGrid[i][j]
self.guiGrid[i][j].config(textvariable = self.cross)
# computer's turn
self.myMove = False
while (self.myMove == False):
self.add_move_comp()
def add_move_comp(self):
repeat = True
while repeat:
i = random.randint(0,0) # row - only allow O to be drawn on 1st row for testing purposes
j = random.randint(0,2) # column
testText = self.guiGrid[i][j].cget('text')
if testText == '':
self.after(1000,lambda i = i, j = j :self.guiGrid[i][j].config(textvariable = self.nought)) # search up rules with returning values using lambda
print('Should plot O at row: ',i,' column: ',j)
print('TEXT ACTUALLY PLOTTED IS: ',self.guiGrid[i][j].cget('text'))
self.myMove = True
repeat = False
print(self.guiGrid[0][0].cget('text'), self.guiGrid[0][1].cget('text'), self.guiGrid[0][2].cget('text')+'THIS IS PRINTING')
root = Tk() # creating Tk instance
rootWidth = '500'
rootHeight = '500'
root.geometry(rootWidth+'x'+rootHeight)
ticTacToe = Window(root) # creating Window object with root as master
root.mainloop() # keeps program running
This is due to the fact that self.after imeadiately returns and starts the given function after passing trough a queque to prevent the actual Window from beeing unable to responde because there is some code running. A way to work around this is to create a BooleanVariable for validation and using self.wait_variable as follows:
from tkinter import *
from functools import partial
from itertools import *
import random
class Window(Frame):
def __init__(self, master = None): # init Window class
Frame.__init__(self, master) # init Frame class
self.master = master # allows us to refer to root as master
self.rows = 3
self.columns = 3
self.guiGrid = [[None for x in range(self.rows)] for y in range(self.columns)] # use this for the computer's moves
self.noText = StringVar(value = '')
self.cross = StringVar(value = 'X')
self.nought = StringVar(value = 'O')
self.button_ij = None
self.myMove = True
self.validationVar = BooleanVar(self)
self.create_window()
self.add_buttons()
def create_window(self):
self.master.title('Tic Tac Toe')
self.pack(fill = BOTH, expand = 1)
for i in range(0,3): # allows buttons to expand to frame size
self.grid_columnconfigure(i, weight = 1)
self.grid_rowconfigure(i, weight = 1)
def add_buttons(self):
rows = 3
columns = 3
for i in range (rows):
for j in range(columns):
self.button_ij = Button(self, textvariable = self.noText, command = lambda i=i, j=j: self.add_move(i,j))
self.guiGrid[i][j] = self.button_ij
self.button_ij.grid(row = i,column = j, sticky =E+W+S+N)
def add_move(self, i,j):
# player's move
while self.myMove:
pressedButton = self.guiGrid[i][j]
self.guiGrid[i][j].config(textvariable = self.cross)
# computer's turn
self.myMove = False
while (self.myMove == False):
self.add_move_comp()
def add_move_comp(self):
repeat = True
while repeat:
i = random.randint(0,0) # row - only allow O to be drawn on 1st row for testing purposes
j = random.randint(0,2) # column
testText = self.guiGrid[i][j].cget('text')
if testText == '':
self.after(1000, self.validationVar.set, True)
self.wait_variable(self.validationVar)
self.guiGrid[i][j].config(textvariable = self.nought) # search up rules with returning values using lambda
print('Should plot O at row: ',i,' column: ',j)
print('TEXT ACTUALLY PLOTTED IS: ',self.guiGrid[i][j].cget('text'))
self.myMove = True
repeat = False
print(self.guiGrid[0][0].cget('text'), self.guiGrid[0][1].cget('text'), self.guiGrid[0][2].cget('text')+'THIS IS PRINTING')
root = Tk() # creating Tk instance
rootWidth = '500'
rootHeight = '500'
root.geometry(rootWidth+'x'+rootHeight)
ticTacToe = Window(root) # creating Window object with root as master
root.mainloop() # keeps program running
I've only recently dipped my toes into python (only ever coded in java and JS) and thought I would try my hand at making a simple number pad GUI. I'm still getting used to the indentation format.
I've applied proper indenting and fixed all typos and syntax errors but still receive the following error
"Traceback (most recent call last):
File "/home/pi/Desktop/Lab Work/Lab 1/Number Pad test GUI.py", line 4, in
class BaseWindow(tkinter.Tk):
File "/home/pi/Desktop/Lab Work/Lab 1/Number Pad test GUI.py", line 8, in BaseWindow
self.minsize (x,y)
NameError: name 'self' is not defined"
I have updated the code below to my latest version also
import tkinter, tkinter.ttk as ttk
import random
class BaseWindow(tkinter.Tk):
def _Change (self):
x,y = self.winfo_width(), self.winfo_height()
self.minsize (x, y); self.maxsize(x, y)
#This locks window size when called
def FgridFormatButtons (self, ButtonList, NewLineAmount = 3):
self.Row = 0
self.Col = 0
for Button in ButtonList:
Button.grid(row = self.Row, column = self.Col)
self.Col += 1
if self.Col == NewLineAmount:
self.Row += 1
self.Col = 0
continue
class Window (BaseWindow):
def __init__(self, **args):
super(Window, self).__init__()
#Main method code
self.EntryFrame = ttk.Frame(self)
self.PadFrame = ttk.Frame(self)
self.EntryFrame.pack(padx = 5, pady = 5)
self.PadFrame.pack(padx = 5, pady = 5)
self.AllButtons = []
self.CanWrite = true
self.Cod = args.get("Code") or random.randrange(9999)
self.Timer = args.get("Timer") or 2000
print ("debug %d"% self.Code)
for x in range (1,10):
self.AllButtons.append(ttk.Button(self.PadFrame, width = 4, text = x, command = lambda y = x: self.Update(x)))
self.bind(str(x), lambda CatchEvent, y = x: self.Update(y))
self.FGridFormatButtons(self.AllButtons)
self.ZeroButton = ttk.Button (self.PadFrame, width = 4, text = 0, command = lambda: self.Update(0))
self.SubmitButton = ttk.Button(self.PadFrame, width = 4, text = "Ent", command = self.CheckCode)
self.ClearButton = ttk.Button(self.PadFrame, width = 4, text = "C", command = lambda: self.Update(-1))
self.ClearButton.grid(row = self.Row, column = 0)
self.ZeroButton.grid(row = self.Row, column = 1)
self.SubmitButton.grid(row = self.Row, column = 2)
self.bind ("0", lambda CatchEvent: self.Update(0))
self.bind("<return>", lambda CatchEvent: self.CheckCode())
self.KeyEnter = ttk.Entry(self,EntryFrame, state ="disabled")
self.KeyEnter.pack
#--
self.after (5, self._Change)
#This will wait 5 miliseconds and then lock the window
#If your computer takes longer than 5 miliseconds to load then kill yourself. Or alternatively, change the last value to match how long it takes
def Update (self, x):
if self.CanWrite:
self.KeyEnter["state"] = "normal"
if x == 1:
self.KeyEnter.delete(0, tkinter.END)
else:
self.KeyEnter.insert(tkinter.END, x)
self.KeyEnter["state"] = 'disabled'
def CheckCode(self):
Key = self.KeyEnter.get()
self.Update(-1)
if Key == str(self.Code):
self.Update("Correct Code!")
self.after(self.Timer, self.destroy)
else:
self.Update("Incorrect code")
self.ChangeWritePerms()
self.after(self.Timer, self.ChangeWritePerms)
def ChangeWritePerms(self):
if self.CanWrite:
self.CanWrite = False
else:
self.CanWrite = True
self.Update(-1)
window().mainloop()
class BaseWindow(tkinter.Tk):
def _change (self):
x,y = self.winfo_width(), self.winfo_height()
self.minimize (x,y)
#This locks window size when called
def FgridFormatButtons (self, ButtonList, NewLineAmount = 3):
self.Row = 0
self.Col = 0
for Button in ButtonList:
Button.grid(row = self.Row, column = self.Col)
self.Col += 1
if self.Col == NewLineAmount:
self.Row += 1
self.Col = 0
continue
class Window (BaseWindow):
def __init__(self, **args):
super(Window, self).__init__()
#Main method code
self.EntryFrame = ttk.Frame(self)
self.PadFrame = ttk.Frame(self)
self.EntryFrame.pack(padx = 5, pady = 5)
self.PadFrame.pack(padx = 5, pady = 5)
self.AllButtons = []
self.CanWrite = true
self.Cod = args.get("Code") or random.randrange(9999)
self.Timer = args.get("Timer") or 2000
print ("debug %d"% self.Code)
for x in range (1,10):
self.AllButtons.append(ttk.Button(self.PadFrame, width = 4, text = x, command = lambda y = x: self.Update(x)))
self.bind(str(x), lambda CatchEvent, y = x: self.Update(y))
self.FGridFormatButtons(self.AllButtons)
self.ZeroButton = ttk.Button (self.PadFrame, width = 4, text = 0, command = lambda: self.Update(0))
self.SubmitButton = ttk.Button(self.PadFrame, width = 4, text = "Ent", command = self.CheckCode)
self.ClearButton = ttk.Button(self.PadFrame, width = 4, text = "C", command = lambda: self.Update(-1))
self.ClearButton.grid(row = self.Row, column = 0)
self.ZeroButton.grid(row = self.Row, column = 1)
self.SubmitButton.grid(row = self.Row, column = 2)
self.bind ("0", lambda CatchEvent: self.Update(0))
self.bind("<return>", lambda CatchEvent: self.CheckCode())
self.KeyEnter = ttk.Entry(self,EntryFrame, state ="disabled")
self.KeyEnter.pack
#--
self.after (5, self._Change)
#This will wait 5 miliseconds and then lock the window
#If your computer takes longer than 5 miliseconds to load then kill yourself. Or alternatively, change the last value to match how long it takes
def Update (self, x):
if self.CanWrite:
self.KeyEnter["state"] = "normal"
if x == 1:
self.KeyEnter.delete(0, tkinter.END)
else:
self.KeyEnter.insert(tkinter.END, x)
self.KeyEnter["state"] = 'disabled'
def CheckCode(self):
Key = self.KeyEnter.get()
self.Update(-1)
if Key == str(self.Code):
self.Update("Correct Code!")
self.after(self.Timer, self.destroy)
else:
self.Update("Incorrect code")
self.ChangeWritePerms()
self.after(self.Timer, self.ChangeWritePerms)
def ChangeWritePerms(self):
if self.CanWrite:
self.CanWrite = False
else:
self.CanWrite = True
self.Update(-1)
window().mainloop()
It seems like you change your question.
Try to change tkinter.tk into tkinter.Tk with big T.
This error shows that you forgot to put comma before lambda function.
"line 60 self.bind("" lambda CatchEvent: self.CheckCode()) ^SyntaxError: invalid syntax"
Have you tried to add comma ?
Check line 5 and 110 you forget space after def and colon at the end function argument.
Check line 86 too, you defined key as Key in line 82, so you have to call it Key with big K in line 86.
Check line 88, it shows self.;after. Please delete the semicolon to avoid syntax error too.
What is the text editor you are using ? If you use vscode, it will show the error with red underline.
include "self.minsize (x, y); self.maxsize(x, y)" inside the function
any statement inside the class must be inside a function
Ex: import tkinter, tkinter.ttk as ttk
import random
class BaseWindow(tkinter.Tk):
def _Change (self):
x,y = self.winfo_width(), self.winfo_height()
self.minsize (x, y); self.maxsize(x, y)
I have a problem using the bind option so I can click a button in my keyboard,
and call a function once the key is pressed.
I tried taking other codes that have the similar purpose and I saw that I'm doing pretty much the same, though I still have some problem I must've missed.
I will be very thankful if you help me with this.
Here's my code:
# -*- coding: utf-8 -*-
#Imports
from Tkinter import *
from PIL import ImageTk, Image
import time
import tkMessageBox
#===========================================================================================================================================#
#Tkinter Class
class App(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
#===========================================================================================================================================#
#Game Pieces Classes
class Board:
def __init__(self, rows = 7, columns = 6, picture_height = None, picture_width = None):
self.rows = rows
self.columns = columns
self.picture = ImageTk.PhotoImage(Image.open(r"C:\Users\Ariel\Desktop\Python\4inarow.gif"))
self.picture_height = self.picture.height()
self.picture_width = self.picture.width()
def create_and_pack(self, canvas):
board_item = canvas.create_image(700, 370, image = self.picture)
def __str__(self):
print "Rows:", self.rows, "Columns:", self.columns
class Disk:
def __init__(self, player_number = None):
self.picture = ImageTk.PhotoImage(Image.open(r"C:\Users\Ariel\Desktop\Python\me" + str(player_number) + ".gif"))
self.player_number = player_number
def create_and_pack(self, canvas, x, y):
disk_item = canvas.create_image(x, y, image = self.picture)
def get_x_parameter(self, number):
#X growing by 70~73 per number
x = 330
for i in range(7):
if number == i:
x = x + i * 72
return x
def get_y_parameter(self, number):
#Y lowered by 70~73 per number
y = 635
for i in range(6):
if number == i:
y = y - i * 72
return y
def place(self, canvas, x, y):
#First left down circle parameters
#480, 635
canvas.move(self.picture, x, y)
def __str__(self):
print "The disk's picture string:", self.picture, "The player disk's number:", self.player_number
#===========================================================================================================================================#
#Game Class
class Game:
def __init__(self, board = None, disk1 = None, disk2 = None):
self.disk1 = disk1
self.disk2 = disk2
self.board = board
#===========================================================================================================================================#
#KeyboardClass
class Keyboard:
def __init__(self, key_number = None):
self.key_number = key_number
def press_and_place(self, canvas, number, function):
canvas.focus_set()
canvas.bind("<" + str(number) + ">", function)
#===========================================================================================================================================#
#Main.
myapp = App()
myapp.master.title("4 in a Row")
myapp.master.maxsize(2000, 1200)
#---------------------------------------------------------------------------------------------------#
GameBoard = Board(7, 6)
FirstPlayerDisk = Disk(1)
SecondPlayerDisk = Disk(2)
GameClass = Game(GameBoard, FirstPlayerDisk, SecondPlayerDisk)
#---------------------------------------------------------------------------------------------------#
#Creating Canvas and placing the disks and the board.
board_canvas = Canvas(width = GameBoard.picture_width, height = GameBoard.picture_height)
board_canvas.pack(expand=1, fill=BOTH)
GameBoard.create_and_pack(board_canvas)
FirstPlayerDisk.create_and_pack(board_canvas, 330, 635)
SecondPlayerDisk.create_and_pack(board_canvas, 260, 635)
#---------------------------------------------------------------------------------------------------#
#Creating Keyboard instance and placing the first disk in the last row in a column of choice
number_choice = 3
KeyboardClass = Keyboard(number_choice)
first_player_x = FirstPlayerDisk.get_x_parameter(number_choice)
first_player_y = FirstPlayerDisk.get_y_parameter(number_choice)
KeyboardClass.press_and_place(board_canvas, number_choice, FirstPlayerDisk.place(board_canvas, first_player_x, first_player_y))
#---------------------------------------------------------------------------------------------------#
myapp.mainloop()
Thanks a lot in advance.
I believe your problem lies in this line:
KeyboardClass.press_and_place(board_canvas, number_choice, FirstPlayerDisk.place(board_canvas, first_player_x, first_player_y))
the third argument FirstPlayerDisk.place(board_canvas, first_player_x, first_player_y) is actually a None type as
def place(self, canvas, x, y):
#First left down circle parameters
#480, 635
canvas.move(self.picture, x, y)
returns None
From How to bind a keypress to a button in Tkinter and this site, you need to pass the function, that is, simply FirstPlayerDisk.place (no parenthesis following it).