Kivy find out which Button called the Function - python

I have a List which I go through and generate a Button for each element in the List. Now when I press the Button I would like to know what Text is inside the Button. Sadly I was not able to figure out how to do this.
Here is the entire Loop however the Last 3 rows are the important ones.
Listezumsortieren = [*self.root.ids.Kommentar.text]
x = 0
stelle = 0
for i in Listezumsortieren:
if x == 17:
Listezumsortieren.insert(stelle," \n")
x = 0
x = x+1
stelle = stelle + 1
if stelle > 65:
return
Zitatselbst = ''.join(Listezumsortieren)
btn = Button(text = '\n"' + Zitatselbst + '"' + "\n ~" + self.root.ids.field.text + "\n", size_hint = (0.8 , None))
btn.bind(on_press=lambda x:self.kek())
self.root.ids.Zitate.add_widget(btn)
Thanks for helping
To specify because of the first answer:
so for example if I have a list of [1,2,3] and have three buttons with the text: (1,2,3) no matter which button I click the Button will return "3" and not the actual text of the Button, Thanks for trying to help
This is because "Self" is not referring to the Button but rather to the class the Function is in (MainApp) so to be more precise I need to know how to get to the Button

Related

How to use bind "<Return>" to call a function

I know my question sounds very much like many previous questions but I can honestly not figure it out in the context of my program. I have an algorithm for the Collatz Conjecture that I would like to run through a Tkinter GUI (everything works just fine through the terminal).I have tried to bind the relevant function to the Return key and to a button but I get the same error message for both methods of entering data, which I will show below. I get the output to work perfectly on the GUI if I input through the terminal.
What I have tried is best explained through the code below. (The code above the #### line has mostly to do with making the GUI appear over my Spyder IDE and not hiding behind it.)
Code:
from tkinter import *
root = Tk()
import os
import subprocess
import platform
def raise_app(root: Tk):
root.attributes("-topmost", True)
if platform.system() == 'Darwin':
tmpl = 'tell application "System Events" to set frontmost of every process whose unix id is {} to true'
script = tmpl.format(os.getpid())
output = subprocess.check_call(['/usr/bin/osascript', '-e', script])
root.after(0, lambda: root.attributes("-topmost", False))
########################################################################
lst = []
def collatz(num):
while num != 1:
lst.append(num)
if num % 2 == 0:
num = int(num / 2)
else:
num = int(3 * num + 1)
def main(event):
collatz(num)
#Input Box
input = Entry(root, width = 10, bg = "light grey")
input.grid(row = 0, column = 0, sticky = W)
input.get()
input.bind("<Return>", main)
##Button
#button1 = Button(root, width = 10, text = "Run", command = main)
#button1.grid(row = 1, column = 0, sticky = W)
##Output box
output1 = Text(root, width = 100, height = 10, bg = "light grey")
output1.grid(row = 3, column = 0, sticky = W)
output2 = Text(root, width = 50, height = 1, bg = "white")
output2.grid(row = 2, column = 0, sticky = W)
output1.insert(END, lst)
output2.insert(END, "Number of iterations are: " + str(len(lst)))
########################################################################
raise_app(root)
root.mainloop()
When I run the code as is, the input box appears but when I click return, I get an error message:
Exception in Tkinter callback
Traceback (most recent call last):
File "/anaconda3/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "/Users/andrehuman/Desktop/Python/programs/Collatz Conjecture/Collatz_alt3.py", line 43, in main
collatz(num)
NameError: name 'num' is not defined
Exactly the same if I try and link a button to the "main" function.
When I comment the input and buttons out, and enter the number through the terminal, everything works as expected. The list of iteration numbers appear in the text box as it should. (And I can even get a Matplotlib graph to display the data visually in the terminal.) If I can get this problem sorted out I want to try and display (or embed) the Matplotlib graph in the GUI.
Anyway, that's it. Any help will be greatly appreciated.
Andre Human
name 'num' is not defined occurs because you're calling collatz(num), but the program does not understand what value you are referring to when you say num. You should assign a value to that name before using it. I assume you want the value to be the contents of your input box.
def main(event):
num = int(input.get())
collatz(num)
You will also need to copy your output1.insert and output2.insert lines to the inside of main. Right now, those lines execute before the window even appears to the user, so there's no way that they can enter a number fast enough to get collatz to trigger before the text gets written. And changing lst after the fact does nothing to the text, since it's not smart enough to notice that the list has changed.
def main(event):
num = int(input.get())
collatz(num)
#delete previous contents of text boxes
output1.delete(1.0, END)
output2.delete(1.0, END)
output1.insert(END, lst)
output2.insert(END, "Number of iterations are: " + str(len(lst)))
Another problem is that successive calls to collatz will cause lst to grow and grow, because the contents of the list from previous calls is still present. Try entering 4 into the text box, and press Enter a few times. The output will go from 2 to 4 to 6... That's not right.
This is something of a natural hazard when using mutable global state. One possible solution is to reset lst at the beginning of each collatz call.
def collatz(num):
lst.clear()
#rest of function goes here
... But I'm more inclined to make lst local to the function, and return it at the end.
def collatz(num):
lst = []
while num != 1:
lst.append(num)
if num % 2 == 0:
num = int(num / 2)
else:
num = int(3 * num + 1)
return lst
def main(event):
num = int(input.get())
lst = collatz(num)
#delete previous contents of text boxes
output1.delete(1.0, END)
output2.delete(1.0, END)
output1.insert(END, lst)
output2.insert(END, "Number of iterations are: " + str(len(lst)))
#later, just before mainloop is called...
#lst doesn't exist in this scope, so just set the text to a literal value
output1.insert(END, "[]")
output2.insert(END, "Number of iterations are: 0")

Clearing Placed Labels in Tkinter

So I have a currency which is increasing (that system is working fine). The first part updates the label every 100 ms. I have another button which triggers the second function which is supposed to clear the labels from the first. It sets home_status equal to 0 which should in theory run Money.place_forget() to clear the code. I have tested each part individually and it works but when I put the clears inside the elif statement it doesn't. It does not give me any errors, it just simply doesn't do anything (it does print END OF UPDATE HOME so the elif is triggered).
Any suggestions?
def updatehome(self):
print("UPDATE HOME")
global buy_button, home_status, currency
MoneyLabel = Label(self, text = "Money: ")
MoneyLabel.place(x = 5, y = 70)
Money = Label(self, text=currency)
Money.place(x = 50, y = 70)
if (home_status == 1):
self.after(100, self.updatehome)
elif (home_status == 0):
print("END OF UPDATE HOME")
Money.place_forget()
MoneyLabel.place_forget()
def clearhome(self):
print("CLEAR HOME")
global home_status
home_status = 0
you are creating ten labels every second, all stacked on top of each other, but you are only deleting the very last label you create.

changing buttons within tkinter

win=Tk()
level1=matrixmaker(4)
def display(x,y):
if z["text"] == " ":
# switch to Goodbye
z["text"] = level1[x][y]
else:
# reset to Hi
z["text"] = " "
for x in range(0,4):
for y in range(0,4):
z=Button(win,text=" ", command=display(x,y))
z.grid(row=x,column=y)
I have this code but I don't know how to get the display function to work. How can I call the button and change the text without it having a hardcoded variable name?
You can't assign the command to the button with the called function (display(x, y)) because this assigned what this function returns (None) to the button's command. You need to assign the callable (display) instead.
To do this and pass arguments you'll need to use a lambda:
z = Button(win, text='')
z['command'] = lambda x=x, y=y, z=z: display(x, y, z)
z.grid(row=x, column=y)
Also, you'll want to change your display() function to accept another argument z so that the correct button gets changed (and correct the indentation):
def display(x,y,z):
if z["text"] == " ":
# switch to Goodbye
z["text"] = level1[x][y]
else:
# reset to Hi
z["text"] = " "

Python Cookie Clicker: Auto Click Function?

My Background:
I have done quite a bit of programming with python, I would say I am not bad at it. I am familiar with most of the modules, OOP programming and stuff. You can check my pastebin profile to see what level I am actually in: www.pastebin.com/u/GameNationRDF/
The Code:
from tkinter import *
import time
master = Tk()
def uiPrint():
info()
print ("")
print (click)
blankLine()
def info():
print ("Double click purchases need 750 clicks!")
info()
click = 0
mult = 1
dcp1 = 0
def blankLine():
for i in range(20):
print ("")
def purchaseDoubleClicksCommand():
global click
global mult
if click < 750:
print ("Not enough clicks!")
blankLine()
elif click >= 750:
mult = mult*2
click = click - 750
print ("Double Clicks Purchased!")
blankLine()
def buttonCommand():
global click
global mult
click += 1*(mult)
uiPrint()
if click == 100:
print ('''Achievement Unlocked: Junior Clicker!
BONUS 100!''')
click += 100
elif click == 400:
print ('''Achievement Unlocked: Little Ninja Clicks!
BONUS 200!''')
click += 300
elif click == 900:
print ('''Achievement Unlocked: Legit Ninja!
DOUBLE CLICKS!''')
mult = mult * 2
elif click == 1500:
print ('''Achievement Unlocked: Click Ninja Master!
QUAD CLICKS!''')
mult = mult * 4
elif click == 3000:
print ('''Achievement Unlocked: Jackie Chan Style!
8 TIMES THE CLICKS!''')
mainClickButton = Button(master, text="Click!", command=buttonCommand)
mainClickButton.pack()
purchaseDoubleClickButton = Button(master, text="Purchase Double Clicks", command = purchaseDoubleClicksCommand)
purchaseDoubleClickButton.pack()
master.title("Clicker! v0.0.6")
master.geometry("%sx%s+%s+%s" % (200,70,512,512))
mainloop()
I need a way to be able to add a auto-clicker that would add certain amount of cookies in a given time. I want it to be purchased by a button. I couldnt get it to work though :(
Any help? Thanks :)
The PyUserInput project looks promising and straightforward:
from pymouse import PyMouse
m = PyMouse()
x_dim, y_dim = m.screen_size()
m.click(x_dim/2, y_dim/2, 1)
Why do you import * by the way? It's bad practice to import more dependencies than needed.
Also if I were you I would move the following section of code:
master = ()
info()
click = 0
mult = 1
dcp1 = 0
to reside above this line:
mainlickButton = Button(master, text="Click!", command=buttoncommand)
It's just cleaner to add declarations and functions. It doesn't make a GINORMOUS difference now, but when your file gets bigger and you have a lot of code it will be easier to read.

New line after x pixels when adding to a label (tkinter)

Currently when I write to a label, it will write only one line, and this sometimes disappears off the edge of the label, like so:
Here is an example of the code I am using to write to the label:
def updateLabel(self, event):
global string
global labelContents
global windowCommand
global currentEnvironment
if event != "no input":
windowCommand = self.getEntry(event)
labelDisplay = "> " + windowCommand
labelContents += labelDisplay
labelContents += "\n"
self.checkLabel()
string.set(labelContents)
self.textEntry.delete(0, END)
self.master.after(0, play)
else:
self.checkLabel()
string.set(labelContents)
labelContents += "You have died. Game over." + "\n"
labelContents += "You scored {0}.".format(score) + "\n"
app.updateLabel("no input")
I would like to know if there was any way to force it to a new line after a certain amount of pixels (the label width) without having to go through and add "\n" everywhere (as that last line is 1 of ~150 possibilities).
Label widget has a perfect option for that: wraplengt.
label = Label(parent, text="This is a really long text; " * 5, wraplengt=200)
From the Label's documentation on effbot.org:
Determines when a label’s text should be wrapped into multiple lines. This is given in screen units. Default is 0 (no wrapping).

Categories

Resources