I have been fighting the same bug for weeks now with zero success: I am trying to get images to come up on my buttons, but they utterly refuse to show up. Regardless of whether I used my old Python 2.5.1 or now 2.6.5, the following code:

'''Minesweeper.'''

from Tkinter import *
import Tkinter as tk
import random

BEGINNER = 1
INTERMEDIATE = 2
EXPERT = 3

OFFSET = 2

BUTTON_SIZE = 2

class Board(Frame, object):
    def __init__(self, master, difficulty):
        Frame.__init__(self, master)
        if difficulty == BEGINNER:
            self.x = 9
            self.y = 9
            self.mines = 10
        elif difficulty == INTERMEDIATE:
            self.x = 16
            self.y = 16
            self.mines = 40
        elif difficulty == EXPERT:
            self.x = 30
            self.y = 16
            self.mines = 99

        self.grid()
        self.create_widgets()

    def create_widgets(self):
        #Create the grid.
        self.square = []
        self.isAMine = []
        self.selected = []
        for i in range(self.x):
            squareColumn = []
            mineColumn = []
            selectedColumn = []
            for j in range(self.y):
                squareColumn.append(Button(self, width = 3, height = 1))
                squareColumn[j].grid(row = j + OFFSET, column = i)
                mineColumn.append(False)
                selectedColumn.append(False)
            self.square.append(squareColumn)
            self.isAMine.append(mineColumn)
            self.selected.append(selectedColumn)
            
        #Plant the mines.
        print 'Dimensions:', self.x, self.y
        for i in range(self.mines):
            mineSquare = random.randrange(self.x * self.y)
            mine_y = mineSquare / self.x
            mine_x = mineSquare % self.x
            self.isAMine[mine_x][mine_y] = True
            self.square[mine_x][mine_y]['text'] = 'X' #temp line; shows mines
            #photo = tk.PhotoImage(file="1.gif")
            #self.square[mine_x][mine_y]['image'] = photo #temp line; shows mines


        for i in range(self.y):
            for j in range(self.x):
                self.square[j][i]['command'] = lambda x=j, y=i: self.hit(x, y)

    #Runs when a button (square) is clicked.
    def hit(self, x, y):
        self.selected[x][y] = True
        self.square[x][y].config(relief=SUNKEN)
        
        #print x, y
        if self.isAMine[x][y]:
            print 'Mine found.  Location:', x, y
        else:
            #Look at all eight neighbors and see if they are mines.
            #x>0, etc. avoid looking off the edge of the map.
            adjMines = 0
            if (x > 0 and y > 0) and self.isAMine[x-1][y-1]: #NW
                adjMines+=1
            if y > 0 and self.isAMine[x][y-1]: #N
                adjMines+=1
            if (x < self.x-1 and y > 0) and self.isAMine[x+1][y-1]: #NE
                adjMines+=1
            if x > 0 and self.isAMine[x-1][y]: #W
                adjMines+=1
            if x < self.x-1 and self.isAMine[x+1][y]: #E
                adjMines+=1
            if (x > 0 and y < self.y-1) and self.isAMine[x-1][y+1]: #SW
                adjMines+=1
            if y < self.y-1 and self.isAMine[x][y+1]: #S
                adjMines+=1
            if (x < self.x-1 and y < self.y-1) and\
               self.isAMine[x+1][y+1]: #SE
                adjMines+=1
            
            if adjMines>0:
                self.square[x][y]['text'] = adjMines
                        
                try:
                    image = []
                    image.append(PhotoImage(file='1.gif').zoom(2))
                except (IOError):
                    print 'File missing.'
                else:
                    if adjMines != 0 and adjMines < 2:
                        self.square[x][y]['text'] = ''
                        self.square[x][y]['image'] = image[adjMines-1]

            else: #adjMines == 0
                #If none of the adjacent squares have mines, it is safe to hit
                #them all.  Just like the official game, this game does
                #precisely that.            
                if (x > 0 and y > 0) and not self.selected[x-1][y-1]:
                    Board.hit(self, x-1, y-1) #NW
                if y > 0 and not self.selected[x][y-1]: #N
                    Board.hit(self, x, y-1)
                if (x < self.x-1 and y > 0) and not self.selected[x+1][y-1]: #NE
                    Board.hit(self, x+1, y-1)
                if x > 0 and not self.selected[x-1][y]: #W
                    Board.hit(self, x-1, y)
                if x < self.x-1 and not self.selected[x+1][y]: #E
                    Board.hit(self, x+1, y)
                if (x > 0 and y < self.y-1) and not self.selected[x-1][y+1]: #SW
                    Board.hit(self, x-1, y+1)
                if y < self.y-1 and not self.selected[x][y+1]: #S
                    Board.hit(self, x, y+1)
                if (x < self.x-1 and y < self.y-1) and\
                   not self.selected[x+1][y+1]:
                    Board.hit(self, x+1, y+1) #SE
                
        self.square[x][y]['command'] = ''
            
def main():
    root = Tk()
    root.title('Minesweeper')
    root.geometry('450x300')
    diff = int(raw_input( 'Select your difficulty level: '))
    theBoard = Board(root, diff)

    root.mainloop()

main()

Produces the following results (the button size is actually different than in this photo, but the image results--the heart of this problem--are exactly the same):

http://img717.yfrog.com/img717/8660/minegoofup.jpg

I am completely at wit's end. I have tried using PIL, I have tried resizing the buttons, and zooming the images, and saving the images as .gif's and .jpeg's and .bmp's and you name it. Absolutely nothing is working. I have a major assignment due within days and absolutely MUST figure this out. Someone please show me what the heck I am doing wrong and what I can do to fix it.

Recommended Answers

All 14 Replies

The code fails to run because you did not attach the 1.gif file.

After creating one very small file from windows minesweeper screen capture. it worked rearly few times, I do not know what happened. Normally it gives this error

Traceback (most recent call last):
File "D:\Tony\Tests\minesweeper.py", line 144, in <module>
main()
File "D:\Tony\Tests\minesweeper.py", line 140, in main
theBoard = Board(root, diff)
File "D:\Tony\Tests\minesweeper.py", line 32, in __init__
self.create_widgets()
File "D:\Tony\Tests\minesweeper.py", line 39, in create_widgets
for i in range(self.x):
AttributeError: 'Board' object has no attribute 'x'

What is the problem with graphics, I could not catch it?

Use the manage attachment button under the message to attach files, not external links, which become not functional in the future.

I overcame the error message be replacing lines from line 135 until end with

root = Tk()
root.title('Minesweeper')
root.geometry('450x300')
diff=0
while not 1<=diff<=3:
    diff = int(raw_input( 'Select your difficulty level, 1..3 : '))
    
theBoard = Board(root, diff)

root.mainloop()

Make the changes indicated by #!!!!!!!!!!!!!! ...

'''Minesweeper.'''

from Tkinter import *
import Tkinter as tk
import random

BEGINNER = 1
INTERMEDIATE = 2
EXPERT = 3

OFFSET = 2

BUTTON_SIZE = 2

class Board(Frame, object):
    def __init__(self, master, difficulty, photo):  #!!!!!!!!!!!!!!
        Frame.__init__(self, master)
        if difficulty == BEGINNER:
            self.x = 9
            self.y = 9
            self.mines = 10
        elif difficulty == INTERMEDIATE:
            self.x = 16
            self.y = 16
            self.mines = 40
        elif difficulty == EXPERT:
            self.x = 30
            self.y = 16
            self.mines = 99

        self.grid()
        self.photo = photo  #!!!!!!!!!!!!!!
        self.create_widgets()

    def create_widgets(self):
        #Create the grid.
        self.square = []
        self.isAMine = []
        self.selected = []
        for i in range(self.x):
            squareColumn = []
            mineColumn = []
            selectedColumn = []
            for j in range(self.y):
                squareColumn.append(Button(self, width=3, height=1, bd=1))
                squareColumn[j].grid(row = j + OFFSET, column = i)
                mineColumn.append(False)
                selectedColumn.append(False)
            self.square.append(squareColumn)
            self.isAMine.append(mineColumn)
            self.selected.append(selectedColumn)
            
        #Plant the mines.
        print 'Dimensions:', self.x, self.y
        for i in range(self.mines):
            mineSquare = random.randrange(self.x * self.y)
            mine_y = mineSquare / self.x
            mine_x = mineSquare % self.x
            self.isAMine[mine_x][mine_y] = True
            #self.square[mine_x][mine_y]['text'] = 'X' #temp line; shows mines
            self.square[mine_x][mine_y]['image'] = self.photo  #!!!!!!!!!!!!!!

        for i in range(self.y):
            for j in range(self.x):
                self.square[j][i]['command'] = lambda x=j, y=i: self.hit(x, y)

    #Runs when a button (square) is clicked.
    def hit(self, x, y):
        self.selected[x][y] = True
        self.square[x][y].config(relief=SUNKEN)
        
        #print x, y
        if self.isAMine[x][y]:
            print 'Mine found.  Location:', x, y
        else:
            #Look at all eight neighbors and see if they are mines.
            #x>0, etc. avoid looking off the edge of the map.
            adjMines = 0
            if (x > 0 and y > 0) and self.isAMine[x-1][y-1]: #NW
                adjMines+=1
            if y > 0 and self.isAMine[x][y-1]: #N
                adjMines+=1
            if (x < self.x-1 and y > 0) and self.isAMine[x+1][y-1]: #NE
                adjMines+=1
            if x > 0 and self.isAMine[x-1][y]: #W
                adjMines+=1
            if x < self.x-1 and self.isAMine[x+1][y]: #E
                adjMines+=1
            if (x > 0 and y < self.y-1) and self.isAMine[x-1][y+1]: #SW
                adjMines+=1
            if y < self.y-1 and self.isAMine[x][y+1]: #S
                adjMines+=1
            if (x < self.x-1 and y < self.y-1) and\
               self.isAMine[x+1][y+1]: #SE
                adjMines+=1
            
            if adjMines>0:
                self.square[x][y]['text'] = adjMines
                        
                try:
                    image = []
                    image.append(PhotoImage(file='1.gif').zoom(2))
                except (IOError):
                    print 'File missing.'
                else:
                    if adjMines != 0 and adjMines < 2:
                        self.square[x][y]['text'] = ''
                        self.square[x][y]['image'] = image[adjMines-1]

            else: #adjMines == 0
                #If none of the adjacent squares have mines, it is safe to hit
                #them all.  Just like the official game, this game does
                #precisely that.
                if (x > 0 and y > 0) and not self.selected[x-1][y-1]:
                    Board.hit(self, x-1, y-1) #NW
                if y > 0 and not self.selected[x][y-1]: #N
                    Board.hit(self, x, y-1)
                if (x < self.x-1 and y > 0) and not self.selected[x+1][y-1]: #NE
                    Board.hit(self, x+1, y-1)
                if x > 0 and not self.selected[x-1][y]: #W
                    Board.hit(self, x-1, y)
                if x < self.x-1 and not self.selected[x+1][y]: #E
                    Board.hit(self, x+1, y)
                if (x > 0 and y < self.y-1) and not self.selected[x-1][y+1]: #SW
                    Board.hit(self, x-1, y+1)
                if y < self.y-1 and not self.selected[x][y+1]: #S
                    Board.hit(self, x, y+1)
                if (x < self.x-1 and y < self.y-1) and\
                   not self.selected[x+1][y+1]:
                    Board.hit(self, x+1, y+1) #SE
                
        self.square[x][y]['command'] = ''
            
def main():
    root = Tk()
    root.title('Minesweeper')
    root.geometry('450x300')
    diff = int(raw_input( 'Select your difficulty level: '))
    # create your image object here for persistence
    photo = tk.PhotoImage(file="1.gif")  #!!!!!!!!!!!!!!
    theBoard = Board(root, diff, photo)  #!!!!!!!!!!!!!!

    root.mainloop()

main()

Alright, I made those changes. Now here is what I get:

http://img25.yfrog.com/img25/3374/weirdness2.jpg

("2" and above, I have not coded the pix for. I want to get the "1" right before proceeding.)

Note that the image is finally coming in. Now the question is, how to get it so it's not so small and it expands to the size of the entire button?

Once you specify width and height of the button you are limited to that size. One solution, change the size or let the image determine the size.

Once you specify width and height of the button you are limited to that size. One solution, change the size

With length and width of the button? I already tried that. Same with zooming the image.

or let the image determine the size.

How would I do that?

Why use PIL, Tkinter can handle the gif image. Part of solution is from recipe from internet for button over image, I forgot where, sorry.

from Tkinter import *

root = Tk()
root.title('Show GIF image test')
 
# pick a .gif image file you have in the working directory
image1 = PhotoImage(file="1.gif")
w = image1.width()
h = image1.height()
 
root.geometry("%dx%d+0+0" % (w, h))
 
# Frame has no image argument
# so use a label as a panel/frame
panel1 = Label(root, image=image1)
panel1.pack(side='top', fill='both', expand='yes')

# save the panel's image from 'garbage collection'
panel1.image = image1

print 'done.'
root.wait_window()

Yes, the program demonstrates panel (label) checking image size of the gif file. Probably it can be adapted to sizing button also. PIL has also function to prepare other format files for PhotoImage.

Please attach the images to your message

Yes, the program demonstrates panel (label) checking image size of the gif file. Probably it can be adapted to sizing button also. PIL has also function to prepare other format files for PhotoImage.

How?

Please attach the images to your message

OK. See below for the previous image (of that sample program).

Ok. I proved two pictures of different size in one button. Adaptation of my code which switched between splash image and scrolled text window. Sorry that I have not been able to study your own code more deeply.

from Tkinter import  *

def toggle():
    global switch
    switch=(switch+1) % 2
    if switch:
        image=image2
    else:
        image=image1
    panel['image']=image
    w = image.width()
    h = image.height()
    root.geometry("%dx%d+0+0" % (w, h+40))#+height for the other buttom

 
root = Tk()
root.title('GIF in button demo')
 
# pick a .gif image file you have in the working directory
image1 = PhotoImage(file="picture1.gif")
image2 = PhotoImage(file="picture2.gif")
image3 = PhotoImage(file="picture3.gif")

panel = Button(command=toggle)
panel.pack(side='bottom')

switch=1
toggle()

for i in range(4):
    button = Button(image=image3, command=toggle)
    button.pack(side='left')

# start the event loop
root.wait_window()

Yes, the program demonstrates panel (label) checking image size of the gif file. Probably it can be adapted to sizing button also. PIL has also function to prepare other format files for PhotoImage.

Er, got a link to how I can do all that?

Please attach the images to your message

I've been trying but it keeps defaulting back to links.

import Tkinter as tk
from ImageTk import PhotoImage

if __name__ == '__main__':
    root = tk.Tk()
    root.title('Advanced Watermarks')

    frame = tk.Frame(root,colormap="new",visual='truecolor').pack()
    ## clip from freephoto.com sea picture
    imagedata = PhotoImage(file='3001_07_75_prev.jpg')
    panel = tk.Button(frame,image=imagedata)
    panel.pack()

    root.mainloop()
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.