Passing variable from one function to another in same class? - python

I'm trying to create a button that changes colors on click.
After digging around in an old Python book I haven't looked at in years, I've gotten to the point where I make the the button, but I can't figure out how to pass i into the second function so it increments and is then is reset to 0.
I suppose I could just increment I on click in the first function, but now I'm annoyed and want to figure it out.
Instead of self.change_color I tried change_color(i). That threw an error. Same with trying self.change_color(i).
I'm not sure what to do at this point.
import tkinter
class joeGUI:
def __init__(self):
i = 0
colorArray = ['blue','DarkGreen','red','yellow']
self.main_window = tkinter.Tk()
self.color_button = tkinter.Button(self.main_window,
text = 'Click to Change Color',
command = self.change_color,
bg = colorArray[i])
self.color_button.pack()
tkinter.mainloop()
def change_color(self):
if (count < 3):
count += 1
else:
count = 0
return count;
joe_gui = joeGUI()

Store i as a class attribute (self.i = 0) and change the references of count to self.i.

Related

Move Thru a Python List One Item at a Time

Still pretty new to Python, so my apologies in advance...
I'm trying to use a button to move thru a List one item at a time.
It works the first time the button is clicked and moves to the second item in the List, but subsequent clicks keep returning the same values
from tkinter import *
window=Tk()
window.title('nextArrItem')
window.geometry("300x200+10+10")
options = ["H9Iu49E6Mxs", "YuWZNV4BkkY", "mBf6kJIbXLg", "Hz-xbM6jaRY"]
print("options[0] = " + options[0])
curItemText = options[0]
nextItemText = options[1]
curItem = 0
print('curItemText = '+curItemText)
print('nextItemText = '+nextItemText)
def nextArrItem(curItem=curItem+1):
print("str(curItem) = "+str(curItem))
try:
curItemText = options[curItem]
nextItemText = options[curItem+1]
print('curItemText = '+curItemText)
print('nextItemText = '+nextItemText)
curItem = curItem + 1
except:
print("End of Array Reached")
nextButton = Button(window, text="Next Item", command=nextArrItem)
nextButton.place(x=130, y=110)
window.mainloop()
When the Window opens initially, these values are returned:
options[0] = H9Iu49E6Mxs
curItemText = H9Iu49E6Mxs
nextItemText = YuWZNV4BkkY
The first click returns the following:
str(curItem) = 1
curItemText = YuWZNV4BkkY
nextItemText = mBf6kJIbXLg
Subsequent clicks keep returning the same values, so it only advances the first time and I'm not sure how to fix it. Although it probably doesn't look like it, this is the culmination of a lot of work just to get it to this point but I'm not sure where to go from here. I have the feeling the solution is going to be a true Homer Simpson "D'oh!" moment but I've steered this boat into shallow waters and need someone to help me from running aground...
Thanks in advance!
Paul
You need to increment the parameter each time to the next highest value. Currently your code just feeds the nextArrItem function the same value each time.
You could also try something to put the curItem inside a mutable data type so that it can be updated from within the scope of the function call like this:
...
options = ["H9Iu49E6Mxs", "YuWZNV4BkkY", "mBf6kJIbXLg", "Hz-xbM6jaRY"]
curItem = [0]
...
def nextArrItem(label=label):
try:
option = options[curItem[0]]
print(option)
label["text"] = option # updates label on each call
curItem[0] += 1 # increments index for option text
except IndexError:
print("End of Array Reached")
...
nextButton = Button(window, text="Next Item", command=nextArrItem)
...
Another way of doing it would be to bind the curItem variable to the window itself like this:
from tkinter import *
window=Tk()
window.curItem = 0
window.title('nextArrItem')
window.geometry("300x200+10+10")
options = ["H9Iu49E6Mxs", "YuWZNV4BkkY", "mBf6kJIbXLg", "Hz-xbM6jaRY"]
label = Label(window, text=options[window.curItem])
label.place(x=130, y=50)
def nextArrItem(label=label):
try:
option = options[window.curItem]
print(option)
label["text"] = option # updates label on each call
window.curItem += 1 # increments index for option text
except IndexError:
print("End of Array Reached")
nextButton = Button(window, text="Next Item", command=nextArrItem)
nextButton.place(x=130, y=110)
window.mainloop()
The issue you have is that curItem is both a global variable and a local variable in your callback function. You only ever update the local variable, so the change doesn't persist.
Here's how you're currently setting up the local variable, as an argument with a default value:
def nextArrItem(curItem=curItem+1):
The default value comes from the global variable, but it is only evaluated once, at the time the function is defined. It does not keep checking the global value, nor do changes to the local variable in the function change the global value either.
There's a better way. You can use a global statement to make it so that your function's code can directly read and write the global variable, so that there's only one curItem that everything is accessing the same way.
def nextArrItem():
global curItem
# the rest can be the same

Choosing from a List of methods in a tkinter Button

Good Day,
I'm new to this forum (and quite new to programming), so I hope my question is properly formulated.
I've been trying to create a GUI in python using tkinter, and I want to have two buttons calling methods of two different classes. One method is defining an integer, the second one is reporting content. I'd have a list of objects of the latter class, and I want to choose the right instance by the integer. Here's a MWE:
import tkinter as tk
class data:
def __init__(self, content):
self.content = content
def report(self):
print("This is reported as self.content:" + str(self.content)) #This doesnt report the correct value for some reason?
print("The Class does register the correct idx:" + str(Selector.idx))
print("Using the Dict the correct value can be returned:" + str(vocables[Selector.idx].content))
class increment:
def __init__(self):
self.idx = 0
def increase(self):
self.idx += 1
print(self.idx)
vocables[self.idx].report()
root = tk.Tk()
Selector = increment()
vocables = []
for id in range(10):
vocables.append(data(id))
# print(vocables[id].content)
CheckVocable = tk.Button(root, text="Report", command=vocables[Selector.idx].report)
CheckVocable.pack()
NextVocable = tk.Button(root, text="Increase Index", command=Selector.increase)
NextVocable.pack()
root.mainloop()
I do not understand why the print of line 8 always reports the value of the first item in the list (vocabules[0] in this instance) instead of my desired value, which is returned in all other print cases. Am I messing up the work with classes or is the button behavior confusing me?
Thanks in advance!

Python GUI shuts down when i use infinite loop

I tried to make a Clicker and I used an infinite loop, so I would raise my Variable every second. But every time I use the Button, my program crashes.
Do you have any advice how I prevent that, because I have no idea what is really happening.
import time
from tkinter import *
class Clicker :
#updates the Label
def AK_CLabel(self):
self.ClickerLabel.configure(text="Du hast " + str(self.Clicks))
#Generates Clicks
def Klicken(self):
self.Clicks += 1
self.AK_CLabel()
#raises price of Helping Elf and raises the clicks per second
def HElf(self) :
if(self.Clicks >= self.priceHElf) :
self.Clicks -= self.priceHElf
self.priceHElf = self.priceHElf * 1.2
self.Elfs += 1
self.Elfhilft()
self.AK_CLabel()
#Should make the Clicks go up by the amount of Elfs, but if I use the Button the Programm shuts down
def Elfhilft(self):
while (not time.sleep(5)):
self.Clicks = self.Bitcoins1 + self.Elfs
time.sleep(1)
def __init__(self, master):
self.master = master
self.master.title = "Der Klicker"
self.Elfs = 0
self.priceHElf = 30
self.Clicks = 30
#Buttons and Label
self.DerKnopf = Button(text = "Clicks", command = self.Klicken)
self.ClickerLabel = Label(text = "You have " +str(self.Clicks))
self.HelferElf = Button(text = "A helping Fairy", command = self.HElf)
self.DerKnopf.pack()
self.ClickerLabel.pack()
self.HelferElf.pack()
root = Tk()
my_gui = Clicker(root)
root.mainloop()
Firstly, in your example bitcoins1 is undeclared. I assume this is just a variable name you forgot to change before posting, so I renamed it to clicks in order to replicate your issue.
Second, you have your Elfhilft() function using sleep(), which is causing issues with your Tkinter app. Tkinter uses its own loop system to handle real-time stuff, and sleep will cause that loop to stall in most cases. I suggest you use an implementation of after (How to create a timer using tkinter?) in order to replicate the autoclicker-esque function I assume you're trying to implement. As an example:
def autoclick(self):
self.clicks = self.clicks + self.Elfs
#In main app / __init__()
root.after(1000, self.autoclick) # updates auto-clicks every second

Python Tkinter preventing button command from executing

I'm trying to get the last few lines of the following code to have when one of the original 6 buttons is pressed to call the appropriate function to rename the buttons. I've tried changing the command line to buttons[0].command = Pistols(). I've also tried using a if loop with a variable such as x == 1 to determine that if the button is pressed x with then be 1 and the for loop will call the function Pistols, but with no success. However the button automatically calls the function and renames the first button to ".44 Pistol" rather than what it should be "Pistols". I wan't the command to only be executed and call the function when pressed. I know that tkinter will automatically look to the function being called and run it's code. How can I either delay this or go about this in another way to have the functions code only execute when pressed. Thanks in advance!
from tkinter import *
buttons = []
clm = [1,2,1,2,1,2]
rw = [1,1,2,2,3,3]
btnmain_list = ['Pistol','Rifle','Assult Rifle','Submachine Gun','Heavy Weapon','Plasma Weapons']
btnpistol_list = ['.44 Pistol', '10mm Pistol', 'Pipe Bolt-Action Pistol','Flare Gun', 'Pipe Pistol', 'Pipe Revolver']
btnrifle_list = []
btnasrifle_list = []
btnsubgun_list = []
btnheavy_list = []
btnplasma_list = []
ms = Tk()
ms.title('Fallout 4 weapon mods and needed materials')
ms.geometry('450x400')
placement = Frame(ms)
placement.grid()
class Guns:
def Pistols ():
buttons[0] = Button(placement,height = '5',width = '20', text = btnpistol_list[0])
buttons[0].grid(column = clm[0], row = rw[0])
def Rifles ():
x = 0
def AssultRifles ():
x = 0
def SubmachineGuns ():
x = 0
def HeavyWeapons ():
x = 0
def PlasmaWeapons ():
x = 0
for i in range (6):
b = Button(placement,height = '5',width = '20', text = btnmain_list[i])
b.grid(column = clm[i], row = rw[i])
buttons.append(b)
buttons[0].command = Pistols()
I've found a solution by changing the class to this:
class Guns:
global counter
counter = 0
def pistolCycle():
global counter
buttons[0].config(text=btnpistol_list[counter])
if counter == len(btnpistol_list)-1:
counter=0
counter = counter+1
def Pistols ():
buttons[0] = Button(placement, height = '5',width = '20', text="Pistols", command = lambda: Guns.pistolCycle() )
buttons[0].grid(column = clm[0], row = rw[0])
def Rifles ():
x = 0
def AssultRifles ():
x = 0
def SubmachineGuns ():
x = 0
def HeavyWeapons ():
x = 0
def PlasmaWeapons ():
x = 0
for i in range (6):
b = Button(placement,height = '5',width = '20', text = btnmain_list[i])
b.grid(column = clm[i], row = rw[i])
buttons.append(b)
Pistols()
So, here's a breakdown of what happens:
Once your buttons are defined, the Pistol function is called, which adds all the features to your Pistol button, including changing the text, and adding the function it will call when pressed.
When the button is pressed, it calls to pistolCycle. What pistol cycle does, is takes the "counter" value, and changes the text of the button to the item in the list which is associated to it. EG, when the counter is 0, .44 Pistol is displayed.
The counter increases by one, each time pistolCycle is called, meaning the next time it's called, it will display the next item in the list.
Now, using global variables can get messy. I've given you the basic framework, so you may be able to use your own logic to get the variable "counter" to pass into pistolCycle each time (EG, pistolCycle(counter))
You will need to make a separate counter and cycle function in order for all the buttons to work.
I hope this helped!!
PS: The if statement in the pistolCycle function means that it wont try and get an item when it doesn't exist in the list.

Moving/Hiding a button in vpython

How do I hide a button or simply move it off the screen in VPython?
I have tried:
del button
button.visible = False
button.pos.x = 500 # well off the screen
None of those seem to work.
I figured it out. Open Lib\site-packages\vis\controls.py(in your python folder). Find the button class. Insert this function at the bottom.
class button(ctrl):
...
def _set_visible(self,value):
self.box1.visible = value
self.box2.visible = value
self.box3.visible = value
self.box4.visible = value
self.button.visible = value
self.label.visible = value
def _get_visible(self):
return self.box1.visible
visible =property(_get_visible,_set_visible)

Categories