For loop assign a variable name for each loop iteration - python

This is a part of a code I've been working on, during the for loop it iterates through product_buttons in order to define which button is selected, and after a button is selected I wanted to show which button was selected and I have managed to do it as follows:
product_buttons = [36,38,40] #raspberry pi pins
in_progress = False
ended = True
product = None
def show_msg(wid,msg):
wid.config(text = msg)
pass
def button_loop():
global in_progress,ended
waiting = False
product = None
while True:
for i in range(len(product_buttons)):
button = IO.input(product_buttons[i])
if button:
print(i,in_progress,ended,product)
if not in_progress:
product = i
while not ended:
time.sleep(0.1)
in_progress = True
show_msg(root.lab_quality,'Button {}
pressed'.format(i))
The code works fine and whenever a button is pressed it changes Button {} pressed with Button 0 pressed, Button 1 pressed or Button 2 pressed.
Now what I was trying to do was to assign a variable name to each iteration in the for loop in order to achieve something like:
i = 0 make i = to a variable for example let's call it a
i = 1 make i = to b
i = 2 make i = to c
So that (still for example) when button 0 is pressed it shows Button a is pressed.
I have tried to store the values like this quality={1:a, 2:b, 3:c} and then call it with show_msg(root.lab_quality,'Button {} pressed'.format(quality)), this was the idea I had in mind but didn't work out and I am a bit stuck and I need to be pointed in the right direction so that I can eventually work it out.
Any help will be greatly appreciated!

You need to define quality as a dictionary like this: quality={'1':'a', '2':'b', '3':'c'}. Then, you can call show_msg function:
show_msg(root.lab_quality,'Button {} pressed'.format(quality[str(i)]))
This way you use the value of i variable as the key to read its name from the quality dictionary.

Thanks guys I have worked it out I did:
btn = ['a','b','c']
show_msg(root.lab_quality,'QUALITY {}'.format(btn[j]))
and works like a charm, was so easy I don't know why I didn't see it before.

Related

Pass dynamically created button information to a function when they are pressed. kivymd, kivy, python

I am trying to delete information about the button when the user presses the trash can on the button.
My problem is that when the user presses the trash can of any button, only the information of the button that is lastly created gets passed to the function, and therefore only the last created button get deleted instead of the one of the button that is pressed.
Please see the picture below.
picture
docs = users_ref.collection(u'Education').stream()
education_lst = []
education_btn = []
for doc in docs:
dict = doc.to_dict()
education_lst.append(dict['Graduation'])
primary = str(dict['University'])
secondary = str(dict['Degree']) + ' in ' + str(dict['Major'])
tertiary = 'Graduation year: ' + dict['Graduation']
btn = ThreeLineAvatarIconListItem(text=primary, secondary_text=secondary, tertiary_text=tertiary)
education_btn.append(btn)
for btn in education_btn:
pic = IconRightWidget(icon='trash-can')
pic.bind(on_release=lambda *args: Education().delete(education_lst[education_btn.index(btn)]))
btn.add_widget(pic)
sm.get_screen('profile').ids.profile_grid.add_widget(btn)
That's a common problem when defining a lambda function in a loop. The loop variable used in the lambda function isn't evaluated until the lambda is actually executed. So, in your case, the btn argument ends up being the last value of btn. A fix is to use a new variable to hold the value of the loop variable, like this:
pic.bind(on_release=lambda *args, x=btn: self.delete(education_lst[education_btn.index(x)]))

Button error, but I get IndexError: list index out of range

I have two buttons on my interface. I want both of them to be able to call their respective functions when I either click on them or a hit the Enter Key.
The problem I'm having is that only the last button in the traveral focus gets activated when I hit the Enter Key, even if the preceeding one has the focus. What can I do to resolve this problem.
Useful answer are welcome and appreciated.
This is the problem in question:
from tkinter import *
w = Tk()
def startProgram(event = None):
print('Program Starting')
def readyContent(event = None):
print('Content being prepared')
# Buttons
Button(text='Prepare', command=readyContent).grid(row=10,column=2)
w.bind('<Return>',readyContent) # Binds the Return key to a Function
Button(text='Start', command=startProgram).grid(row=10,column=3)
w.bind('<Return>',startProgram) # Binds the Return key to a Function
w.mainloop()
When you click on the Prepare or Start button, in return you get either Content being prepared or Program Starting repectively. Nothing like that happens when you use the Tab Key to give focus to one button or the other. Even if the focus is on the Prepare button, when you hit Enter you get: Program Starting
This is the solution to my problem.
I hope it helps anyone else having the same problem as me.
from tkinter import *
w = Tk()
def startProgram(event = None):
print('Program Starting')
def readyContent(event = None):
print('Content being prepared')
# Buttons
btn1 = Button(text='Prepare', command=readyContent)
btn1.grid(row=10,column=2)
btn1.bind('<Return>',readyContent) # Binds the Return key to a Function
btn2 = Button(text='Start', command=startProgram)
btn2.grid(row=10,column=3)
btn2.bind('<Return>',startProgram) # Binds the Return key to a Function
w.mainloop()
Have a good day! :)

Blocking button click signals in PyQt

I have a program that uses pyqt's .animateClick() feature to show the user a sequence of different button clicks that the user has to copy in that specific order. The problem is I don't want the animateClick() to send a signal, I only want the button click signals from the user. Here is some of my code to demonstrate what I mean, and how I tried to solve that problem (that doesn't work). I simplified my code quite a bit so its easier to read, let me know if you have any questions.
from PyQt4 import QtCore,QtGui
global flag
global ai_states
ai_states = []
user_states = []
class Program(object):
# Set up the push buttons
#Code Here.
# Connect push buttons to function get_state()
self.pushButton.clicked.connect(self.get_state)
self.pushButton_2.clicked.connect(self.get_state)
self.pushButton_3.clicked.connect(self.get_state)
self.pushButton_4.clicked.connect(self.get_state)
# Code that starts the start() function
def start(self):
flag = 0
ai_states[:] = []
i = -1
# Code here that generates ai_states, numbers 1-4, in any order, based on button numbers.
for k in ai_states:
i = i + 1
# Code here that animates button clicks determined by ai_states
# Changes the flag to 1 once the loop ends
if i == len(ai_states):
flag = 1
def get_state(self):
if flag == 1:
user_states.append(str(self.centralWidget.sender().text()))
else:
pass
if len(user_states) == len(ai_states):
# Checks to make sure the user inputted the same clicks as the ai_states
Even though the flag does come out to be 1 after the start() function, it is still appending the animatedClick() signals. What am I doing wrong? I'm new to GUI programming, so I'm probably going about this in a very bad way. Any help would be appreciated.
Never use global variables unless you really have to. If you need shared access to variables, use instance attributes:
from PyQt4 import QtCore,QtGui
class Program(object):
def __init__(self):
self.ai_states = []
self.user_states = []
self.flag = 1
# Set up the push buttons
# Code Here
# Connect push buttons to function get_state()
self.pushButton.clicked.connect(self.get_state)
self.pushButton_2.clicked.connect(self.get_state)
self.pushButton_3.clicked.connect(self.get_state)
self.pushButton_4.clicked.connect(self.get_state)
# Code that starts the start() function
def start(self):
self.flag = 0
del self.ai_states[:]
i = -1
# Code here that generates ai_states, numbers 1-4, in any order, based on button numbers.
for k in self.ai_states:
i = i + 1
# Code here that animates button clicks determined by ai_states
# Changes the flag to 1 once the loop ends
self.flag = 1
def get_state(self):
if self.flag == 1:
self.user_states.append(str(self.centralWidget.sender().text()))
if len(self.user_states) == len(self.ai_states):
# Checks to make sure the user inputted the same clicks as the ai_states

How to make Tkinter checkbuttons work individually and default as checked

I am trying to have a series of checkboxes which can be selected or not selected - then when the user presses the button, the letters allocated to the checkboxes should be added to an inputted string and then printed.
I am having 2 major problems;
The when the user presses a checkbox, all of the checkboxes are selected.
I would like to have the default being that all of them as checked, but I cannot find how to do this. If this cannot be answered, it is less important than the 1st problem, and hence doesn't matter as much.
This is my code so far;
import Tkinter
class MENU():
def __init__(self,NewData):
self.SCREEN = Tkinter.Tk()
self.NewData = NewData
self.Selection = {"A":1,"B":1,"C":1,"D":1}
self.A = Tkinter.Checkbutton(self.SCREEN,text="A",variable=self.Selection["A"]).pack()
self.B = Tkinter.Checkbutton(self.SCREEN,text="B",variable=self.Selection["B"]).pack()
self.C = Tkinter.Checkbutton(self.SCREEN,text="C",variable=self.Selection["C"]).pack()
self.D = Tkinter.Checkbutton(self.SCREEN,text="D",variable=self.Selection["D"]).pack()
self.BtnFinish = Tkinter.Button(self.SCREEN,text="Finish selection",command=self.FinishSelection)
self.BtnFinish.pack()
self.SCREEN.mainloop()
def FinishSelection(self):
SelectionString = ""
for n in self.Selection:
if self.Selection[n]:
SelectionString+=n
self.NewData+="\nQuestions\n"+SelectionString+"\n"
print self.NewData
MENU("")
If it matters at all, this is for Python 2.7.3. Additionally, my thanks, and also apologies to those of you who likely have to point out something incredibly obvious/basic, which, as a beginner for Tkinter, I have not realised.
You must use one of the Tkinter objects StrintVar, IntVar, BooleanVar or DoubleVar normally (StringVar) as the value of the variable argument. You can't use a normal python variable. You'll have to create an individual variable for each.
For example:
self.Selection = {"A": Tkinter.BoolVar(), "B": Tkinter.BoolVar(), ...}
self.Selection["A"].set(True)
...
Then, to get the value you'll need to use the get method:
value = self.Selection["A"].get()

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