I'm attempting to create a program that does a handful of different tasks; in this case calculating a die roll. I've created the function for calculating the roll and am having two issues. First, even though the print statements are in the dice_roll function (which shouldn't run through until the button is pressed) it's printing as soon as the program is launched, so it's not waiting for the user selections in the OptionMenus. I can't figure out why this is occurring when based on how I have it setup it shouldn't run or print anything until the button is pressed.
Secondly, when I do use the dropdown menu to make a selection it's returning the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\wildc\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 1948, in __call__
return self.func(*args)
^^^^^^^^^^^^^^^^
File "C:\Users\wildc\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 4012, in __call__
self.__var.set(self.__value)
TypeError: Variable.set() missing 1 required positional argument: 'value'
I've tried re-structuring the program several times, and I'm expecting the program to take the user inputs from the options menu, run the calculation, and then print the solution (To the console for now, and then eventually to the Entry() box in the program). At first I had the die_roll function nested inside of roll calc since the program is packing the widgets into frame two and then clearing them for the next section; I moved it hoping that it would resolve the issue but it didn't.
import tkinter as tk
from tkinter import *
from random import *
import tkinter
app = Tk()
app.title("Placeholder Title")
app.geometry('750x750')
frame1 = Frame(app, padx = 5, pady = 5)
frame1.grid(row = 0, column = 1)
frame2 = Frame(app, padx = 5, pady = 5)
frame2.grid(row = 0, column = 2)
rand_die = 0
def die_roll(dice, nums, mods):
variable_dice = dice
if variable_dice == 'D4':
rand_die == 4
elif variable_dice == 'D6':
rand_die == 6
elif variable_dice == 'D8':
rand_die == 8
elif variable_dice == 'D10':
rand_die == 10
elif variable_dice == 'D12':
rand_die == 12
elif variable_dice == 'D20':
rand_die == 20
rand_roll = randrange(0, rand_die 1)
num_die = nums
mod = mods
print(rand_roll, num_die, mod)
solution = (rand_roll * num_die) mod
print(solution)
def clear():
for widgets in frame2.winfo_children():
widgets.destroy()
def roll_calc():
myStr = ' '
rand_die = 0
Dice= [
'D4',
'D6',
'D6',
'D10',
'D12',
'D20'
]
number = [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
]
modifier = [
-10,
-9,
-8,
-7,
-6,
-5,
-4,
-3,
-2,
-1,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
]
variable_num = IntVar(frame2)
variable_dice = StringVar(frame2)
variable_mod = IntVar(frame2)
variable_dice.set(Dice[0])
variable_num.set(number[0])
variable_mod.set(modifier[10])
close_btn = Button(frame2, text = 'Close Dice Roller', command = clear).pack(side = LEFT, padx = 5, pady = 5)
diceMenu = OptionMenu(frame2, Variable, variable_dice, *Dice)
dice_label = tk.Label(frame2, text = "Dice")
dice_label.pack()
diceMenu.pack()
numMenu = OptionMenu(frame2, Variable, variable_num, *number)
num_label = tk.Label(frame2, text = 'Number of dice')
num_label.pack()
numMenu.pack()
modMenu = OptionMenu(frame2, Variable, variable_mod, *modifier)
mod_label = tk.Label(frame2, text = 'Modifier')
mod_label.pack()
modMenu.pack()
disp_tf = Entry(frame2)
disp_tf.pack(expand = True)
die_button = Button(frame2, text = "Roll The Dice", command = die_roll(variable_dice.get(), variable_num.get(), variable_mod.get())).pack()
if __name__ == "__main__":
npc_btn = Button(frame1, text = 'NPCs').pack(padx = 5, pady = 5)
notes_btn = Button(frame1, text = 'Notes').pack(padx = 5, pady = 5)
roll_btn = Button(frame1, text = 'Roll', command = roll_calc).pack(padx = 5, pady = 5)
app.mainloop()
CodePudding user response:
There are few issues in your code:
command = die_roll(...)
will executedie_roll(...)
immediately without clicking the button. Usecommand = lambda: die_roll(...)
. (I thinkdie_roll
is typo, it should bedice_roll()
instead)In
OptionMenu(frame_2, Variable, variable_xxx, ...)
, the second argument should be a reference to aStringVar
, butVariable
is a class name. It should be removed because the required argument is the third argument actually. So it should beOptionMenu(frame_2, variable_xxx, ...)
instead.Inside
die_roll()
, there are lines likerand_die == ...
which should be assignment statements likerand_die = ...
instead.
Required changes in code:
...
def die_roll(dice, nums, mods):
variable_dice = dice
if variable_dice == 'D4':
rand_die = 4 ### changed from rand_die == 4
elif variable_dice == 'D6':
rand_die = 6 ### changed from rand_die == 6
elif variable_dice == 'D8':
rand_die = 8 ### changed from rand_die == 8
elif variable_dice == 'D10':
rand_die = 10 ### changed from rand_die == 10
elif variable_dice == 'D12':
rand_die = 12 ### changed from rand_die == 12
elif variable_dice == 'D20':
rand_die = 20 ### changed from rand_die == 20
rand_roll = randrange(0, rand_die 1)
num_die = nums
mod = mods
print(rand_roll, num_die, mod)
solution = (rand_roll * num_die) mod
print(solution)
...
def roll_calc():
...
diceMenu = OptionMenu(frame2, variable_dice, *Dice) ### removed Variable argument
dice_label = tk.Label(frame2, text = "Dice")
dice_label.pack()
diceMenu.pack()
numMenu = OptionMenu(frame2, variable_num, *number) ### removed Variable argument
num_label = tk.Label(frame2, text = 'Number of dice')
num_label.pack()
numMenu.pack()
modMenu = OptionMenu(frame2, variable_mod, *modifier) ### removed Variable argument
mod_label = tk.Label(frame2, text = 'Modifier')
mod_label.pack()
modMenu.pack()
disp_tf = Entry(frame2)
disp_tf.pack(expand = True)
die_button = Button(frame2, text = "Roll The Dice", command = lambda: die_roll(variable_dice.get(), variable_num.get(), variable_mod.get())).pack()
# used lambda ^^^^^^
...