Python Tk() Button command not completely working - python

I'm quite new to python programming and have quite a basic question which I can't seem to resolve myself - I hope someone might be able to shed some light on this!
I created a .py file which runs a basic Rock, Paper, Scissors game between a user and the (random) computer. This uses a GUI via a tk() and works absolutely fine.
Then, I created another .py file, this time to create an overall menu GUI, from which I could choose to run my Rock, Paper, Scissors game. I can create this tk() fine, the button to select the RPS game, the game loads up, but this time it doesn't work at all! I can press the buttons, but they don't progress the game.
Here's my code for the game.py:
from tkinter import *
from tkinter.ttk import *
import random
def gui():
<game code goes in here, including other functions>
root=Tk()
root.title("Rock, Paper, Scissors")
# more code to define what this looks like
# including a Frame, buttons, labels, etc>
if __name__=='__main__':
gui()
And then I created the overall game menu, menu.py:
from tkinter import *
from tkinter.ttk import *
import random
import game
main=Tk()
main.title("J's games")
mainframe=Frame(main,height=200,width=500)
mainframe.pack_propagate(0)
mainframe.pack(padx=5,pady=5)
intro=Label(mainframe,
text="""Welcome to J's Games. Please make your (RPS) choice.""")
intro.pack(side=TOP)
rps_button=Button(mainframe, text="Rock,Paper,Scissors", command=game.gui)
rps_button.pack()
test_button=Button(mainframe,text="Test Button")
test_button.pack()
exit_button=Button(mainframe,text="Quit", command=main.destroy)
exit_button.pack(side=BOTTOM)
main.mainloop()
If anyone can see something obvious, please let me know. I'm confused as to why it works on its own, but not when I incorporate it into another function (the button command). I've tried the IDLE debugging but it seems to freeze on me!

I presume you want the main window to remain when one selects a particular game. That means that the game should be in a separate frame, initially in a separate Toplevel. Modify your rps file something like the following,
from tkinter import *
from tkinter.ttk import *
import random
class RPS(Toplevel):
def __init__(self, parent, title):
Toplevel.__init__(parent)
self.title(title)
#game code goes in here, including other functions
# more code to define what this looks like
# including a Frame, buttons, labels, etc>
if __name__=='__main__':
root=Tk()
root.withdraw()
RPS(title = "Rock, Paper, Scissors")
root.mainloop()
This way, importing the file does not create a second root and mainloop.
If you want only one game running at a time, you could instead use a paned window with two panes. Turtledemo does this. The code is in turtledemo.main. You would then derive RPS from Frame and pack it into the second pane.

Related

Move tkinter button randomly on mouse hover

I'm trying to make a button move randomly to coordinates in lists.
It moves the first time I hover on it each time I run the programme and never after and I can't figure it out, I'm a total noob, though and frankly I'm amazed it works at all.
I hate asking questions but I've been trying to solve this for weeks so I appreciate anyone's help..
import tkinter as tk
from tkinter import *
import random
root = tk.Tk()
root.title('Press me')
root.geometry('1280x800')
img=PhotoImage(file='red_button_crop.png')
my_label=Label(root, text="",font='helvetica,12')
my_label.pack(pady=50)
but_loc_x=[200,600,1000]
but_loc_y=[200,350,600]
but_pos_x=random.choice(but_loc_x)
but_pos_y=random.choice(but_loc_y)
def press():
my_label.config(text="You pressed me.\n Well done\nYou are as clever as a monkey.\n Not one of the good ones tho")
root.after(1500,root.destroy)
def button_hover(e):
root.after(250)
button.place_configure(x=but_pos_x,y=but_pos_y)
#def unhover(e):
# root.after(500)
#button.place_configure(x=600,y=350)
button =tk.Button(root,image=img,borderwidth=0,command=press)
button.place(x=600,y=350,anchor=CENTER)
button.bind("<Enter>",button_hover)
#button.bind("<Leave>",unhover)
root.mainloop()
I've tried implementing various bit of code I searched up on the net but I don't know enough to work it out
Importantly, as one of the comments suggests, the button is moving every time you hover over it, so your code was in fact correct.
However, because the coordinates are set outside of the function it always hovers to the same place (so it appears like it was not moving).
The changes that correct to code to the desired output are below.
removed from tkinter import * and used the tk alias as it should be.
moved the random button positions into the function (see comment with arrow).
This is the corrected version of the code:
import tkinter as tk
# from tkinter import *
import random
root = tk.Tk()
root.title('Press me')
root.geometry('1280x800')
img=tk.PhotoImage(file='red_button_crop.png')
my_label=tk.Label(root, text="",font='helvetica,12')
my_label.pack(pady=50)
but_loc_x=[200,600,1000]
but_loc_y=[200,350,600]
def press():
my_label.config(text="You pressed me.\n Well done\nYou are as clever as a monkey.\n Not one of the good ones tho")
root.after(1500,root.destroy)
def button_hover(e):
root.after(250)
but_pos_x=random.choice(but_loc_x) # <----- moved into the function
but_pos_y=random.choice(but_loc_y) # <----- moved into the function
button.place_configure(x=but_pos_x,y=but_pos_y)
#def unhover(e):
# root.after(500)
#button.place_configure(x=600,y=350)
button =tk.Button(root,image=img,borderwidth=0,command=press)
button.place(x=600,y=350,anchor=tk.CENTER)
button.bind("<Enter>",button_hover)
#button.bind("<Leave>",unhover)
root.mainloop()
Result:
the image red_button_crop.png now moves randomly when hovered over.

Python Tkinter GUI application query

I have built a Python tkinter GUI application which is an application for running different tasks. The application window is divided into 2 halves horizontally, first half shows the options the user can choose for the selected menu option and second half shows the progress of the task by showing the log messages. Each task has a separate menu option, the user selects the menu option and first half is refreshed with user option along with a Submit button.
The GUI is built using the object oriented method where each task in the menu option is an class method of the GUI object.
I now have about 5-6 menu options and working fine but the code size is becoming huge and it is becoming hard to debug any issue or add new features.
Is there any way to write the method of a class in separate file which can be called from within the main class. The logging of messages in the GUI is written in the main class so if the method is written in a separate file the how will the log messages written in the other file appear in the main window.
Please suggest alternatives.
This might not help you completely, but this is what I use. I divide my tkinter code into 2 files. First gui.py contains the GUI components (widgets) and the second methods.py contains the methods.
Both the files should be in same directory.
Here is an example of a simple app that changes the label on a button click. The method change() is stored in a different file.
gui.py
from tkinter import *
from tkinter import ttk
from methods import change #Using absolute import instead of wildcard imports
class ClassNameGoesHere:
def __init__(self,app):
self.testbtn = ttk.Button(app,text="Test",command = lambda: change(self))
#calling the change method.
self.testbtn.grid(row=0,column=0,padx=10,pady=10)
self.testlabel = ttk.Label(app,text="Before Button Click")
self.testlabel.grid(row=1,column=0,padx=10,pady=10)
def main():
root = Tk()
root.title("Title Goes Here")
obj = ClassNameGoesHere(root)
root.mainloop()
if __name__ == "__main__":
main()
methods.py
from tkinter import *
from tkinter import ttk
def change(self):
self.testlabel.config(text="After Button Click")

Importing and using mp3s on button press

So I have coded a "copy" of the game 2048 after following a Kite youtube tutorial. I want to add a small mp3 to play anytime you click an arrow key(to move stuff around in the game) but I'm not entirely sure what i'm doing right or wrong here. How do I do this?
I've snipped the important stuff out(import music is a folder for my mp3s)
import tkinter as tk
import mp3play
import music
The two errors I'm getting are down below, the Tk in Tk() is underlined and the root in left(root...)
when i attempt to run the code like this, it highlights "import mp3play" and says there is a Syntax error. Not sure why, I have in fact installed mp3play via pip installer as well
root = Tk()
f = mp3play.load('beep.mp3'); play = lambda: f.play()
button = left(root, text = "Play", command = play)
button.pack()
root.mainloop()
in between the 2 middle sections is the def for up, down, left, and right but that would just clutter this question
Here is the stackoverflow I've referenced for it, to be honest I dont understand half of it. How can I play a sound when a tkinter button is pushed?
Take a look at this simple example using winsound which is easier to handle for small beeps.
from tkinter import *
import winsound
root = Tk()
def play():
winsound.Beep(1000, 100)
b = Button(root,text='Play',command=play)
b.pack()
root.mainloop()
winsound.Beep(1000, 100) takes two positional arguemnts, 1000 is the frequency and 100 is the duration in milliseconds.
Do let me know if any errors or doubts.
Cheers

How to add Tkinter button that allows the user to play their own music?

Just a quick question: In a game, I'm making, I want the player to be able to pick an audio file from his/her computer and play it in the game and I'm not all that sure how to do it. I want them to be able to open a browse files screen (default file explorer) and then select a music file and play it as bgm, all by the click of a button.
Now I know Tkinter doesn't support sound but I don't care how the program runs. As long as I can fit it into my code. If you need my code, it's here: https://github.com/SeaPuppy2006/FruitClicker (I'm using my windows build at the moment). Thanks!
You could use playsound module and use a thread to prevent block:
from playsound import playsound
import tkinter
from tkinter import filedialog
import threading
def f():
def play():
pathname = filedialog.askopenfilename()
playsound(pathname)
threading.Thread(target=play).start()
root = tkinter.Tk()
tkinter.Button(root,text="playsound",command=f).grid()
root.mainloop()

Problem with tkinter code execution order

I have my principal script running with terminal that works perfectly. Im trying to make a gui for it but im stuck at this point.
Like you see on the screen, at the start of the script it asks if it should check the database. And just after, it asks first the platform before opening the captcha for the database check. The problem happens exactly here on my GUI version, look.
Like you see, the gui starts, but when i click on check for new database, it directly opens the captcha without asking the platform... And it asks me the platform only after i solved the captcha which i dont want to after...
Here is the main testkinter.py code:
import tkinter as tk
from tkinter import messagebox
import commands
import CheckDatabase
import SetPlatformfile
def check_and_hide():
CheckDatabase.db_download(root)
checkdb.pack_forget()
checkdb1.pack_forget()
root = tk.Tk()
checkdb = tk.Button(root, text="Check for new databases", command=check_and_hide)
checkdb.pack()
checkdb1 = tk.Button(root, text="No")
checkdb1.pack()
root.mainloop()
Here is the set_platform function called in the Checkdatabse file:
import tkinter as tk
import config
from tkinter import messagebox
def set_platform(root):
platform = tk.Label(root,text="'a'|Android -- 'i'|iOS: ")
platform.pack()
androidbutton=tk.Button(root,text="Android",command=renameplatformandroid)
iosbutton=tk.Button(root,text="iOS",command=renameplatformios)
androidbutton.pack()
iosbutton.pack()
def renameplatformandroid():
config.platform = 'android'
print(config.platform)
def renameplatformios():
config.platform = 'ios'
print(config.platform)
And cuz of my checkdatabase file is really really long, i'll just put a screen at the exact moment where set_platform is called (its called in the func signup which itself is directly called at the beginning of db_download) .
I hope my question is clear! Let me know if you need more details.

Categories