I wanted to program a simple graphical version of Tic Tac Toe in Python after having previously made a text based one with a friend. For this I used tkinter. I have been able to get rid of all mistakes in the first window where you choose which symbol you want. But in the second window when you are supposed to place it, when I press one of the buttons it tells me that "pyimage2" doesn't exist which seems to be a common error
I have already checked out some other threads where I was told that I should use TopLevel instead, since there can only be one instance of Tk(). But I already am using it, and when I try using two instances by using destroy() on the first, the error remains. I have also switched from simple PhotoImage to PIL, but even that is of no help
from tkinter import *
from random import *
from PIL import Image, ImageTk
global root
global SpielerSymbol
SpielerSymbol = "Defaultshit"
def combine_funcs(*funcs):
def combined_func(*args, **kwargs):
for f in funcs:
f(*args, **kwargs)
class SelectionScreen:
def __init__(self,pRoot):
Imageo = Image.open("o.png")
o = ImageTk.PhotoImage(Imageo)
Imagex = Image.open("x.png")
x = ImageTk.PhotoImage(Imagex)
Screen = Toplevel(pRoot)
self.TextField = Label(Screen, text="Please choose a symbol.")
self.TextField.grid(row=1,column=1)
self.ButtonX = self.SelectionButton(x,Screen)
self.ButtonX.Choice.grid(row = 2, column = 1)
self.ButtonO = self.SelectionButton(o,Screen)
self.ButtonO.Choice.grid(row = 2, column = 2)
Screen.mainloop()
class SelectionButton:
def __init__(self, pImage, pScreen):
self.Choice = Button(pScreen, image = pImage, command = lambda: combine_funcs(setSpielerSymbol(str(pImage)), pScreen.destroy(), pScreen.quit()))
def setSpielerSymbol(pZeichen):
global SpielerSymbol
SpielerSymbol = pZeichen
class Game:
def __init__(self, pRoot):
global SpielerSymbol
ImageFeldx = Image.open("Feldx.png")
Feldx = ImageTk.PhotoImage(ImageFeldx)
ImageFeldo = Image.open("Feldo.png")
Feldo = ImageTk.PhotoImage(ImageFeldo)
ImageFeld = Image.open("Feld.png")
Feld = ImageTk.PhotoImage(ImageFeld)
Window = Toplevel(pRoot)
Feld1 = [self.Feld(Feld,Window,1,1), self.Feld(Feld,Window,1,2), self.Feld(Feld,Window,1,3),
self.Feld(Feld,Window,2,1), self.Feld(Feld,Window,2,2), self.Feld(Feld,Window,2,3),
self.Feld(Feld,Window,3,1), self.Feld(Feld,Window,3,2), self.Feld(Feld,Window,3,3)]
Window.mainloop()
class Feld:
def __init__(self, pImage, pWindow, pRow, pColumn):
self.Feld1 = Button(pWindow, image = pImage, command =lambda: combine_funcs(self.setFeldImage(self), Window.quit()) )
self.Feld1.grid(row=pRow,column=pColumn)
def setFeldImage(self, pFeld1):
pFeld1.Feld1.config(image=SpielerSymbol)
def main():
root = Tk()
root.withdraw()
SelectionScreen1 = SelectionScreen(root)
print("Das ist das Werk von Feiglingen")
Game1 = Game(root)
main()
The output should be two windows, first the one where you choose a symbol, that one should work fine, and the second should be a tic tac toe field where clicking on a button should display the symbol you've chosen. And what I instead get is the error message image "pyimage1" doesn't exist
Also sorry for the ugly code, I am still a beginner, especially at Python
Related
I have 2 classes, first one is Game where's located the main window and its settings, the second one is Piece that have some parameters to establish a Button with an image on its surface using Pillow. From the main class Game I planned call the other class to create objects on this window(root). Everything works fine(1st pic) untill I call my setter from any of these classes to change the image of the Button(Piece), it doesn't appear though the path to the new file is absolutely correct and the button becomes enabled if I'm not wrong and it's not clickable (2nd pic)
How can I resolve the problem, cos I need this possibility to change pictures on the button for my tic-toe game?
from tkinter import *
from PIL import Image
from PIL import ImageTk
class Game:
ICON = "./rsc/logo.ico"
KREST_IMAGE = "./rsc/krest.png"
DEFAULT_IMAGE = "./rsc/1.png"
def __init__(self):
self.root = Tk()
self.root.title("Tic-tac-toe")
self.root.iconbitmap(Game.ICON)
self.root.resizable(False,False)
self.root.geometry("300x300+500+500")
self.c = Piece()
self.root.mainloop()
class Piece:
def __init__(self):
self.img = Game.DEFAULT_IMAGE
self.piece = Button(image = self._img)
self.img = Game.KREST_IMAGE
# for ex. calling again the setter. Writing direct path instead of Game.KREST_IMAGE doesn't help.
self.piece.pack()
#property
def img(self):
return self._img
#img.setter
def img(self, path):
self.temp = Image.open(path)
self.temp = self.temp.resize((20,20), Image.ANTIALIAS)
self.temp = ImageTk.PhotoImage(self.temp)
self._img = self.temp
the picture
how to remove the page1's widgets when the next button is pressed, so that only the page2's widgets is shown.
and vice versa if the back button is pressed on page 2, so the widgets don't overlap
from tkinter import *
class Buttons(Button):
def __init__(self,master,**kwargs):
super().__init__(master=master,**kwargs)
self.look = {"fg":"ghost white","bg":"DarkBlue"}
self.config(self.look)
def makeButton(self,name,texts,wide,rows,cols,com):
self.name = name
self.texts = texts
self.wide = wide
self.rows = rows
self.cols = cols
self.com = com
self.name = Buttons(root,text=self.texts,width=self.wide,command=self.com)
self.name.place(x=self.rows,y=self.cols)
class make(Buttons):
def __init__(self, mainFrame):
super().__init__(mainFrame)
self.main_frame = Frame(mainFrame, width=400, height=300)
self.main_frame.place()
self.page1()
def page1(self):
self.makeButton("name1","Page1-widgets1",15,125,30,None)
self.makeButton("name2","Page1-widgets2",15,125,80,None)
self.makeButton("name3","Next",15,125,130,self.page2)
self.makeButton("name4","Exit",15,125,180,exit)
def page2(self):
self.makeButton("name5","Page2-widgets1",15,135,40,None)
self.makeButton("name6","Page2-widgets2",15,135,90,None)
self.makeButton("name7","Page2-widgets3",15,135,140,None)
self.makeButton("name8","Back",15,135,210,self.page1)
def main():
global root
root = Tk()
root.geometry('400x300+50+50')
script = make(root)
root.mainloop()
if __name__ == '__main__':
main()
was gonna comment but not enough reps, so gonna ask my question here. I copied your script and produced same error too. Firstly its not clear what you want to achieve with script so comments between definitions would help a lot!. When continue button is pressed you want current page to be destroyed and new one to be created right ?
enter code here
def frame_elements_remove(self, elements):
self.elements = elements
for self.element in self.elements:
self.element.destroy()
To destroy button it has to object. When I try to check for type of element in list ;
self.frame_elements = []
with
def mainPage(self):
self.frame_elements_remove(self.frame_elements)
self.makeButton("Button1", "Continue", 10, 10, self.page1)
self.makeButton("Button2", "Exit", 10, 80, quit)
self.controler = 1
self.frame_elements = [self.makeButton]
#just put here print for type check
print(type(self.frame_elements[0]))
it returns;
<class 'method'>
So its seems, its not destroyable because it is not object but a method.
Hope it helps!
I'm currently working on a Synthesizer inside Python for a school project and currently have a really troublesome issue. I have a Stack of Checkboxes which mark when a note is played and on which pitch inside a sequencer. My Problem is that whenever I open two Oscillators inside my synthesizer and put in the Values inside the checkboxes, the checkboxes duplicate their value over the multiple windows, but don't do it for the actual sequence, as in I have two lists with correct values, but the values aren't properly displayed inside the window.
To Replicate the Problem hit "new Oscillator" then click on "Arpeggio", do this a second time and click any Checkbox on the Arppeggio Windows
I know this might be a confusing explanation, but I'm going to link the complete code in the bottom so you can try it out and might know what I'm talking about.
The problem occurs inside the "Arpeggio" Class
import numpy # used for Waveform Calculation
from functools import partial # used for Command Combining
from tkinter import * # used for GUI
from tkinter import ttk # used for GUI
from tkinter import filedialog # used for GUI
np = numpy # Simplifying Libraries
tk = ttk # Simplifying Libraries
fd = filedialog # Simplifying Libraries
root = Tk()
#StartupFunction
def StartUp():
print("")
print("Starting Startup")
app = App(root) # Initializing GUI
print("Finished Startup")
main()
("Exiting Startup")
#Main Program Function
def main():
print("Executing Main")
root.mainloop()
print("Finished Main")
return 0
class Oscillator():
pass
class App(tk.Frame):
OscillatorWindowList = []
OscillatorList = []
SoundInputArrayList = []
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
root.title("PySynth")
root.geometry("984x300")
root.resizable(False, True)
root.maxsize(984,720)
btnNewOscillator = Button(root,text="New Oscillator",command=self.NewOscillator,relief=RIDGE,bg="#2d2d2d",fg="white")
btnNewOscillator.place(x = 8, y = 8+128)
def NewOscillator(self):
print("AddingOscillator")
self.OscillatorList.append(Oscillator())
self.SoundInputArrayList.append(SoundInputArray(root,len(self.OscillatorList)-1,len(self.OscillatorList)-1))
print(self.OscillatorList)
self.OscillatorWindowList.append(OscillatorGUI(root,self.OscillatorList[len(self.OscillatorList)-1],len(self.OscillatorList)))
def EXIT(self):
root.destroy()
#$SoundInputArray
class SoundInputArray():
actv = []
CheckbuttonList = []
CheckButtonFreq = []
i=0
ButtonCount = 32
VolumeSlider = None
btnArpeggio = None
Arpeggio = None
hasArpeggio = False
LFO = None
ArpeggioList = [(0,0)]
def __init__(self,master,oscillatorCount,number):
btnArpeggio = Button(master,text="Arpeggio",command=self.OpenArpeggio,relief=RIDGE,bg="#2d2d2d",fg="white")
btnArpeggio.place(x = 8, y = (1+oscillatorCount)*48 +128 )
def OpenArpeggio(self):
if self.Arpeggio == None:
self.Arpeggio = Arpeggio()
def GetArpeggio(self):
return self.Arpeggio
#$Arpeggio
class Arpeggio():
SoundValueList = None
def __init__(self):
GUI = Toplevel(root)
GUI.title("Arpeggio")
GUI.geometry("480x320")
GUI.resizable(False, False)
GUI.configure(bg="#171717")
self.SoundValueList = np.arange(0,16)
self.DrawUI(GUI)
self.ClearList()
def DrawUI(self,frame):
Button(frame,text="display", command= self.PrintSound, width=11,bg="#171717",).place(x = 4, y = 4)
Button(frame,text="empty", command= self.ClearList).place(x = 96, y = 4)
y = 1
x = 1
checkbuttonList = []
for y in range(1,13):
for x in range(0,16):
updatecommand = partial(self.UpdateList,x,y)
checkbuttonList.append(Checkbutton(frame, variable=self.SoundValueList[x], onvalue=y, offvalue=0,command = updatecommand))
checkbuttonList[len(checkbuttonList)-1].place(x = x*24 + 96, y= y*24 + 8)
def ClearList(self):
for i in range(0,16):
self.SoundValueList[i] = 0
def UpdateList(self,x,value):
if (self.SoundValueList[x] == value):
self.SoundValueList[x] = 0
else:
self.SoundValueList[x] = value
self.PrintSound()
def PrintSound(self):
print(self.SoundValueList)
def GetList(self):
print(self.SoundValueList)
return self.SoundValueList
StartUp() # Initiate Program
i'm new on Tkinter and i'm trying to make an animated button.
I'm using the enter-leave events but the click on button it's not responding very well.
My code is:
imagePath = "Resources/"
imagelist = ["boton_1.gif","boton_2.gif","boton_3.gif","boton_4.gif","boton_5.gif","boton_6.gif",
"boton_7.gif","boton_8.gif","boton_9.gif","boton_10.gif","boton_11.gif","boton_12.gif",
"boton_13.gif","boton_14.gif","boton_15.gif","boton_16.gif"]
giflist = []
for imagefile in imagelist:
photo = PhotoImage(file=imagePath+imagefile)
giflist.append(photo)
self.photo=giflist[0]
button = Button(buttonFrame, image=self.photo,background='orange',activebackground='lightsalmon',
command=lambda: controller.show_frame(ListPlayerPage))
button.pack(pady=5)
def enter(event):
self.clickOnButton1 = True
for i in range(1,8):
button.config(image=giflist[i])
button.update()
time.sleep(0.1)
if self.clickOnButton1 == False:
break
while (self.clickOnButton1):
for i in range (9,15):
button.config(image=giflist[i])
button.update()
time.sleep(0.08)
if self.clickOnButton1 == False:
break
def leave(event):
self.clickOnButton1 = False
button.config(image=self.photo)
button.update()
button.bind("<Enter>",enter)
button.bind("<Leave>",leave)
Thanks!!
Part of the problem is definitely related to the fact you're calling sleep. As a good rule of thumb you should never call sleep in the main thread of a GUI. It prevents the GUI from processing all events, including screen refreshes.
Generally speaking, you should also avoid calling update. It can result in nested event loops, if during the processing of update you end up calling a method that again calls update.
Here's a really simple example of solution that creates a button that can be animated. It uses after to iterate over a list of text strings, one new string every half second. This example will animate forever, but you can easily have it show each item only once. This modifies the text to make the example shorter, but you can easily modify it to change images instead of text.
import Tkinter as tk # use tkinter for python 3.x
class AnimatedButton(tk.Button):
def __init__(self, *args, **kwargs):
tk.Button.__init__(self, *args, **kwargs)
self._job = None
def cancel_animation(self):
if self._job is not None:
self.after_cancel(self._job)
self._job = None
def animate(self, textlist):
text = textlist.pop(0)
textlist.append(text)
self.configure(text=text)
self._job = self.after(500, self.animate, textlist)
You use it like any other Button, but you can call animate to start animation and cancel_animate to cancel it:
button = AnimatedButton(root, width=10)
data = ["one","two","three","four","five","six"]
button.bind("<Enter>", lambda event: button.animate(data))
button.bind("<Leave>", lambda event: button.cancel_animation())
I followed the Bryan Oakley example and found a nice solution!
First of all, this is an animated button with a bit complex animation. I have 16 images. The firts one is the base image. Then i have eight images that are the first part of the animation. The rest of the images are the loop part of the animation.
When you put the mouse over the button, the animation starts.
Here is the code!:
import Tkinter as tk # use tkinter for python 3.x
root = tk.Tk()
root.geometry("300x200")
class AnimatedButton(tk.Button):
def __init__(self, *args, **kwargs):
tk.Button.__init__(self, *args, **kwargs)
self._job = None
self.i = 1
def cancel_animation(self,image):
self.configure(image=image)
self.i = 1
if self._job is not None:
self.after_cancel(self._job)
self._job = None
def animate(self, imagelist):
image = imagelist[self.i]
self.i+=1
if self.i == (len(imagelist)-1):
self.i = 9
self.configure(image=image)
self._job = self.after(80, self.animate, imagelist)
imagePath = "Resources/"
imagelist = ["boton_1.gif","boton_2.gif","boton_3.gif","boton_4.gif","boton_5.gif","boton_6.gif",
"boton_7.gif","boton_8.gif","boton_9.gif","boton_10.gif","boton_11.gif","boton_12.gif",
"boton_13.gif","boton_14.gif","boton_15.gif","boton_16.gif"]
giflist = []
for imagefile in imagelist:
photo = tk.PhotoImage(file=imagePath+imagefile)
giflist.append(photo)
image = giflist[0]
button = AnimatedButton(root,image = image)
button.bind("<Enter>", lambda event: button.animate(giflist))
button.bind("<Leave>", lambda event: button.cancel_animation(image))
button.pack()
root.mainloop()
Thank's!!!
Does anyone can help here?
I have two files called game.py and settings.py, I just want to get one value from settings to use in game, but I dont know what I am doing wrong.
the value I want it is in the function bbbbb...
THIS IS MY SETTINGS
from tkinter import*
import game
class Application(Frame):
def __init__ (self, master):
Frame.__init__(self,master)
self.grid()
self.create_widgets()
def bbbbb(self):
self.xr = self.ball_numbers.get()
print("printing...", self.xr)
return self.xr
def create_widgets(self):
self.ball_numbers = IntVar()
Label(self,text = "Select how many balls you wish to play:").grid()
Radiobutton(self, text = "1 Ball", variable = self.ball_numbers, value = 1, command = self.bbbbb).grid ()
Radiobutton(self, text = "2 Balls", variable = self.ball_numbers, value = 2, command = self.bbbbb).grid ()
Radiobutton(self, text = "3 Balls", variable = self.ball_numbers, value = 3, command = self.bbbbb).grid ()
settings_window = Tk()
settings_window.title(" THE BOUNCER - Settings")
settings_window.geometry("600x600")
app = Application(settings_window)
settings_window.mainloop()
I need that value in the class handling_settings, in the function create_ball_numbers
AND THIS IS MY game.py
from livewires import games, color
from tkinter import*
import settings
import random
games.init(screen_width = 735, screen_height = 350, fps = 35)
class Bounce(games.Sprite):
def update(self):
if self.right > games.screen.width or self.left < 0:
self.dx = -self.dx
if self.top < 0:
self.dy = -self.dy
if self.bottom == 315 and self.overlapping_sprites:
self.dy = -self.dy
class Bar_moving(games.Sprite):
def update(self):
self.x = games.mouse.x
self.y = 315
class handling_settings():
self.yr = bbbbb()
print("printing number from settings ", self.yr)
def create_ball_numbers(self):
print("inside def", self.yr)
def main():
background = games.load_image("BG.jpg", transparent = False)
games.screen.background = background
call = handling_settings()
call.create_ball_numbers()
bar_small = games.load_image("bar_small.jpg", transparent = False)
the_bar_small = Bar_moving(image = bar_small, x = games.mouse.x)
games.screen.add(the_bar_small)
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()
main()
I think I am not using on the right way IMPORT on top of the file.... keeping appearing this msg...
File "C:\Users\Bruno\Desktop\DIT\Object Oriented Programming\GAME - Assignment\game.py", line 3, in <module>
from settings import bbbbb
ImportError: cannot import name bbbbb
If I run both files individually... its ok... but when I try to get the value in bbbbb function in settings, I get stuck...
You have a circular import; settings imports game, which imports settings. At that time, neither module is fully done initializing (anything beyond the import lines has not yet run).
You don't actually use the game module in settings, so just remove the import game line from settings.py.
In game.py, you imported the settings name; bbbbb is an attribute on the Application class in that module. The line:
self.yr = bbbbb()
will never work here.
You should definitely not create a new Tk() root window in settings, however; you can only ever have one main loop in a Tk application. Make settings a dialog window triggered by the main application in game.
So to get the bbbbb() result, you need to instead spawn the settings dialog box, let the user interact with it, and then retrieve the ball_numbers setting when the user closes the dialog again.
First don't do any circular import, in settings.py there is no need to import game module.
As bbbbb is a function of class Application, therefore it cannot be called directly, to call it we need an object of the same class, which is already created as
app = Application(settings_window)
so, in module game.py, just use app object to call bbbbb()
self.yr = settings.app.bbbbb()