Making Tkinter Photoimage crashes python program - python

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.

Related

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.

Tkinter - modifying buttons based on rows and columns

I want to change the colour of a button based on its row and column. I am able to search for adjacent buttons, but cant do anything with them. The code is a python version of the board game Othello, and I am trying to get the "sandwiching" aspect of the game to run. Ideally, it stays in the grid system so I am able to code to my ability
from tkinter import *
### Function to change button colour ###
def changeColour(tempButton, row, column):
if tempButton.cget("bg") == "black":
tempButton.configure (bg = "white")
else:
tempButton.configure (bg = "black")
sandwichButton(tempButton, row, column)
### Function to sandwich adjacent buttons ###
def sandwichButton(originButton, row, column):
for x in range (-1,2,1):
for y in range (-1,2,1):
aRow = (row + y)
aColumn = (column + x)
adjacentInfo = find_position(othello, aRow, aColumn)
endButtonInfo = find_position(othello, aRow + y, aColumn + x)
if adjacentInfo["row"] == (aRow) and adjacentInfo["column"] == (aColumn):
adjacentButton = ADJACENT INFORMATION
if endButtonInfo["row"] == (aRow + y) and endButtonInfo["column"] == (aColumn+x):
if originButton.cget("bg") == "black":
adjacentButton.configure (bg = "white")
else:
adjacentButton.configure (bg = "black")
### Function to find button position ###
def find_position(frame, row, column):
for children in frame.children.values():
info = children.grid_info()
if info["row"] == row and info["column"] == column:
return info
break
### Creating the window ###
othello = Tk()
othello.title("Othello Draft 1")
othello.geometry("800x800")
### Creating buttons ###
for r in range (8): #Rows
for c in range(8): #Columns
button = Button(othello, width = 10, height = 5)
button.grid(row = r, column = c)
button.configure (bg = "green", command = lambda buttonName = button, r = r, c = c: changeColour(buttonName, r, c))
### Running the window ###
othello.mainloop()
You could add the buttons to a list and use an if and elif statement to configure the buttons and input your conditions into the if.
for button in [list your buttons here]
if condition:
button.config(command=command(), bg=colour)
elif condition:
button.config(command=command2(), bg=colour2)

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.

Stop text from overlapping in Tkinter canvas

I am creating a game in the tkinter canvas which involves generating text (1 or 2 digit numbers) and I've gotten that to work, but I can't work out how to display them so they don't overlap. At the moment I have this:
import tkinter as tk
from tkinter import font
import random
BOX_SIZE = 300
class Game(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.config(bg = "white")
self.numBox = tk.Canvas(self, height = BOX_SIZE, width = BOX_SIZE , bg = "white", highlightthickness = 0)
self.numBox.pack(expand = True)
self.score = 0
self.numberSpawn()
def placeNumber(self, value):
validSpawn = False
attempts = 0
maxAttempt = False
while not validSpawn and not maxAttempt:
attempts += 1
if attempts > 20:
maxAttempt = True
attempts = 0
size = random.choice([24,36,48,72])
coord = [random.randint(40,BOX_SIZE - 40) for x in range(2)]
self.numBox.update()
pxSize = tk.font.Font(size = size, family = "Times New Roman").measure(value)
if len(str(value)) == 1:
secondCoords = [coord[0] + pxSize *2.5 , coord[1] + pxSize]
else:
secondCoords = [x + pxSize for x in coord]
if not self.numBox.find_overlapping(*coord, *secondCoords):
validSpawn = True
if not maxAttempt:
newTxt = self.numBox.create_text(*coord, font = ("Times New Roman",size), text = value)
def numberSpawn(self):
self.maxNum = random.randint(3,19)
self.placeNumber(self.maxNum)
for i in range(random.randint(4, 16)):
num = random.randint(0, self.maxNum-1)
self.placeNumber(num)
app = Game()
app.mainloop()
value is the number to be displayed, BOX_SIZE is the dimensions of the canvas. I tried using this to stop the text overlapping and this to find the pixel size of the text before creating it. Despite this, the text still overlaps like this:
I'm not sure how to fix this, or why it doesn't work as it is. Any help is appreciated.
Here is a solution for you:
import tkinter as tk
from tkinter import font
import random
def checkOverlap(R1, R2):
if (R1[0]>=R2[2]) or (R1[2]<=R2[0]) or (R1[3]<=R2[1]) or (R1[1]>=R2[3]):
return False
else:
return True
def go():
validSpawn = False
while not validSpawn:
value = random.randint(1,99)
size = random.choice([24,36,48,72])
coord = [random.randint(40,500 - 40) for x in range(2)]
new_number = canvas.create_text(*coord, font = ("Times New Roman",size),text=value)
new_box = canvas.bbox(new_number)
canvas.itemconfigure(new_number, state='hidden')
validSpawn = True
for i in canvas.items:
this_box = canvas.bbox(i)
if checkOverlap(this_box, new_box):
validSpawn = False
break
canvas.itemconfigure(new_number, state='normal')
canvas.items.append(new_number)
root = tk.Tk()
canvas = tk.Canvas(root, width = 500, height = 500, bg='white')
canvas.items = []
canvas.pack()
btn = tk.Button(root, text="Go", command=go)
btn.pack()
root.mainloop()
Instead of having it try to figure out how big the item was going to be, I just had it draw it, take its measurements, hide it and then look for overlaps and either delete it or show it based on the results. You will need to add in your maximum tries in there or it does start to get slower the more numbers there are on the screen. It should not draw a frame in the middle of a function so the user will never see it there while it is taking the measurement.
I also had it keep an array of all the number that are saved to the screen so I can loop through them and run my own overlapping function. That's just how I like to do it, you can go back to using find_overlapping and it should still work.
I think the problem is that:
you are giving up too soon, and
when you hit your limit of attempts, you add the text whether it overlaps or not
You should bump the number of attempts up considerably (maybe a few hundred), and then if the number exceeds the maximum then you shouldn't draw the text.
I think a better strategy might be to first draw the text item, then use the bbox of the method to compute the actual amount of space taken up by the item. Then, use that to find overlapping items. The just-created item will always overlap, but if the number of overlapping is greater than 1, pick new random coordinates.
For example, something like this perhaps:
def placeNumber(self, value):
size = random.choice([24,36,48,72])
coord = [random.randint(40,BOX_SIZE - 40) for x in range(2)]
newTxt = self.numBox.create_text(*coord, font = ("Times New Roman",size), text = value)
for i in range(1000): # 1000 is the maximum number of tries to make
bbox = self.numBox.bbox(newTxt)
overlapping = self.numBox.find_overlapping(*bbox)
if len(overlapping) == 1:
return
# compute new coordinate
coord = [random.randint(40,BOX_SIZE - 40) for x in range(2)]
self.numBox.coords(newTxt, *coord)
# delete the text since we couldn't find a space for it.
self.numBox.delete(newTxt)
Either algorithm will be slow when there isn't much free space. When I created a 1000x1000 canvas with 100 numbers, it laid them out with zero overlaps in under a second.

tkinter cant assign text variable

the problem was my input popup had to be a toplevel window so changing tk.Tk() to tk.Toplevel() makes it work fine ;)
#Josh Harrison
#3008088
from graphics import *
from random import randrange
import winsound, sys
#scale for size of squares
scale = 50
#setupBoard sets up the board with a randomly generated puzzle
def setupBoard(size, color):
board = [[[0, Rectangle(Point(scale*.05,scale*.05),Point(scale*.95,scale*.95))] for x in range(size)] for x in range(size)]
for x in range(size):
for y in range(size):
board[x][y][1] = Rectangle(Point(x*scale+scale*.05,y*scale+scale*.05),Point(x*scale+scale*.95,y*scale+scale*.95))
for i in range(1):
selectTile(board, Point(randrange(size)*scale,randrange(size)*scale), size, color)
return board
#selectTile does the action for selecting tiles
#set color to 0 for black and white and 1 for color rotation
def selectTile(board,point,size,color):
#sets value switch according to if colors are desired or not
if color == 1:
valueSwitch = colorSwitch
else:
valueSwitch = bwSwitch
x = int(point.getX()/scale)
y = int(point.getY()/scale)
#temp is made to preserve the selected tiles state
temp = board[x][y][0]
#swap all square values
#note try and except are also looped
for i in range(3):
for z in range(3):
try:
board[x-1+i][y-1+z][0] = valueSwitch(board[x-1+i][y-1+z][0])
except:
#overlap fix for x maxed
if x == size - 1 and y != size - 1:
board[0][y-1+z][0] = valueSwitch(board[0][y-1+z][0])
#overlap fix for y maxed
if y == size - 1 and x != size - 1:
board[x-1+i][0][0] = valueSwitch(board[x-1+i][0][0])
#overlap fix for bottom right corner
if x == size - 1 and y == size - 1:
board[0][0][0] = valueSwitch(board[0][0][0])
for a in range(2):
board[0][size-a-1][0] = valueSwitch(board[0][size-a-1][0])
board[size-a-1][0][0] = valueSwitch(board[size-a-1][0][0])
#give middle square initial value again
board[x][y][0] = temp
#updateBoard updates the squares to the right colour according to value
def updateBoard(board, size, count):
if count != 0:
winsound.Beep(333, 200)
for x in range(size):
for y in range(size):
if board[x][y][0] == 0:
board[x][y][1].setFill('white')
elif board[x][y][0] == 1:
board[x][y][1].setFill('yellow')
elif board[x][y][0] == 2:
board[x][y][1].setFill('green')
elif board[x][y][0] == 3:
board[x][y][1].setFill('blue')
elif board[x][y][0] == 4:
board[x][y][1].setFill('black')
#drawBoard draws the initial board
def drawBoard(size, board, win):
for x in range(size):
for y in range(size):
board[x][y][1].draw(win)
return
#checks to see if board is white(Winning condition)
def winGame(board, size):
#steps through all x and y values
for x in range(size):
for y in range(size):
if board[x][y][0] != 0:
return 0
#returns true if no black squares are found
return 1
#valueSwitch() just makes switching values easier by checking values and selecting the appropriate one
def colorSwitch(value):
if value == 4:
return 0
else:
return value + 1
#bwSwitch only selects from black and white value
def bwSwitch(value):
if value == 4:
return 0
else:
return 4
#winMessage() displaying a winning message graphic
def winMessage(size, scale, win):
gameMessage = Text(Point(size*scale/2,size*scale/2),"You have won logic!")
gameMessage.setSize(int(scale/4))
gameMessage.setTextColor('red')
gameMessage.draw(win)
#gameMenu() is a menu to select game size
def gameMenu():
win = GraphWin("Logic Menu", 400, 600)
win.setBackground('light blue')
board = [[[Text(Point(0,0),'bleh'),Rectangle(Point(0,0),Point(200,200))] for y in range(3)] for x in range(2)]
#Making and drawing the buttons ;)
for x in range(2):
for y in range(3):
board[x][y][1] = Rectangle(Point(x*200+200*.05,y*200+200*.05),Point(x*200+200*.95,y*200+200*.95))
board[x][y][1].draw(win)
board[0][0][0] = Text(board[0][0][1].getCenter(), 'Click for 5x5 puzzle')
board[1][0][0] = Text(board[1][0][1].getCenter(), 'Click for 7x7 puzzle')
board[0][1][0] = Text(board[0][1][1].getCenter(), 'Click for 9x9 puzzle')
board[1][1][0] = Text(board[1][1][1].getCenter(), 'Click for 12x12 puzzle')
board[0][2][0] = Text(board[0][2][1].getCenter(), 'Click to toggle colors')
board[1][2][0] = Text(board[1][2][1].getCenter(), 'Highscores!')
#drawing button options
for x in range(2):
for y in range(3):
board[x][y][0].draw(win)
#check to see what button is pressed
point = win.getMouse()
x = int(point.getX()/200)
y = int(point.getY()/200)
#colors is either 1 for colors or 0 for no colors
colors = 0
#turning colors on and off
#board[0][2][1] is the rectangle for colors
while y == 2:
if x == 0:
if colors == 0:
winsound.Beep(400, 200)
colors = 1
board[0][2][1].setFill('green')
else:
winsound.Beep(363, 200)
colors = 0
board[0][2][1].setFill('')
else:
winsound.Beep(400, 200)
board[1][2][1].setFill('red')
#board is just passed in for a smother button click effect not necessary for functionality
highscore_board(board)
point = win.getMouse()
x = int(point.getX()/200)
y = int(point.getY()/200)
board[x][y][1].setFill('red')
winsound.Beep(400, 200)
win.close()
if x == 0 and y == 0:
return 5 , colors
if x == 1 and y == 0:
return 7 , colors
if x == 0 and y == 1:
return 9 , colors
if x == 1 and y == 1:
return 12 , colors
return 5 , colors
#highscore() checks to see if player has highscore and outputs a highscore to a text file
def highscore(count):
#checks to see if highscore file exists
try:
scoreInfo = [line.strip() for line in open('highscore.txt')]
#remove all spacing
for i in range(scoreInfo.count('')):
scoreInfo.remove('')
scoreInfo[1]
scores = int(len(scoreInfo)/2)
newEntry = 0
#creates new highscore file is none exist
except:
win = GraphWin("Highscore!", 400, 200)
gameMessage = Text(Point(200,100),"Please input name: ")
gameMessage.setSize(int(scale/4))
gameMessage.setTextColor('red')
gameMessage.draw(win)
name=inputWin()
f = open('highscore.txt', 'w')
f.write(name)
f.write('\n'+str(count))
f.close()
gameMessage.setText(name+': '+str(count)+' - saved!')
time.sleep(1)
win.close()
return
#if there is a new highscore it is added at the beginning of the file
for i in range(scores):
if scores < 10 or count < int(scoreInfo[i*2+1]):
win = GraphWin("Highscore!", 400, 200)
gameMessage = Text(Point(200,100),"Please input name: ")
gameMessage.setSize(int(scale/4))
gameMessage.setTextColor('red')
gameMessage.draw(win)
name=inputWin()
f = open('highscore.txt', 'w')
#max 10 highscores 9 + new highscore
if scores >= 10:
scores = 9
for i in range(scores):
try:
if count < int(scoreInfo[i*2+1]) and not newEntry:
f.write(name)
f.write('\n'+str(count))
f.write('\n\n\n')
newEntry = 1
f.write(scoreInfo[i*2])
f.write('\n')
f.write(scoreInfo[i*2+1])
f.write('\n\n\n')
except:
pass
#if no entries have been added
#the new value is then added to the end
if newEntry == 0:
f.write(name)
f.write('\n'+str(count))
f.write('\n\n\n')
f.close()
gameMessage.setText(name+': '+str(count)+' - saved!')
time.sleep(1)
win.close()
break
pass
#board is just passed in for a smother button click effect not necessary for functionality
def highscore_board(board):
win = GraphWin("Highscores", 200, 500)
win.setBackground('light green')
try:
scoreInfo = [line.strip() for line in open('highscore.txt')]
#remove all spacing
for i in range(scoreInfo.count('')):
scoreInfo.remove('')
Text(Point(50,20),"Highscores:").draw(win)
for i in range(10):
Text(Point(10,45*i+60),str(i+1)+'. ').draw(win)
try:
Text(Point(60,45*i+60),scoreInfo[i*2]).draw(win)
Text(Point(170,45*i+60),scoreInfo[1+i*2]).draw(win)
except:
pass
except:
Text(Point(100,250),"no scores yet.").draw(win)
time.sleep(.05)
board[1][2][1].setFill('')
#prevent program crash if scoreboard is exited through os
try:
win.getMouse()
winsound.Beep(363, 200)
win.close()
except:
winsound.Beep(363, 200)
import tkinter as tk
def getString(ment,mGui):
global hsname
hsname = ment.get()
mGui.destroy()
mGui.quit()
def inputWin():
mGui = tk.Tk()
ment = tk.StringVar()
mGui.title('New Highscore!')
mEntry = tk.Entry(mGui,textvariable=ment).pack(side=tk.LEFT)
mbutton = tk.Button(mGui,text='OK',command=lambda:getString(ment,mGui),fg='red',bg='blue').pack(side=tk.RIGHT)
mGui.mainloop()
return hsname
this is the portion that wont work
import tkinter as tk
def getString(ment,mGui):
global hsname
hsname = ment.get()
mGui.destroy()
mGui.quit()
def inputWin():
mGui = tk.Tk()
ment = tk.StringVar()
mGui.title('New Highscore!')
mEntry = tk.Entry(mGui,textvariable=ment)
mEntry.pack(side=tk.LEFT)
mbutton = tk.Button(mGui,text='OK',command=lambda:getString(ment,mGui),fg='red',bg='blue')
mbutton.pack(side=tk.RIGHT)
mGui.mainloop()
return hsname
I'm just screwing around trying to make adding a highscore more visual for a game I made this code it works fine by itself but when I import it or even copy the whole code into a py file with other functions it just stops assigning ment any values I don't understand :/
any help is appreciated
this is the code that runs the game
#Josh Harrison
#3008088
from logic_game import *
def playGame():
option = gameMenu()
size = option[0]
color = option[1]
win = GraphWin("Logic Game", size*scale, size*scale)
win.setBackground('light pink')
board = setupBoard(size, color)
drawBoard(size, board, win)
countText = Text(Point(scale,scale/2),'moves: 0')
countText.setTextColor('red')
countText.draw(win)
count = 0
while not winGame(board, size):
updateBoard(board, size, count)
selectTile(board, win.getMouse(), size, color)
count += 1
countText.setText('moves: ' + str(count))
updateBoard(board, size, count)
winMessage(size, scale, win)
highscore(count)
#pauses the window and waits for click before continuing
win.getMouse()
#closes the window "win"
win.close()
playGame()
link for graphics.py
http://mcsp.wartburg.edu/zelle/python/graphics.py
I don't understand exactly what your problem is doing wrong, but I'm pretty sure I know what the problem is.
Most of your program is using some library named graphics to run a GUI. Then you're trying to use Tkinter to run another GUI in the same program.
I don't know what that graphics library that is, but unless it's either built on top of Tkinter, or specifically designed to work with Tkinter, this is unlikely to work. Both of them are going to try to be in charge of the one and only GUI for your program, handling all of the events from the user/windowing system, and so forth. One or both are going to fail.
In fact, even if graphics were built on top of Tkinter or designed to work together with it, calling mainloop on the Tkinter window is at best going to freeze up the rest of your GUI until you exit that mainloop, and at worst going to break the outer mainloop that the other GUI is relying on.
From what I can see from your other code, that graphics library seems to have enough features to do everything you were trying to do with Tkinter—create a new window, place some widgets on it, handle a button click. So, why not just use that?
Now that you've given us a link to the graphics library you're using… it looks like a thin wrapper around Tkinter. Which means you should be able to integrate them easily. You just have to create a new Toplevel instead of a root window (since graphics has already created a Tkinter root), and not call mainloop or quit (because you're already in a Tkinter main loop created by graphics).
Since you haven't given us an SSCCE that I can just run and hack on, I've built my own super-simple one around the first example in the graphics docs, which does what you were trying to do, and also shows how you can interact with the graphics window from the Tkinter code.
from graphics import *
import Tkinter as tk
def getString(ment,mGui):
global win
print(ment.get())
mGui.destroy()
win.close()
def inputWin():
global hsname
mGui = tk.Toplevel()
ment = tk.StringVar()
mGui.title('New Highscore!')
tk.Entry(mGui,textvariable=ment).pack(side=tk.LEFT)
tk.Button(mGui,text='OK',command=lambda:getString(ment,mGui),fg='red',bg='blue').pack(side=tk.RIGHT)
win.getMouse()
def main():
global win
win = GraphWin("My Circle", 100, 100)
c = Circle(Point(50,50), 10)
c.draw(win)
win.getMouse() # Pause to view result
inputWin()
main()
It would be better to refactor this to eliminate your global variables, either using an OO design (create a class so you can store things as instance attributes) or a functional design (pass values through closures or bake them in with lambda/partial, as you're already doing in your Button command), but I tried to follow the style you already set in your code rather than rewrite everything.

Categories