I'm trying to use a function which a placed inside the class of Tkinder but the function(aktodec) can't be found and a get an error. I don't wanna call the def as a command of a button but as a function that will give value to one of my variables
from Tkinter import *
class ADialog:
def __init__(self, parent):
top = self.top = Toplevel(parent)
Label(top, text="Number to convert").pack()
self.numb = Entry(top)
self.numb.pack(padx=15)
Label(top, text="Base of incered number").pack()
self.base = Entry(top)
self.base.pack(padx=15)
Label(top, text="Base you want to be converted").pack()
self.basemet=Entry(top)
self.basemet.pack(padx=15)
b = Button(top, text="OK", command=self.met)
b.pack(pady=5)
def aktodec(self,num,base): #####commands
dec=0
num=num[::-1]
for i in range(len(num)):
s=int(num1[i])*(int(base)**i)
dec=dec+s
def met(self):
num=self.numb=str(self.numb.get())
base=self.base =int(self.base.get())
basemet=self.basemet=int(self.basemet.get())
if base==basemet:
Label(root,text="The number "+self.numb+"is converted to"+self.numb) ##why can't be print??
if base==10:
new=num
else:
new1=self.aktodec(num,base) ####why aktodec doesn't give value to "new"??
Label(root,text="Number is"+str(new))
self.top.destroy()
root = Tk()
def open_dialog():
dial = ADialog(root)
root.wait_window(dial.top)
root.wm_geometry("400x300+20+40")
message=StringVar()
message.set("Complete the form")
Label(root, textvariable=message).pack(padx=30)
root.update()
message.set("Form completed")
Button(root, text="Done", command=root.destroy).pack()
Button(root, text="new", command=open_dialog).pack()
root.update()
root.mainloop()
And also I have a problem whith the label
Label(root,text="The number "+self.numb+"is converted to"+self.numb
which (i don't know why) won't appear to the root even the base=basemet. Help please(it's for a project in this week)!
In Python, a function can't modify some arguments(integers, strings) as perceived by the caller, they are immutable. However, some objects like lists are mutable.
def aktodec(self,num,base):
dec=0
num=num[::-1]
for i in range(len(num)):
s=int(num1[i])*(int(base)**i)
dec=dec+s
return dec
def met(self):
num=self.numb=str(self.numb.get())
base=self.base =int(self.base.get())
basemet=self.basemet=int(self.basemet.get())
new = num
if base==basemet:
Label(root,text="The number "+self.numb+"is converted to"+self.numb).pack()
if base==10:
new=num
else:
new=self.aktodec(num,base)
Label(root,text="Number is"+str(new)).pack()
self.top.destroy()
Related
I can't seem to update my money counter(var money) when its labeled, I have a button that's supposed to add 0.1 to moneyNum but the money counter doesn't change. I'm new to stack overflow and would appreciate any help.(btw sry if its REALLY messy)
from tkinter import *
import random
from time import sleep
root = Tk()
root.geometry('320x320')
#spacing
spacingTitle = Label(root, text=" \n\n\n\n\n\n\n\n\n")
#title
title = Label(root, text=" \bGamblers Dream\b", font="Helvetica", fg="red")
titleWelcom = Label(root, text=" Welcom to...")
titleWelcom.grid()
title.grid()
#money counter
moneyNum = float(10.0)
money = Label(root, text="money:" + str(moneyNum), font="Helvetica")
money.grid(row=3, column=0)
#moneyClicker
def moneyButtonAdder():
global moneyNum
moneyNum = moneyNum + 0.1
moneyClicker = Button(root, text="click", fg="green", command=moneyButtonAdder)
moneyClicker.grid(row=14)
root.mainloop()
The problem is that once you create a label, you pass the string to it. Label displays the string, and:
changing a string object does not change the label text
changing the integer does not change the string - it lost the whole connection when the new string object was created
So everything is not as procedural as you would have hoped it is.
The solution - use StringVar objects and detect value changes - see this.
So, the solution is:
from tkinter import *
class Observed(object):
"""adapted copy from https://stackoverflow.com/a/6192298/10713244"""
def __init__(self):
self._observed = 10.0
self._observers = []
#property
def observed(self):
return self._observed
#observed.setter
def observed(self, value):
self._observed = value
for callback in self._observers:
print('announcing change')
callback(self._observed)
def bind_to(self, callback):
print('bound')
self._observers.append(callback)
class Observer(object):
def __init__(self, data):
self.text = ''
self.data = data
self.data.bind_to(self.update)
self.tkinter_init()
def update(self, observed):
self.text = 'float: '+str(data._observed)
self.tkinter_update()
def tkinter_init(self):
self.tk = Tk()
self.tvar = StringVar()
self.label = Label(textvariable=self.tvar)
self.label.pack()
def tkinter_update(self):
self.tvar.set(self.text)
if __name__ == '__main__':
data = Observed()
label = Observer(data)
print(label.text)
data.observed = 10.0
print(label.text)
def dec(): data.observed -= 0.1
Button(label.tk, text='decrease', command=dec).pack()
label.tk.mainloop()
Hope that's helpful!
Greetings Stack Overflowers!
Please note that I'm a novice and I'm just learning.
I'm having the following error : AttributeError: '_tkinter.tkapp' object has no attribute 'button_draw'
The main logic where the issue seems to be is located in start_game_event. Basically if the game_type is with draw, then the button must be created. However, if a new game is made based on the current windows and the button still exists, I want it to be removed. I'm not sure if there's another way to go about it, for instance regenerating the main frame completely but that's where I'm standing.
Here's the code :
from tkinter import Button, E, Frame, IntVar, Label, LEFT, messagebox, N, NE, Radiobutton, RIGHT, S, SW, StringVar, Tk, Toplevel, W
class DominoWindow(Tk):
def __init__(self):
super().__init__()
self.nb_players_var = None
self.type_partie = None
self.title('Jeu de Pydomino!')
self.resizable(width=False, height=False)
self.frame_player_north = Frame(self)
self.frame_player_west = Frame(self)
self.frame_table = Frame(self, borderwidth=2)
self.frame_player_est = Frame(self)
self.frame_current_player = Frame(self)
self.frame_player_north.grid(row=0, column=1)
self.frame_player_west.grid(row=1, column=0)
self.frame_table.grid(row=1, column=1)
self.frame_player_est.grid(row=1, column=2)
self.frame_current_player.grid(row=2, column=1)
self.label_name_player_north = Label(self.frame_player_north)
self.label_name_player_north.grid(row=0)
self.label_hand_player_north = Label(self.frame_player_north)
self.label_hand_player_north.grid(row=1)
self.label_name_player_west = Label(self.frame_player_west)
self.label_name_player_west.grid(row=0)
self.label_hand_player_west = Label(self.frame_player_west)
self.label_hand_player_west.grid(row=1)
self.label_table = Label(self.frame_table, height=8, width=100)
self.label_table.grid(row=0, column=0)
self.label_name_player_east = Label(self.frame_player_est)
self.label_name_player_east.grid(row=0)
self.label_hand_player_east = Label(self.frame_player_est)
self.label_hand_player_east.grid(row=1)
self.label_name_current_player = Label(self.frame_current_player)
self.label_name_current_player.grid(row=1)
self.frame_hand_current_player = Frame(self.frame_current_player)
self.button_quit = Button(self, text="Quitter", command=self.quit_party_event)
self.button_quit.grid(row=3, column=2)
self.button_new_game = Button(self, text="Nouvelle partie", command=self.introduction_game)
self.button_new_game.grid(row=2, column=2)
self.introduction_game()
def show(self):
if self.nb_players_var.get() == 2:
self.label_name_player_north.config(text="Player 0")
self.label_hand_player_north.config(text="[|]" * 6) #len(self.partie.donnes[self.partie.tour+1]))
self.label_table.config(text="VARIABLE_TABLE")
self.label_name_current_player.config(text="Player Current")
self.label_name_player_east.config(text="")
self.label_hand_player_east.config(text="")
self.label_name_player_west.config(text="")
self.label_hand_player_west.config(text="")
elif self.nb_players_var.get() == 3:
self.label_name_player_north.config(text="Player 0")
self.label_hand_player_north.config(text="[|]" * 6) #len(partie.Partie.donnes[partie.tour+1]))
self.label_name_player_east.config(text="Player 1")
self.label_hand_player_east.config(text="[|]\n" * 6) #len(self.partie.donnes[self.partie.tour+2]))
self.label_table.config(text="VARIABLE DU PLATEAU")
self.label_name_current_player.config(text="Player Current")
self.label_name_player_west.config(text="")
self.label_hand_player_west.config(text="")
elif self.nb_players_var.get() == 4:
self.label_name_player_north.config(text="Player 0")
self.label_hand_player_north.config(text="[|]" * 6) #len(self.partie.donnes[self.partie.tour+1]))
self.label_name_player_east.config(text="Player 1")
self.label_hand_player_east.config(text="[|]\n" * 6) #len(self.partie.donnes[self.partie.tour+2]))
self.label_name_player_west.config(text="Player 3")
self.label_hand_player_west.config(text="[|]\n" * 6) #len(self.partie.donnes[self.partir.tour+3]))
self.label_table.config(text="VARIABLE_DU_PLATEAU")
self.label_name_current_player.config(text="Player Current")
def introduction_game(self):
self.introduction_window_game = Toplevel(self, height=200, width=500)
self.introduction_window_game.title("Choose your game settings!")
self.introduction_window_game._root().lift()
self.nb_players_var = IntVar()
self.type_partie = StringVar()
# Label(self.introduction_window_game, text="Choose your game settings!").pack()
Label(self.introduction_window_game, text="\nWhat kind of game do you want?").pack()
Radiobutton(self.introduction_window_game, text="Game without draw",
variable=self.type_partie, value="without draw").pack(anchor=W)
Radiobutton(self.introduction_window_game, text="Game with draw",
variable=self.type_partie, value="with draw").pack(anchor=W)
Label(self.introduction_window_game, text="\nCombien de Players voulez-vous?").pack()
Radiobutton(self.introduction_window_game, text="2 Players",
variable=self.nb_players_var, value=2).pack(anchor=W)
Radiobutton(self.introduction_window_game, text="3 Players",
variable=self.nb_players_var, value=3).pack(anchor=W)
Radiobutton(self.introduction_window_game, text="4 Players",
variable=self.nb_players_var, value=4).pack(anchor=W)
Button(self.introduction_window_game, text="Quit",
command=self.quit_party_event).pack(side=RIGHT)
Button(self.introduction_window_game, text="Ok",
command=self.start_game_event).pack(side=RIGHT)
def start_game_event(self):
result = messagebox.askokcancel("Paramètres de partie",
f"Vous avez choisi {self.nb_players_var.get()} Players et "
f"le type de partie {self.type_partie.get()}."
f"\nEst-ce exact?", icon='warning')
if result == True:
self.start_game()
self.show()
self.introduction_window_game.destroy()
if self.type_partie.get() == "with draw":
self.button_draw = Button(self, text="Draw", command=self.button_to_draw)
self.button_draw.grid(row=3, column=0)
else:
self.button_draw.grid_remove()
self.destroy
def quit_party_event(self):
result = messagebox.askokcancel("Quit the game.", "Are you sur?", icon='warning')
if result == True:
self.destroy()
def button_to_draw(self):
print("Function test. You drew a domino!")
def message_fin_de_partie(self):
pass
if __name__ == '__main__':
DominoWindow().mainloop()
The error is located here : self.button_draw.grid_remove()
Thank you and I hope it is all clear.
Edited : Removed dependency and adjusted the variable name. Mistype.
I'll start by saying I commented out the line self.start_game() as the start_game method doesn't exist. I'll also add that to reproduce the problem I started the app and then chose to start a game without draw with any number of players.
Ultimately it's possible to do what you appear to want: i.e. not always have the 'Draw' button. What I would do would be to add the line self.button_draw = None somewhere within __init__(). This ensures that your window always has a button_draw attribute, and hence gets rid of the AttributeError about this attribute.
Next, you will need to adjust the lower if statement within start_game_event() to remove the 'Draw' button from the grid if it has been created:
if self.type_partie.get() == "with draw":
self.button_draw = Button(self, text="Draw", command=self.button_to_draw)
self.button_draw.grid(row=3, column=0)
elif self.button_draw is not None:
self.button_draw.grid_remove()
self.button_draw.destroy()
self.button_draw = None
I've replaced the else with elif and the condition that self.button_draw isn't None: we can't remove the 'Draw' button if there's no button to remove.
Note also that I replaced the line self.destroy with self.button_draw.destroy(): the former would have closed your app had you called the method but as you didn't call self.desroy it did nothing. Also, once the button has been destroyed we can set self.button_draw back to None to signify we have no 'Draw' button.
In a similar vein, if the 'Draw' button exists and you start another game with draw, you'll have two buttons in your window. You'll only see one because one will be on top of the other. However, as you only keep a reference to one button, you'll only be able to delete one of these two buttons. I'll leave it up to you to make a similar modification to your code to only add the button if it doesn't already exist.
I have created the following checkbox popup in Python 3.5 using tkinter (see image) with the following code:
from tkinter import *
class Checkbar(Frame):
def __init__(self, parent=None, picks=[], side=LEFT, anchor=W):
Frame.__init__(self, parent)
self.vars = []
for pick in picks:
var = IntVar()
chk = Checkbutton(self, text=pick, variable=var)
chk.pack(side=side, anchor=anchor, expand=YES)
self.vars.append(var)
def state(self):
return map((lambda var: var.get()), self.vars)
if __name__ == '__main__':
root = Tk()
lng = Checkbar(root, ['DerVar1', 'DerVar2', 'DerVar3', 'DerVar4', 'DerVar5', 'DerVar6', 'DerVar7', 'DerVar8'])
tgl = Checkbar(root, ['DerVar9','DerVar10', 'DerVar11', 'DerVar12', 'DerVar13', 'DerVar14'])
lng.pack(side=TOP, fill=X)
tgl.pack(side=LEFT)
lng.config(relief=GROOVE, bd=2)
def allstates():
print(list(lng.state()), list(tgl.state()))
Button(root, text='Quit', command=root.quit).pack(side=RIGHT)
Button(root, text='Run', command=allstates).pack(side=RIGHT)
root.mainloop()
As you can see I have checked 'DerVar2' and DerVar3'. After I click run I get the following highlighted in yellow.
As you can see a 1 corresponds to a checkbox getting checked.
the variable 'lng' is a checkbar object. I want to say if 'DerVar2' is checked, then print 'test' but can't get it to work.
This is the code I have tried and below is the error I get:
if lng[1] == 1:
print ('test')
TypeError: Can't convert 'int' object to str implicitly
The problem is that your Checkbar class has no __getitem__ method so lng[1] will trigger an error. To do lng[1] == 1 without errors, just add the following method to you rCheckbar class:
def __getitem__(self, key):
return self.vars[key].get()
That way lng[i] will return the value of the i-th IntVar of the Checkbar
You need to explicitly cast to the same types to compare. Try this:
if int(lng[1]) == 1:
print ('test')
or
if lng[1] == str(1):
print ('test')
I'm writing a python script that requires the user to enter the name of a folder. For most cases, the default will suffice, but I want an entry box to appear that allows the user to over-ride the default. Here's what I have:
from Tkinter import *
import time
def main():
#some stuff
def getFolderName():
master = Tk()
folderName = Entry(master)
folderName.pack()
folderName.insert(END, 'dat' + time.strftime('%m%d%Y'))
folderName.focus_set()
createDirectoryName = folderName.get()
def callback():
global createDirectoryName
createDirectoryName = folderName.get()
return
b = Button(master, text="OK and Close", width=10, command=callback)
b.pack()
mainloop()
return createDirectoryName
getFolderName()
#other stuff happens....
return
if __name__ == '__main__':
main()
I know next to nothing about tkInter and have 2 questions.
Is over-riding the default entry using global createDirectoryName within the callback function the best way to do this?
How can I make the button close the window when you press it.
I've tried
def callback():
global createDirectoryName
createDirectoryName = folderName.get()
master.destroy
but that simply destroys the window upon running the script.
I don't know how experienced are you in Tkinter, but I suggest you use classes.
try:
from tkinter import * #3.x
except:
from Tkinter import * #2.x
class anynamehere(Tk): #you can make the class inherit from Tk directly,
def __init__(self): #__init__ is a special methoed that gets called anytime the class does
Tk.__init__(self) #it has to be called __init__
#further code here e.g.
self.frame = Frame()
self.frame.pack()
self.makeUI()
self.number = 0 # this will work in the class anywhere so you don't need global all the time
def makeUI(self):
#code to make the UI
self.number = 1 # no need for global
#answer to question No.2
Button(frame, command = self.destroy).pack()
anyname = anynamehere() #remember it alredy has Tk
anyname.mainloop()
Also why do you want to override the deafult Entry behavior ?
The solution would be to make another button and bind a command to it like this
self.enteredtext = StringVar()
self.entry = Entry(frame, textvariable = self.enteredtext)
self.entry.pack()
self.button = Button(frame, text = "Submit", command = self.getfolder, #someother options, check tkitner documentation for full list)
self.button.pack()
def getfolder(self): #make the UI in one method, command in other I suggest
text = self.enteredtext.get()
#text now has whats been entered to the entry, do what you need to with it
I'd like to have a generic method that will change the value of a tkinter variable. I want to be able to do this from a menu option that brings up a new dialog box which is from a generic method that can be used for different variables. the code I have so far is below:
import sys
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
import sequencer as seq
class View(ttk.Frame):
"""Main Gui class"""
def __init__(self, master = None):
ttk.Frame.__init__(self, master, borderwidth=5, width=450, height=500)
self.master = master
self.grid(column=0, row=0, sticky=(N, S, E, W))
self.columnconfigure(0, weight=1)
###############################
### User editable variables ###
self.precision = IntVar(value=4, name='precision')
self.sensitivity = IntVar(value = 50, name='sensitivity')
### User editable variables ###
###############################
self.create_menus()
def create_menus(self):
"""Produces the menu layout for the main window"""
self.master.option_add('*tearOff', FALSE)
self.menubar = Menu(self.master)
self.master['menu'] = self.menubar
# Menu Variables
menu_file = Menu(self.menubar)
menu_edit = Menu(self.menubar)
# Add the menus to the menubar and assign their variables
self.menubar.add_cascade(menu=menu_file, label="File")
self.menubar.add_cascade(menu=menu_edit, label = "Edit")
### ADD COMMANDS TO THE MENUES ###
### File ###
menu_file.add_command(label="Quit", command=self.master.destroy)
### Edit ###
menu_edit.add_command(label="Backbone", command=lambda : self.edit_backbone())
menu_edit.add_command(label="Precision", command=lambda : self.precision.set(self.set_value_int("Precision")))
menu_edit.add_command(label="Sensitivity", command=lambda : self.sensitivity.set(self.set_value_int("Sensitivity")))
menu_edit.add_command(label="print precision", command=lambda : print(self.precision.get()))
menu_edit.add_command(label="print sensitivity", command=lambda : print(self.sensitivity.get()))
def set_value_int(self, name):
"""Standards dialog that return a user define value of a specific type"""
t = Toplevel(self)
t.title("Set " + name)
label = ttk.Label(t, text="Set "+name)
label.grid(row=0)
entry = ttk.Entry(t)
entry.grid(row=1)
cancel = ttk.Button(t, text="Cancel", command=lambda : t.destroy())
cancel.grid(column=0, row=2)
okey = ttk.Button(t, text="Okey", command=lambda : okey(entry.get()))
okey.grid(column=1, row=2)
def okey(value):
"""return value according to type"""
try:
t.destroy()
return int(value)
except:
self.error_box("value must be and integer")
def error_box(self, error_message="Unknown error"):
"""(Frame, String) -> None
Opens an window with an Okey button and a custom error message"""
t=Toplevel(self)
t.title("Error")
label = ttk.Label(t, text=error_message)
label.grid(row=0)
okey = ttk.Button(t, text="Okey", command=lambda : t.destroy())
okey.grid(row=1)
if __name__ == "__main__":
root = Tk()
root.title("Sequencer")
view = View(root)
root.mainloop()
print("End")
The Edit-> print xxxxxx commands are purely for testing purposes to check if the values have changed. If these are executed before trying to change the values of precision or sensitivity then they work as expected.
If you try to change either of the tkinter variables in the way I have tried to do they become None types and I can't see why. I can only assume that you are not allowed to change them in the way that I have but I can't think of another way to do it without having a separated method for each variable which I'd like to avoid.
Baicly I'd like the user to be able to customise the variables precision and sensitivity and use the same method in the code to change the values.
Extra but not necessarily vital:- If there is a way to define which type the variable should be in the methods arguments as well that would be even better as I will have other variables for the user to change later and they will be of different types.
Any help would be much appreciated. I have tried to be as clear as I can but let me know if anything is not.
Thanks
self.set_value_int always returns None, so it's always going to set your variable to none.
Instead of trying to write a complex lambda that is hard to debug, put all of your logic inside the function. Have the function set the value. All you need to do is tell it what variable to set:
menu_edit.add_command(label="Precision",
command=lambda name="Precision", var=self.precision: self.set_value_int(name, var))
...
def set_value_int(self, name, var):
...
def okey():
s = entry.get()
try:
var.set(int(s))
...