import Tkinter
import random
win = Tkinter.Tk()
win.title('Dice Roller')
def mainloop():
class Die:
def __init__(self,ivalue, parent):
self.value = ivalue
self.display = Tkinter.Label(parent,relief='ridge',borderwidth=4, text=str(self.value))
def roll(self):
self.value = random.randint(1,6)
self.display.config(text=str(self.value))
class diceRoller:
def rolldice():
d1.roll()
d2.roll()
d3.roll()
def __init__(self):
self.diceList = []
self.win = Tkinter.Tk("Dice Roller")
for i in range(3):
di = Die(self.win)
self.dieList.append(di)
rolldice()
row1 = Tkinter.Frame(win)
row2 = Tkinter.Frame(win)
d1.roll.display.pack(side="left")
d2.roll.display.pack(side="left")
d3.roll.display.pack(side="left")
row1.pack()
rolldice = Tkinter.Button(row2, command=rolldice(), text = "Roll")
rolldice.pack()
row2.pack()
win.mainloop()
I'm having trouble with my python code with Tkinter. I'm trying to get it to produce a window with three buttons that present the numbers rolled on the dice and another that lets me re roll the dice.
The code you have inside class diceRoller under the method rolldice has to be in some method. It cannot just stay in a class. Create a method using def and add that code to it.
If a name of a method is __init__, it is called a constructor. A constructor is a method that will be called when the object is created (i.e. when you do diceRoller()). You perhaps should put the code, that's now just laying inside diceRoller into such a method/constructor, I don't know (you should know if that's the case).
Note: In Python we usually write first characters of class names uppercase.
Related
I am trying to create the function 'count' that takes in an integer in the form of a variable, and adds 1 to it every time the return key is pressed, saving to the variable each time.
The argument needs to remain generic, because in the future this will run the same 'count' function on multiple variables depending on which button is pressed.
I've tried making messi a global variable by putting global messi at the top, but the same problem occurs.
import tkinter as tk
class PlayerStats:
def __init__(self, name, touches):
team = "Barcelona"
self.name = name
self.touches = touches
def count(number):
number = number + 1
print(number)
messi = PlayerStats("Messi",0)
root = tk.Tk()
root.bind('<Return>', lambda event :PlayerStats.count(messi.touches))
root.mainloop()
When I run this snippet, it iterates it once, from 0 to 1, and then resets always printing out 1.
Any thoughts on why this is happening and how to fix would be appreciated!!
You are not saving the result of the operation.
You're instanciating your PlayerStats class with a value of 0 for touches.
That value is then never mutated throughout your code.
When tkinter is calling your count method, it increments number but that variable never leaves the scope of the method, and is thus garbage collected.
To fix it, you should change your class to something like
import tkinter as tk
class PlayerStats:
def __init__(self, name, touches):
team = "Barcelona"
self.name = name
self.touches = touches
def count(self): # the first argument of a method is always a reference to the instance
self.touches += 1
print(self.touches)
messi = PlayerStats("Messi", 0)
root = tk.Tk()
root.bind('<Return>', lambda event: messi.count()) # You need to call the method on the instance you created.
root.mainloop()
Thanks for your help Dogeek. My functioning code from above now looks like this:
import tkinter as tk
class PlayerStats:
def __init__(self, name, touches):
team = "Barcelona"
self.name = name
self.touches = touches
def count(self, number):
self.touches += 1
print(number)
messi = PlayerStats("Messi",0)
root = tk.Tk()
root.bind('<Return>', lambda event :messi.count(messi.touches))
root.mainloop()
One thing this does not solve though is the ability to reuse that function for different variables. I am now trying to come up with an elegant way to do something like this:
import tkinter as tk
class PlayerStats:
def __init__(self, name, touches, shots):
team = "Barcelona"
self.name = name
self.touches = touches
self.shots = shots
def count(self, number):
self.number += 1
print(number)
messi = PlayerStats("Messi",0)
root = tk.Tk()
root.bind('<Return>', lambda event :messi.count(messi.touches))
root.bind('<s>', lambda event :messi.count(messi.shots))
root.mainloop()
where number represents either messi.shots or messi.touches depending on what key is pressed. I'd like to do this without recreating a bunch of nearly identical functions for each key.
I have a problem related to a TKinter GUI I am creating, but the problem is not necessarily specific to this library.
Background
I am currently in the advanced stage of a python self-learning course. The learning module I am on is covering TKinter for creating interactive GUI's. I am making a game whereby randomly generated numbered buttons must be clicked in succession in the quickest time possible.
Brief: https://edube.org/learn/pcpp1-4-gui-programming/lab-the-clicker
Problem
Under my class, game_grid, I have created an instance variable; 'self.holder', a 25 entry dictionary of {Key : TkinterButtonObject} form
When calling this instance variable for use in a class method, I get the following error:
AttributeError: 'game_grid' object has no attribute 'holder'
I have a print statement under class init which proves this attribute has been successfully created. I have made sure my spacing and tabs are all OK, and have tried every location for this variable, including using as a class variable, and a global variable to no avail - as it is an semi-complex object. I don't see what difference it should make, but any ideas would be much appreciated. I am also aware this could be done without classes, but I am trying to adopt DRY principles and orthogonality in all of my programs.
Thanks in advance.
Full Code:
import tkinter as tk
from tkinter import*
import random
from tkinter import messagebox
import time
win = tk.Tk()
class game_grid:
def __init__(self, win):
self.last_number = 0
self.number_buttons = {}
self.row_count = 0
self.column_count = 0
#Generate a list of 25 random numbers
self.number_list = random.sample(range(0, 999), 25)
#Puts the numbers in a dictionary (number : buttonobject)
self.holder = {i: tk.Button(win, text = str(i), command = game_grid.select_button(self, i)) for i in self.number_list}
#pack each object into window by iterating rows and columns
for key in self.holder:
self.holder[key].grid(column = self.column_count, row = self.row_count)
if self.column_count < 4:
self.column_count += 1
elif self.column_count == 4:
self.column_count = 0
self.row_count += 1
print(self.holder)
def select_button(self, number):
if number > self.last_number:
self.holder[number].config(state=tk.DISABLED)
self.last_number = number
else:
pass
class stopclock():
def __init__(self):
#Stopclock variable initialisation
self.time_begin = 0
self.time_end = 0
self.time_elapsed= 0
def start(self):
if self.time_begin == 0:
self.time_begin = time.time()
return("Timer started\nStart time: ", self.time_begin)
else:
return("Timer already active")
def stop(self):
self.time_end = time.time()
self.time_elapsed = time_end - time_begin
return("Timer finished\nEnd time: ", time_begin,"\nTime Elapsed: ", time_elapsed)
play1 = game_grid(win)
win.mainloop()
Perhaps you meant:
command = self.select_button(self, i)
Update:
Though from research:How to pass arguments to a Button command in Tkinter?
It should be:
command = lambda i=i: self.select_button(i)
You call select_button from inside the dict comprehension of holder. select_button then tries to use holder, but it is not yet defined. You don't want to actually call select_button, but assign a function to the button, like that:
self.holder = {i: tk.Button(window, text=str(i), command=lambda i=i: self.select_button(i)) for i in self.number_list}
I want to use the bot_create function with a button but I keep getting (on line 20) the problem "bots not defined" so I moved the function down below the button but got the problem "bot_create not defined".
I didn't get this problem using C++ and I'm new to Python. How should I arrange the functions?
import tkinter as tk
import numpy as np
import multiprocessing as mp
bots_max = 1000 # Maximum number of bots
bot = []
bot_count = 0
# Menu functions
def save_field():
pass
# Field functions
def field_clear():
pass
# Bots functions
def bots_create():
bot[bot_count] = bots
bot_count += 1
main = tk.Tk()
field_sides = 600
ctrls_width = 200
main.geometry("800x600")
main.resizable(0, 0)
main.title("Swarm Simulator v1.0")
# Controls menu on left side
button1 = tk.Button(main, text = "Button 1").pack(side = "left", command = bots_create())
class environment:
def __init__():
pass
class wall:
def __init__():
pass
# Bots
class bots:
alive = True
def __init__():
alive = True
# Field where bots live
field = tk.Canvas(main, width = field_sides, height = field_sides, bg = "white").pack(side = "right")
for particle in bots:
print("|")
main.mainloop()
Here's a version of your code that fixes all the syntactic problems, and so compiles (what I really mean is that my IDE now thinks its ok). It also runs, but I don't know if it does what you intended. See my comments in the code:
import tkinter as tk
import numpy as np
import multiprocessing as mp
# moved your class defs up to fix problems with accessing them before they are defined
class environment:
def __init__(self): # need a self param here
pass
class wall:
def __init__(self): # need a self param here
pass
# Bots
class bots:
alive = True
def __init__(self): # need a self param here
alive = True
bots_max = 1000 # Maximum number of bots
bot = []
# bot_count = 0 # this no longer does anything. use `len(bot)` to get the number of objects in the 'bot' list
# Menu functions
def save_field():
pass
# Field functions
def field_clear():
pass
# Bots functions
def bots_create():
# bot[bot_count] = bots # this will crash as it is referring to a non-existent location in the list
# also, your use of "bots" here makes no sense
# bot_count += 1 # this makes 'bot_count' a local variable, which is not what you want
bot.append(bots()) # not sure this is what you want, but this creates a new 'bots' object and adds it to the 'bot' list
main = tk.Tk()
field_sides = 600
ctrls_width = 200
main.geometry("800x600")
main.resizable(0, 0)
main.title("Swarm Simulator v1.0")
# Controls menu on left side
button1 = tk.Button(main, text = "Button 1").pack(side = "left", command = bots_create())
# Field where bots live
field = tk.Canvas(main, width = field_sides, height = field_sides, bg = "white").pack(side = "right")
for particle in bot: # maybe you want to iterate over the 'bot' list instead of the 'bots' type?
print("|")
main.mainloop()
As #khelwood says, it seems that you should swap the use of the names bot and bots per the way you are using them
I am doing a card game.
The class is called Card:
It can give a random value with the deal() method to display a random card from the numbers 1-13
The other file will import the file name that contains the Class Card. It will call the class 5 times and be able to store it by appending it on a list and displaying it in another def called display_hand
Here is the class file:
import random
class Card:
def __init__(self):
self.__value = 0
def deal(self):
self.__value = random.randint(1, 13)
def set_value(self, value):
self.__value = value
def get_value(self):
return self.__value
def find_face_value(self):
faces = ['Joker','Ace','Two','Three','Four','Five','Six',
'Seven','Eight','Nine','Ten','Jack','Queen','King']
return faces[self.__value]
def __str__(self):
return self.find_face_value()
The program is too big so this is the def for calling the function 5 times:
def deal_hand():
# Create an empty list to append the cards.
hand = []
deal_hand = classcard3.Card()
for i in range(1, 6):
deal_hand = classcard3.Card()
deal_hand.deal()
# Create a new object in memory and assign it to the
# hand variable
w = classcard3.Card(deal_hand)
# add it to the list
hand.append(w)
return hand
Here is the display function:
def display_hand(hand):
print ("The 5-card hand is: ")
for item in hand:
print(hand)
This is not showing anything except for the print inside the loop. How can I pass it to the display hand to show the cards?
This is the only thing that shows whenever I use the print function inside the loop. I'm trying to use it outside and I have no idea what I'm doing wrong. My apologies if I'm not explaining this too well. I'm a beginner at python and new to this website. Thanks
deal Four
deal Three
deal Five
deal Six
deal Queen
The only error that I'm getting from this is:
line 274, in deal_hand
w = classcard3.Card(deal_hand)
TypeError: __init__() takes 1 positional argument but 2 were given
This doesn't make sense, because I'm doing it just as the book says and is not willing to display the values
I am making a basic RPG style game. I have made different classes for the various parts of the code, one for each of the main items involved (hero, door, monsters etc.)
For both the hero and door, i assign them random locations, shown below in the code, but for the door I run a while loop which makes sure that the door is a certain distance from the hero (using pythagorus).
However the while loop in the door class won't work as it always uses a value of 0 for both heroC and heroR (row and column of the hero). I am relatively new to using classes, but it doesnt seem to make sense as in HeroLocation I assign a random integer to these variables, and HeroLocation is called before DoorLocation.
Any help would be greatly appreciated!!
class Hero(Character):
def __init__(self):
super(Hero, self).__init__(10, 10, 1, 1, 0, 1)
self.herolocations = list(range(1,6)) + list(range(10,14))
self.heroC = 0
self.heroR = 0
def HeroLocation(self):
#place hero
self.heroC = random.choice(self.herolocations)
self.heroR = random.choice(self.herolocations)
class Door:
def __init__(self):
self.hero = Hero()
self.doorC = 0
self.doorR = 0
def DoorLocation(self):
while ((self.hero.heroC-self.doorC)**2+(self.hero.heroR-self.doorR)**2) <= 128:
self.doorC = random.randint(1, 13)
self.doorR = random.randint(1, 13)
class game:
def __init__(self, parent):
self.hero = Hero()
self.door = Door()
def MakeMap(self):
self.hero.HeroLocation()
self.herol = self.Main_game.create_image(15+30*self.hero.heroC,15+30*self.hero.heroR, image = self.heroimage)
self.door.DoorLocation()
self.doorl = self.Main_game.create_image(15+30*self.door.doorC,15+30*self.door.doorR, image = self.exitdoor)
NB there is a lot more code, but i have only posted what i felt was the relevant stuff, if you need more to crack the puzzle message me!
You are not calling the good Hero instance in Door.DoorLocation.
Btw I really advice you to change class & methods name following Pep 8.
In Door.__init__, first line:
self.hero = Hero()
Here, you are instantiating a new Hero's instance. But, in game.MakeMap you are calling self.hero.HeroLocation().
This self.hero instance is not the same, because it was instantiated in game.__init__ and not in Door.__init__.
I didn't try, but check what behaviour gives this update:
class game:
def __init__(self, parent):
self.door = Door()
self.hero = self.door.hero
With this you now are calling the instance defined in Door.__init__, so when doing self.hero.HeroLocation() in game and (self.hero.heroC-self.doorC [...] in Door you are pointing the same instance.
Last thing, this solution may works, but is surely not what you really wants, I think a door should not store a hero, a hero should not store a door too, but here is more complex question about patterns.