storing instances in variables in python - python

In my Pyqt4 program I want to change the shortcut for some buttons. As I have quite a lot I thought of accessing a button through user input. I copied the relevant code snippets.
self.btn3 = QtGui.QPushButton(self)
b, ok = QtGui.QInputDialog.getText(self, 'Keyboard Mapping',
"Enter button number: ")
so the user would, say, input "btn3", and then in another input dialog he'd specify the new shortcut. Finally, I want to change the button shortcut like this:
self.b.setShortcut(newkey)
I get an error that my QMainWindow Class has no attribute "b".
Is there no way of storing an instance in a variable? Or maybe reading the variable or something? I'd be glad if you can help me...

The issue here is that python doesn't take the value from b for the lookup when you do self.b.setShortcut(newkey), rather, it just looks for the name b.
You can do what you want using getattr():
getattr(self, b).setShortcut(newkey)
However, this is bad style and will generally be unsafe and cause problems. Instead, make a data structure that suits your need - here it would make sense to create a dictionary, for example:
self.widgets = {"btn3": QtGui.QPushButton(self)}
...
self.widgets[b].setShortcut(newkey)

Related

Issue with getting value of checkboxes tkinter

I'm trying to get the value of checkboxes in tkinter so I can have the data from those checkboxes exported into a excel spreadsheet
I've tried having the checkboxes generate iteratively (as they are presently) and making them manually, but no matter what I do, can't get them to give me their values (whether they are checked or not) and it's really stressing me out.
def check():
for movie in movies():
print(button.get())
Button(moviewindow,text="Check",command=check).pack(anchor=S)
for movie in movies():
var1 = IntVar()
button = Checkbutton(moviewindow,
bg=moviewindow_bg,
font=("Times",23),
onvalue=1,
offvalue=0,
text=movie.replace("<strong>","").replace("</strong>",""),
variable=var1).pack(anchor=W)
I expect the code to print either 1 or 0, but I cant get the checkboxes to return their values.
You need to store your variables (and possibly, buttons) somewhere. What's happening currently is this:
You create a Button that runs the function check. Inside check, you iterate over movies, and try to get the value from button. You should be getting the value from var1, but that's not the chief issue here. The main problem is that var1 only contains the very last IntVar created, so the loop will only repeat the value of the last checkbox you created.
Without knowing what kind of an object movie is, it's hard to say the best way to proceed here. If movie is a class object, you could perhaps change its properties. If it's a hashable object, here's what you can do.
Somewhere above your code: Create a dict for association between movies and vars
checkbox_vars = {}
Fix check to use this dict
def check():
for movie in movies():
print(checkbox_vars[movie].get())
Within your loop, store the variable in the dict
var1 = IntVar()
# Store the variable in checkbox_vars, for this specific movie
checkbox_vars[movie] = var1
This is still a somewhat inelegant way to do it, but it should illustrate how you need to actually create an association between button/var1 and movie yourself instead of it being implicit.
Use var1.get() to get the current value of the checkbox.
To print the value as soon as the check button is updated, use it inside the button's invoke method.

Kivy dynamic widget issue

Well, i'm a beginner using kivy framework, so i thought that someone here could help me.
My question is:
On my app, the user input a number n, then the app return n TextInput widgets. But how can i use the values inserted on each TextInput? The first part is easy to do, i did it by a list. (If someone know how to do it directly on kv file i would appreciate it). My issue is on second part, i need to use and manipulate these values (in TextInputs) later but i can't reach to them. I mean, i set up for each widget in the list an id, but i can't reach to .text attribute of them. Here is a piece of my code:
class FirstLayout(BoxLayout):
def next_layout(self):
self.clear_widgets()
secondLayout = Factory.SecondLayout()
number = NumericProperty()
# This 'number' variable came from another widget on kv file
textinput_list = []
# That list will receive as many TextInputs field as my variable 'number' said (by the loop for)
for i in range(int(self.number.text)):
textinput_list.append(TextInput())
textinput_list[i].id = "input" + str(i + 1)
# So for each textinput, i added a id named 'inputx' (where x is the number of the current
# iteration) my question resides here. How could i use those values (inside of each textinput
# on this list
# later? Because i'm not creating these widgets (TextInputs) on kv language so i don't know how to
# bind the ids for a new variable directly in .py file
secondLayout.container.add_widget(textinput_list[i])
self.add_widget(secondLayout)
If I understand your question right, you just have to make textinput_list a class variable. So this.
textinput_list = []
becomes
self.textinput_list = []
Lets say you have an object of FirstLayout called first. With first.textinput_list[0] you can access the first textinput and so on.
If you want to easily access the textinputs via id I would suggest using a dictionary, with the keys being the id's and the values being the inputs.

Python: Configuring Tkinter widget with argument to configure as a string

I'm using Python and Tkinter and was wondering whether there is anyway I could do something like this because currently it gives me an error. I would like to be able to configure a widget with user input as a string to decide what to configure, hence why the variable 'string_variable' needs to be a string.
tk_widget.config(string_variable = variable)
At the moment, I get an error saying "TclError: unknown option -'string_of_stringvar_here'" Please help me! Thank you for your replies in advance.
- Ed
You can treat a widget like a dictionary, with attributes being keys. For example:
label = tk.Label(root)
...
some_attribute = "background"
some_value = "red"
label[some_attribute] = some_value
You can also build up a dictionary of attributes and values, and pass that to the config method:
values = {some_attribute: some_value}
label.config(values)

dynamically asigning instances in Python/PyQt4

Ok, this might be a duplicate, but as I couldn't really get anything out of (possibly) similar questions, here is mine: I'm working on a small PyQt4 program where I can enter the name of a song in a QLineEdit and then add a QLabel of it beneath it. I want a button beside each one of these labels that deletes the label when clicked. Relevant code:
def Add(self):
self.rf= QtGui.QLabel(self.le1.text(),self)
self.rf.move(45,30)
self.rf.resize(450,30)
self.rf.show()
self.x = QtGui.QPushButton("X",self)
self.x.move(10,30)
self.x.resize(30,30)
self.x.show()
self.x.clicked.connect(self.Del)
def Del(self):
self.rf.close()
self.x.close()
Now, what I'm not understanding is how I can assign a different instance to each of these dynamically added Qlabels, in order to delete the specific one when the button is clicked.
The best idea I had was creating a variable containing a number that would change with each added QLabel, something like var = rf+str(num) and num = 0, then adding 1 to num for each QLabel and then using getattr for the instances, so getattr(self, var) = Qtgui.QLabel(...), which unfortunately gives me an error that I can't assign that value to the function. And I can't create a dictionary since I have to have different instances for that.
Any ideas would be highly appreciated, thanks a lot.
You could keep them all in a dict and then key that off of the label text. It also provides a quick way to check for duplicates.

python load from shelve - can I retain the variable name?

I'm teaching myself how to write a basic game in python (text based - not using pygame). (Note: I haven't actually gotten to the "game" part per-se, because I wanted to make sure I have the basic core structure figured out first.)
I'm at the point where I'm trying to figure out how I might implement a save/load scenario so a game session could persist beyond a signle running of the program. I did a bit of searching and everything seems to point to pickling or shelving as the best solutions.
My test scenario is for saving and loading a single instance of a class. Specifically, I have a class called Characters(), and (for testing's sake) a sigle instance of that class assigned to a variable called pc. Instances of the Character class have an attribute called name which is originally set to "DEFAULT", but will be updated based on user input at the initial setup of a new game. For ex:
class Characters(object):
def __init__(self):
self.name = "DEFAULT"
pc = Characters()
pc.name = "Bob"
I also have (or will have) a large number of functions that refer to various instances using the variables they are asigned to. For example, a made up one as a simplified example might be:
def print_name(character):
print character.name
def run():
print_name(pc)
run()
I plan to have a save function that will pack up the pc instance (among other info) with their current info (ex: with the updated name). I also will have a load function that would allow a user to play a saved game instead of starting a new one. From what I read, the load could work something like this:
*assuming info was saved to a file called "save1"
*assuming the pc instance was shelved with "pc" as the key
import shelve
mysave = shelve.open("save1")
pc = mysave["pc"]
My question is, is there a way for the shelve load to "remember" the variable name assotiated with the instance, and automatically do that << pc = mysave["pc"] >> step? Or a way for me to store that variable name as a string (ex as the key) and somehow use that string to create the variable with the correct name (pc)?
I will need to "save" a LOT of instances, and can automate that process with a loop, but I don't know how to automate the unloading to specific variable names. Do I really have to re-asign each one individually and explicitly? I need to asign the instances back to the apropriate variable names bc I have a bunch of core functions that refer to specific instances using variable names (like the example I gave above).
Ideas? Is this possible, or is there an entirely different solution that I'm not seeing?
Thanks!
~ribs
Sure, it's possible to do something like that. Since a shelf itself is like a dictionary, just save all the character instances in a real dictionary instance inside it using their variable's name as the key. For example:
class Character(object):
def __init__(self, name="DEFAULT"):
self.name = name
pc = Character("Bob")
def print_name(character):
print character.name
def run():
print_name(pc)
run()
import shelve
mysave = shelve.open("save1")
# save all Character instances without the default name
mysave["all characters"] = {varname:value for varname,value in
globals().iteritems() if
isinstance(value, Character) and
value.name != "DEFAULT"}
mysave.close()
del pc
mysave = shelve.open("save1")
globals().update(mysave["all characters"])
mysave.close()
run()

Categories