英文:
Python 3 & Tkinter: How to run conditional block based on choice between buttons
问题
I am converting a text-based card game, written in Python 3, to a UI via tkinter. There are many instances where the player is prompted to make a choice. Getting this choice in text format is easy; however, I am stuck trying to get this choice using buttons.
In the text-based game, I can easily get the player's choice through a variable set equal to input and then run resulting lines of code.
call_or_pass = user_input('What do you choose?')
if call_or_pass == 'call':
# code that does stuff
elif call_or_pass == 'pass':
# other code that does stuff
# Then lots more code after this...
I am struggling to translate this code to a tkinter UI. Keep in mind choice prompts and the buttons used to make the choice must appear in specific instances. My program is built within a class. A variable to track player choices, self.user_choice
, is defined in the __init__
and set to None
by default. The buttons are created above .mainloop()
within the UI code.
# buttons
self.call_button = tk.Button(text='Call', font=self.medium, command=lambda: self.button_choice('call'))
self.pass_button = tk.Button(text='Pass', font=self.medium, command=lambda: self.button_choice('pass'))
The buttons are bound to a function called button_choice
. Each button passes an argument to this function that updates the self.user_choice
variable.
def button_choice(self, choice):
if choice == 'call':
self.user_choice = 'call'
elif choice == 'pass':
self.user_choice = 'pass'
When a choice prompt occurs, the buttons are drawn to the UI with a place_buttons
function. But, I am calling place_buttons
in the specific instance with the function select_button
. Once the update to self.user_choice
is made, the program should run one of two conditional block options within select_button
. For debugging purposes, I am trying to change some text at the top of a window.
# draws the button to the UI when called
def place_buttons(self):
self.call_button.place(x=self.window_width - (self.window_width * .58), y=self.window_height - (self.window_height * .38))
self.pass_button.place(x=self.window_width - (self.window_width * .48), y=self.window_height - (self.window_height * .38))
# function for a specific choice prompt instance
def select_button(self):
self.place_buttons()
# in the text-based game, the call_or_pass = input() was here followed by the below if/elif block
if self.user_choice == 'call':
self.prompt_text.config(text='You selected call')
elif self.user_choice == 'pass':
self.prompt_text.config(text='You selected pass')
However, I can't figure out setting the path of the conditional block in select_button
equal to the result of the clicked button.
- I know that the if/elif code in
select_button
doesn't work because no button has been clicked, thusself.user_choice
is equal toNone
. - I tried writing a while loop above the block in
select_button
, but that creates an infinite loop. - I know that I need to return the value of the if/elif in
button_choice
toselect_button
, but givenbutton_choice
is bound to the buttons, I can't call it fromselect_button
. - I know that I could update the text within
button_choice
, but the broader goal is to run many lines of code which is better suited for the separateselect_button
function.
Any help would be greatly appreciated. I can provide additional context or code as requested. The full debug program is 67 lines. I tried to keep the code snippets above as succinct as possible while giving enough context.
Thanks.
英文:
I am converting a text based card game, written in Python 3, to a UI via tkinter. There are many instances where the player is prompted to make a choice. Getting this choice in text format is easy, however I am stuck trying to get this choice using buttons.
In the text based game I can easily get the player's choice through a variable set equal to input and then run resulting lines of code.
call_or_pass = user_input('What do you choose?')
if call:
code that does stuff
elif pass:
other code that does stuff
Then lots more code after this...
I am struggling to translate this code to tkinter UI. Keep in mind choice prompts and the buttons used to make the choice must appear in specific instances. My program is built within a class. A variable to track player choices, self.user_choice, is defined in the init and set to None by default. The buttons are created above .mainloop() within the UI code.
#buttons
self.call_button = tk.Button(text='Call', font=self.medium, command=lambda: self.button_choice('call'))
self.pass_button = tk.Button(text='Pass', font=self.medium, command=lambda: self.button_choice('pass'))
The buttons are bound to a function called button_choice. Each button passes an argument to this function that updates the self.user_choice variable.
def button_choice(self, choice):
if choice == 'call':
self.user_choice = 'call'
elif choice == 'pass':
self.user_choice = 'pass'
When a choice prompt occurs, the buttons are drawn to the UI with a place_buttons function. But, I am calling place_buttons in the specific instance with the function select_button. Once the update to self.user_choice is made, the program should run one of two conditional block options within select_button. For debugging purposes, I am trying to change some text at the top of a window.
#draws the button to the UI when called
def place_buttons(self):
self.call_button.place(x=self.window_width - (self.window_width * .58), y=self.window_height - (self.window_height * .38))
self.pass_button.place(x=self.window_width - (self.window_width * .48), y=self.window_height - (self.window_height * .38))
#function for a specific choice prompt instance
def select_button(self):
self.place_buttons()
#in the text based game, the call_or_pass = input() was here followed by the below if/elif block
if self.user_choice == 'call':
self.prompt_text.config(text='You selected call')
elif self.user_choice == 'pass':
self.prompt_text.config(text='You selected pass')
However, I can't figure out setting the path of the conditional block in select_button equal to the result of the clicked button.
- I know that the if/elif code in select_button doesn't work because no button has been clicked, thus self.user_choice is equal to None.
- I tried writing a while loop above the block in select_button but that creates an infinite loop.
- I know that I need to return the value of the if/elif in button_choice to select_button, but given button_choice is bound to the buttons, I can't call it from select_button.
- I know that I could update the text within the button_choice, but the broader goal is to run many lines of code which is better suited for the separate select_button function.
Any help would be greatly appreciated. I can provide additional context or code as requested. The full debug program is 67 lines. I tried to keep the code snippets above as succinct as possible while giving enough context.
Thanks.
答案1
得分: 0
不确定这是否是您正在寻找的内容。
这使您可以配置2个按钮的命令,以带您进入新的功能。只要每个功能都带您进入另一个功能,就可以无限延续。
这的主要部分是button_choice
和rebind_buttons
方法,通过将要调用的方法作为参数传递给lambda函数,您可以变化代码下一步采取的操作。我添加了**kwargs作为如何传递不同数量的数据的示例。
from tkinter import *
class myGame:
def __init__(self):
self.root = Tk()
self.callbutton = None
self.passbutton = None
self.prompt_text = None
def button_choice(self, choice, callback, **kwargs):
callback(choice, **kwargs)
def rebind_buttons(self, command, **kwargs):
print("重新绑定按钮以运行新命令")
self.callbutton.configure(command=lambda c=self.callbutton.cget('text').lower(), f=command: self.button_choice(c, f, **kwargs))
self.passbutton.configure(command=lambda c=self.passbutton.cget('text').lower(), f=command: self.button_choice(c, f, **kwargs))
def starter(self):
self.rebind_buttons(self.q2)
def q2(self, choice, **kwargs): ## 游戏示例
if choice == "call":
self.prompt_text.configure(text="用户打电话了")
self.rebind_buttons(self.q3) ##这里设置下一个函数的操作
elif choice == "pass":
self.prompt_text.configure(text="用户放弃了")
self.rebind_buttons(self.q3, item="hat") ##这里设置下一个函数的操作,它接受**kwargs,以便传递需要的数据。
def q3(self, choice, **kwargs): ## 另一个游戏示例。这次kwargs被发送,以便您可以基于它做决定。
if choice == "call":
if kwargs.pop('item', None) is None:
self.prompt_text.configure(text="用户打电话了,但没有帽子")
else:
self.prompt_text.configure(text="用户打电话了,他戴上了帽子")
#self.rebind_buttons(self.q3) # 这应该是下一部分
elif choice == "pass":
if kwargs.pop('item', None) is None:
self.prompt_text.configure(text="用户放弃了,失去了他的帽子")
else:
self.prompt_text.configure(text="用户放弃了,没有帽子,他必须回去")
self.rebind_buttons(self.q2)
def main(self):
self.prompt_text = Label(self.root, text="")
self.prompt_text.pack(side=TOP)
##创建按钮
self.callbutton = Button(self.root, text="Call", command=lambda c='call', f=None:self.button_choice(c, f))
self.passbutton = Button(self.root, text="Pass", command=lambda c='pass', f=None:self.button_choice(c, f))
self.callbutton.pack(side=LEFT)
self.passbutton.pack(side=RIGHT)
self.starter() ##创建第一个选择
self.root.mainloop()
if __name__ == "__main__":
game = myGame()
game.main()
英文:
Not sure if this is what you are looking for.
This lets you configure the command of the 2 buttons to take you to a new function. as long as each function takes you to another one it can be endless.
The main part of this is the button_choice
and rebind_buttons
methods
by passing the method you want to call next as an argument into the lambda function you can vary what actions your code takes next. I added **kwargs as example on how you can pass varying amounts of data through as well.
from tkinter import *
class myGame:
def __init__(self):
self.root = Tk()
self.callbutton = None
self.passbutton = None
self.prompt_text = None
def button_choice(self, choice, callback, **kwargs):
callback(choice, **kwargs)
def rebind_buttons(self, command, **kwargs):
print("rebinding buttons to run new command")
self.callbutton.configure(command=lambda c=self.callbutton.cget('text').lower(), f=command: self.button_choice(c, f, **kwargs))
self.passbutton.configure(command=lambda c=self.passbutton.cget('text').lower(), f=command: self.button_choice(c, f, **kwargs))
def starter(self):
self.rebind_buttons(self.q2)
def q2(self, choice, **kwargs): ## just an example of a game
if choice == "call":
self.prompt_text.configure(text="The user called")
self.rebind_buttons(self.q3) ##this is where you set the action to the next function
elif choice == "pass":
self.prompt_text.configure(text="The user passed")
self.rebind_buttons(self.q3, item="hat") ##this is where you set the action to the next function, it accepts **kwargs so data can be passed if needed.
def q3(self, choice, **kwargs): ## another example of a game. this time kwargs are being sent so you can make decisions based on that.
if choice == "call":
if kwargs.pop('item', None) is None:
self.prompt_text.configure(text="The user called but doesnt have a hat")
else:
self.prompt_text.configure(text="The user called he put on his hat")
#self.rebind_buttons(self.q3) # this should be the next part
elif choice == "pass":
if kwargs.pop('item', None) is None:
self.prompt_text.configure(text="The user passed and lost his hat")
else:
self.prompt_text.configure(text="The user passed, without a hat he has to go back")
self.rebind_buttons(self.q2)
def main(self):
self.prompt_text = Label(self.root, text="")
self.prompt_text.pack(side=TOP)
##creates the buttons
self.callbutton = Button(self.root, text="Call", command=lambda c='call', f=None:self.button_choice(c, f))
self.passbutton = Button(self.root, text="Pass", command=lambda c='pass', f=None:self.button_choice(c, f))
self.callbutton.pack(side=LEFT)
self.passbutton.pack(side=RIGHT)
self.starter() ##creates the first choice
self.root.mainloop()
if __name__ == "__main__":
game = myGame()
game.main()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论