Generic value editor GUI for dictionaries in PyQt - python

Say I have a dictionary full of parameters:
{speed = 1, intelligence = 3, dexterity = 2}
I want to call a loop that creates a Label and a SpinBox for each item in this list procedurally, in case I want to add more attributes later. I can create the window and return the updated values just fine. My only issue is that I want all the widgets to be created as necessary, whether I have 7 or 20 attributes to edit.
So the label object could be called speed_Label and the intelligence label object intelligence_Label, and the spinbox containing the value of speed would be speed_SpinBox and so on, which then I could pass back easily. However, this
a) seems like poor naming practice
b) seems difficult seeing as I can't find out how to give objects names procedurally, say
for KEY in dict.keys(): # say the KEY is "Speed"
# this would produce a Label object called Speed_Label
# which displays the text "Speed"
"KEY" + "_Label" = QLabel("KEY")

Why not simply use a list or dict?
Something like this should work:
widgets = {}
form = QFormLayout()
for key, value in your_dict.iteritems():
widgets[key] = widget = {}
widget['spinbox'] = spinbox = QSpinBox()
spinbox.setValue(value)
form.addRow(key, spinbox)

Related

how to assign the variable for python tkinter entry?

I am trying to create a simple 'SOS' puzzle game from Tkinter. I am creating an entry widgets grid using the grid method. Now I want an assigned variables for each entry. I try to do it using for loops but I can't use that variable the proper way. Can you help me? My question idea explain given below digram,
Code
for i in range(5):
for j in range(5):
self.entry=Entry(root,textvariable=f'{i}{j}')
self.entry.grid(row=i,column=j)
self.position.update({f"{i}-{j}":f"{i}{j}"})
enter code here
Instead of creating variables on the go, you should store the widgets made into a list or a dictionary. The list seems more reasonable as you can index it more easily.
Below is a simple, but full example that shows how you can make a 2-D list as well as search this list for the entry object:
from tkinter import * # You might want to use import tkinter as tk
root = Tk()
def searcher():
row = int(search.get().split(',')[0]) # Parse the row out of the input given
col = int(search.get().split(',')[1]) # Similarly, parse the column
obj = lst[row][col] # Index the list with the given values
print(obj.get()) # Use the get() to access its value.
lst = []
for i in range(5):
tmp = [] # Sub list for the main list
for j in range(5):
ent = Entry(root)
ent.grid(row=i,column=j)
tmp.append(ent)
lst.append(tmp)
search = Entry(root)
search.grid(row=99,column=0,pady=10) # Place this at the end
Button(root,text='Search',command=searcher).grid(row=100,column=0)
root.mainloop()
You have to enter some row and column like 0,0 which refers to 1st row, 1st column and press the button. Make sure there are no spaces in the entry. You should not worry much about the searching part, as you might require some other logic. But instead of making variables on the go, you should use this approach and store it in a container.
Also a note, you do not have to use textvariable as here the need of those are totally none. You can do whatever you want with the original object of Entry itself. Just make sure you have the list indexing start from 0 rather than 1(or subtract 1 from the given normal values).

Importing dictionary values into an OptionMenu in Python

I'm stuck right now and could really use some help, i've exhausted every resource google could find for me and I still can't figure out how to do what I am attempting. (If its even possible)
In my python program I am using Tkinter in Python 3.5.1 to make a little calculator applet. For the calculator in question I created a CSV file and imported it using csv.DictReader.
import csv
exptable = csv.DictReader(open('C:/Users/SampleInfo.csv'))
result = {}
for column in exptable:
key = column.pop('Current Level')
if key in result:
pass
result[key] = column
Now the part that I simply can't figure out is how to use the information contained WITHIN this imported dictionary. Here is what I am trying so far...
DropDownLevelVar = StringVar()
DropDownLevel = ttk.OptionMenu(root, {column})
DropDownLevel.grid(column=3, row=1)
This is leaving me with...
Error on line 49, in module DropDownLevel = ttk.OptionMenu(root, {column})
TypeError: unhashable type: 'dict'
The CSV Dictionary I am trying to use contains 2 columns of data, "Current Level and Total EXP" See This for what the Data looks like.
What I would like is for the OptionMenu Dropdown list to be populated with the values listed under Current Level within the dictionary.
My goal is to create a super simple calculator that calculates how many of a certain monster I would need to kill to reach my desired level. (If Current level = 55, then 100 Kills at 500xp ea until 56.) I imported the dictionary so that I could reference the values over and over if I needed to.
I'm REALLY new to programming so i'm sorry if I look like a complete idiot!
Why not use this method to populate your dict?
Anyway, to correctly populate the result dict:
import csv
exptable = csv.DictReader(open('C:/Users/SampleInfo.csv'))
result = {}
for column in exptable: # should actually be called `row`
key = column['Current Level']
if key not in result:
result[key] = column['Total EXP']
The for and if block can be better written as:
for column in exptable: # should actually be called `row`
if column['Current Level'] not in result:
result[column['Current Level']] = column['Total EXP']
If ttk.OptionMenu wants a dict, then the line DropDownLevel = ttk.OptionMenu(root, {column}) should probably be:
DropDownLevel = ttk.OptionMenu(root, result)
Edit: And the pythonic way to do this, as per the method linked above:
import csv
result = {}
with open('C:/Users/SampleInfo.csv') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
if row['Current Level'] not in result: # is this check necessary?
result[row['Current Level']] = row['Total EXP']

Construction of 5 level tree structure in python

i want to reduce the number of times i hit the data base to retrieve data. So i think taking entire data into a tree will increase the performance of the system as i will not be hitting the database frequently.
I am a beginner in python, so please do help and advice me in creating the tree structure.
You can use nested dictionaries. Nested means that the value of a key:value pair can be another dictionary.
JerseyMike has given a nice example, I just want to point out that his addItemAttributes function is equivalent to the more concise
def addItemAttributes(tree, idList):
(menu, cat, subcat, item, attribs) = idList;
currDict = tree.setdefault(menu, {})\
.setdefault(cat, {})\
.setdefault(subcat, {})\
.setdefault(item, {})
for a in attribs:
currDict[a[0]] = a[1]
...and that you might like to wrap getItemAttributes in a try block so you can deal with the case that one of the keys is missing, eg.
try:
getItemAttributes(...)
except KeyError:
#key was incorrect, deal with the situation
I'm putting this together on the fly since I don't have my Python interpreter handy. Here are two functions for populating and reading from the nested dictionary structures. The first parameter passed to each is the base dictionary that will hold all of your menu information.
This function is used to add to the dictionaries. This function can be probably be more efficient, code-wise, but I wanted you to understand what was going on. For each item of each subcategory of each category of menu, you will need to construct a list of the attributes to pass in.
# idList is a tuple consisting of the following elements:
# menu: string - menu name
# cat: string - category name
# subcat: string - subcategory name
# item: string - item name
# attribs: list - a list of the attributes tied to this item in the form of
# [('Price', '7.95'),('ContainsPeanuts', 'Yes'),('Vegan', 'No'),...].
# You can do the attribs another way, this was convenient for
# the example.
def addItemAttributes(tree, idList):
(menu, cat, subcat, item, attribs) = idList;
if not tree.has_key(menu): # if the menu does not exist...
tree[menu] = {} # Create a new dictionary for this menu
currDict = tree[menu] # currDict now holds the menu dictionary
if not currDict.has_key(cat): # if the category does not exist...
currDict[cat] = {} # Create a new dictionary for this category
currDict = currDict[cat] # currDict now holds the category dictionary
if not currDict.has_key(subcat): # if the subcategory does not exist...
currDict[subcat] = {} # Create a new dictionary for this subcategory
currDict = currDict[subcat] # currDict now holds the subcategory dictionary
if not currDict.has_key(item): # if the category does not exist...
currDict[item] = {} # Create a new dictionary for this category
currDict = currDict[item] # currDict now holds the category dictionary
for a in attribs
currDict[a(0)] = a(1)
The function to read from the nested structure is easier to follow:
# Understand that if any of the vaules passed to the following function
# have not been loaded, you will get an error. This is the quick and
# dirty way. Thank you to Janne for jarring my mind to the try/except.
def getItemAttributes(tree, menu, cat, subcat, item):
try:
return tree[menu][cat][subcat][item].items()
except KeyError:
# take care of missing keys
I hope this helps. :)

How to clear items from a ttk.Treeview widget?

ing_scroll = Scrollbar(window1_frame1, orient=VERTICAL)
ingredients = ttk.Treeview(window1_frame1, yscrollcommand=ing_scroll.set, height=5, columns=['Ingredient', 'Amount'], show="headings")
ingredients.heading("Ingredient", text='Ingredient')
ingredients.column("Ingredient", width=7)
ingredients.heading("Amount", text='Amount')
ingredients.column("Amount", width=1)
ing_scroll.config(command=ingredients.yview)
ing_scroll.pack(side=RIGHT, fill=Y)
ingredients.pack(side=LEFT, fill='both', expand=1)
def OnRecpSelect(event):
DB = menu_combo.get()
mytable = recipe_combo.get()
ingredient_list = TKengine.pull_ingredients(DB, mytable)
# NEED TO CLEAR THE INGREDIENTS TTK:TREEVIEW OBJECT HERE!
for i in ingredient_list:
ingre = i[1]
amoun = i[2]
value = ingre,amoun
ingredients.insert('',0,values=value)
ingredient_list is a list that displays something like... ('Sugar', '1 Cup') and so on... The def is for a combobox that is selected, so what I would like is for the treeview to clear and not just keep adding more ingredients. Unfortunately I don't see a clear() method.
If theres a programmatic way of identifying what is there first (enumerating a rowcount would be good...) this is driving me nuts. I did notice in the docs that you can use the delete method, but it wants to know what the item is to delete... if I use:
ingredients.delete('',0)
I get
TclError: Item 0 not found
So I would assume it wants something like 'Sugar' as the Item...
of course its a catch 22 because if you select the combobox and want to clear the ingredients treeview, the same ingredient items are not in every recipe, so how do we know what items to delete?...
Please let me know if you need any more details... I am fairly new to working with the treeview object, but its making me want to just work with two listboxes on a canvas.
To just make the code a bit more concise and Pythonic:
map(ingredients.delete, ingredients.get_children())
When you insert an item on the tree, the insert method returns an item id. This is what you give to the delete method.
Also, given an item id (such as the root item), you can get a list of all of its children with the get_children method. If you do not give any arguments to the get_children it will return a list of all the items that belong to the root element. You can then iterate over this list to delete the items.
This is all documented in the treeview docs at docs.python.org.

How to get value from selected item in treeview in PyGTK?

I'm learning PyGtk. I have a simple treeview with 1 column, I get items for that treeview from list.
How to get value of selected item in treeview?
You may use the gtk.TreeView.get_selection() method to get the gtk.TreeSelection.
Next, you should use the gtk.TreeSelection.get_selected_rows() method to get the TreeModel (the ListStore) and the selected items
paths.
Then, you can use the gtk.TreeModel.get_iter() in order to get the iter from the path (returned by the gtk.TreeSelection.get_selected_rows() method).
Finally, you may use the gtk.TreeModel.get_value() method to get the value corresponding to the column and the iter previously recovered.
Example :
def onSelectionChanged(tree_selection) :
(model, pathlist) = tree_selection.get_selected_rows()
for path in pathlist :
tree_iter = model.get_iter(path)
value = model.get_value(tree_iter,0)
print value
listStore = gtk.ListStore(int)
treeview = gtk.TreeView()
treeview.set_model(listStore)
tree_selection = treeview.get_selection()
tree_selection.set_mode(gtk.SELECTION_MULTIPLE)
tree_selection.connect("changed", onSelectionChanged)

Categories