Loosing my mind over this - been through many different articles, forums and questions but still can't figure this out.
I'm a programming noob, and I am currently using IronPython to create a Windows Form application. Visual Studio 2015 is my IDE.
I am wanting to create 100+ label elements on the main form from an array which has been loaded in from a CSV. The array works fine, the code for that is here:
with open('sites.csv', 'rb') as f:
reader = csv.reader(f)
for row in reader:
sites.append(row[0])
The array looks like this:
Sitename 1,Sitename 2,Sitename 3,Sitename 4 etc.
Inside my "MyForm" class which is where I create my child controls before showing the form I have a loop to go through this array and create a label for each sitename entry in the list.
#Create Label for each Site
for s in sites:
sitename = str(s) #Convert Name into a String
elementname = sitename.replace(" ","") + "Label"
elementname = Label()
elementname.Name = str(elementname)
elementname.Parent = self
elementname.Location = Point(lastx,lasty)
counter = counter + counter
lasty = lasty + 10
The variable sitename will convert the current site name entry in the list to a string value with any spaces (e.g. Northern Site).
The variable elementname takes the sitename variable and removes the spaces and adds the word Label to the end of the name.
I then try and create a label object on the form with with the name held in the elementname variable.
Although this doesn't cause an error or exception when I run, the result only outputs one label with the name of first entry in the array/list.
I might be coming this from the wrong angle. I can see why it isn't working by stepping through the code. It creates every single label with the variable elementnamenot the sitenamelabel I was intending it to.
I've attempted to generate variables dynamically using a dictionary but this didn't seem to work, and attempted to create an array of label's on the form and then populate these with the loop but this didn't seem to work.
You will have to actually add every label you have created to the form. A good way to do this is to create a list of labels and add them at the end using the AddRange method.
labels = [] # create a blank list to hold all labels
for s in sites:
sitename = str(s) #Convert Name into a String
elementname = sitename.replace(" ","") + "Label"
elementname = Label()
elementname.Name = str(elementname)
elementname.Parent = self
elementname.Location = Point(lastx,lasty)
labels.append(elementname) # add each element to the list
counter = counter + counter
lasty = lasty + 10
# Add all labels to the form
MyForm.Controls.AddRange(System.Array[Label](labels))
Related
Another one of these puzzles where Im sure I got the right idea but I cant seem to implement it.
Im trying to make a dropdown that instantly opens the URL to whatever column 1 of the list says but I'm not sure if I maybe need a dictionary and call it from that, do I need to define the list by columns...
So I figured out how to open up URLS from a TreeView but now Im figuring out how to open the URL from a Dropdown. I want the {spec} to be populated by only the first item from the list (Pepperoni) in this case.
QUICKJUMP_1 = [
["--", "--"],
["Pepperoni", "Pizza"],
]
def openGoogle():
_spec_ = QUICKJUMP_1
url = f'https://google.com/{_spec_}'
webbrowser.open(url)
quickjump = StringVar()
quickjump.set(QUICKJUMP_1[0])
spec = ttk.Combobox(root, width=30, textvariable=quickjump, state="")
spec['values'] = [item[1] for item in QUICKJUMP_1]
spec.place(x=300, y=400)
spec.current(0)
spec.bind("<<ComboboxSelected>>", openGoogle)
EDIT:
I updated the code as it was figured out how to make it actually open up the URL but as it stands right now all it currently does is just opens up the first part of the list whatever part of the list the "spec = QUICKJUMP" points it to i.e [1] = item 2.
So I need someway to tell it to pick from the drop box and only the first part.
Since the code given is not a working code, I will write down an example and you can hopefully figure it out from it:
from tkinter import *
from tkinter import ttk
import webbrowser
root = Tk()
base_url = 'www.google.com/{}'
options = ['--','Peperoni Pizza']
def open_url(e): # e.widget is the widget that triggers the event, here, combobox
if e.widget.get() != options[0]: # If the value is not '--'
value = e.widget.get()
just_the_flavour = value.split(' ')[0] # This will split the text 'Peperoni Pizza' into two items in a list
# It does this where there is ' ', ie, a blank space, so the list will be ['Peperoni','Pizza']
# Then we take just the first item from it use [0]
url = base_url.format(just_the_flavour)
webbrowser.open(url)
combobox = ttk.Combobox(root,values=options)
combobox.pack()
combobox.current(0) # Set the first value to the first in the list
combobox.bind('<<ComboboxSelected>>',open_url) # Bind to the function
root.mainloop()
I have explained it on the comments to understand it on the go.
I have a function, which based on the count generates the comboboxes. I want to destroy any combobox which is available already whenever my count variable changes. I used winfo_exists to do this...but it throws an attribute error every time. Please help me with this.
Here is the code of that function:
def create(event):
count = combo.current()
print ("count")
print(count)
for i in range(1,count+2):
if (create_combo[i].winfo_exists()):
create_combo[i].destroy()
for i in range (1,count+2):
create = tk.StringVar()
create_combo[i]= ttk.Combobox(new_window_2,width = 15,textvariable = create, values = sheets)
#create_combo.set("Sheet " + str(i))
create_combo[i].grid(column = i, row =4, padx=10,pady=10)
To delete the widgets which are created in loop, can be deleted by using the method available in this link
Python Tkinter :removing widgets that were created using a for loop
This worked for me... I dont understand why winfo_exists didn't work.
Anyway Thanks!!
list_of_owner_widgets = []
def create(event):
count = combo.current()
print(count)
for widget in list_of_owner_widgets:
widget.destroy()
for i in range (1,count+2):
create = tk.StringVar()
create_combo[i]= ttk.Combobox(new_window_2,width = 15,textvariable = create, values = sheets)
list_of_owner_widgets.append(create_combo[i])
create_combo[i].grid(column = i, row =4, padx=10,pady=10)
If you wish to destroy a Python widget, be it a Checkbox in your case, you use the following code.
It is a lot easier to remove and show widgets using the .grid method!
Your code:
create_combo[i].destroy()
I assume (as I can see further down the code file) that you used the grid method. In which case I would simply change the code to:
create_combo[i].grid_forget()
Hope This Helps!
From your post:
for i in range(1,count+2):
if (create_combo[i].winfo_exists()):
create_combo[i].destroy()
And the error:
AttributeError: 'str' object has no attribute 'winfo_exists'
I can infer that:Your create_combo must be a list full of string(Instead of Combobox widget).
You could add print(create_combo) before the first for loop to check the value in create_combo.It must be a list full of string.
And it seems that your problem is not here,you should check the way how you create the create_combo.
lets assume create_combo = ['a','b','c']. So I am creating three comboboxes create_combo[0...2]. So name of the comboboxes(widgets) is a, b, c.
No,you couldn't.
If really want to get a list of comboboxes you create,you should use:
create_combo = []
for i in range(3):
t = ttk.Combobox(xxxxx)
t.grid(xxxxxx)
create_combo.append(t) # append it to your create_combo
And then,you could use:
for i in create_combo:
if i.winfo_exists(): # i should be a widget,not string
xxxxxxx # your job
I'm trying to create variables within these loops but python gives me a syntax error. tme and empty both give me this problem. I'm trying to get python to read an excel sheet and put the values in a list. The variables I'm trying to create are supposed to help me find the empty spaces in python and remove the value from another list I created so that the values I obtain correspond to the correct input and the inputs that have no value in excel are removed from that list. It gives an index error too if there's a fix for that I'd appreciate it, but I can figure that out if the variables work correctly.
span = list()
print(span)
price = list() #creates a list with all the values before giving index error
for q in range(1,chart.nrows):
for i in range (1,chart.ncol):
L = (chart.cell_value(q,i))
if L != '': #all values that exist will be appended to the list
price.append(L)
else: #find x and y parts of space, have that popped from span list
moth = chart.cell_value(q,0)
m = str(moth)
y = year = str(chart.cell_value(0,i)
tme = m + ' ' + y
empty = span.index(tme)
span.pop(empty)
Just from a syntax point of view you were missing a closing bracket in
y = year = str(chart.cell_value(0,i))
Code:
for i in range(len(self.models_chosen)):
self.test.insert(i, vars())
self.model_entry_dict_text["entry" + str(i)] = ttk.Label(
self.entry_frame,
text="Quantity of: " + self.models_chosen[i]
)
self.model_entry_dict_text["entry" + str(i)].pack(fill=X)
self.model_entry_dict["entry" + str(i)] = Spinbox(self.entry_frame, from_=0, to=2000,)
self.model_entry_dict["entry" + str(i)].pack(fill=X)
self.models_entry_box_created = True
self.old_models = self.models_chosen
What I have done is made a dictionary within a for in range called -
self.model_entry_dict["entry" + str(i)]
So it would be:
self.model_entry_dict["entry1"] = Spinbox(self..)
self.model_entry_dict["entry2"] = Spinbox(self..)
self.model_entry_dict["entry3"] = Spinbox(self..)
...
depending on the range.
For each of the spinboxes that I have created, I need the value from inside them (which is why I have put the text variable option as part of the arguments) - The problem is I don't know how to have a different variable for each spinbox created due to the spinboxes being created in a loop.
Say I put self.textvariable, all the spinboxes would have the same value. An example of what I want to have would be
textvariable = self.variable+i
so:
self.variable1 to be the text variable for self.model_entry_dict["entry1"]
self.variable2 to be the text variable for self.model_entry_dict["entry2"]
... etc.
To which I then just do:
self.variable1.get() - And it should get the number that is inside the spinbox
But I don't think it's possible to add a string/integer to a variable name.
Here you can see an image of the models I have chosen in the listbox, I then pressed update button and it generated 3 spinboxes, now I want to retrieve the numbers in the spinboxes (whether it be stored into 3 different variables or in a list/dictionary/array):
http://gyazo.com/a7c9847ec16b16fb443082066b42f890
example of what I'm looking for is (using the image provided above):
test1 = self.variable1.get()
print(test1)
output:
1800
test2 = self.variable2.get()
print(test2)
output:
300
test3 = self.variable3.get()
print(test3)
output:
30
I'm sorry if this may seem a little confusing, I started using Python for a week or so, so it's probably sloppy. I'm sure there's probably better ways of doing this and different methods.
You don't need to give each variable a name. Just use a list:
self.vars = []
for i in range(len(self.models_chosen)):
var = StringVar()
self.vars.append(var)
...
self.model_entry_dict["entry" + str(i)].config(textvariable=var)
I have a method that is suppose to take a search parameter and remove everything from the list that does not meet the parameter. But when it runs it removes list items at almost random. I've debugged it and it correctly determines if an item needs to be removed but it doesn't remove the right one. I think it has something to do with when I remove one item it messes up the indexes of the rest of the list, which doesn't with with my method of tracking the index.
I posted the whole class but the relevant code is towards the bottom
class StudentFinderWindow(Tkinter.Toplevel):
def __init__(self):
Tkinter.Toplevel.__init__(self) # Create Window
##### window attributes
self.title('Edit Students') #sets window title
##### puts stuff into the window
# text
editStudentInfoLabel = Tkinter.Label(self,text='Select the student from the list below or search for one in the search box provided')
editStudentInfoLabel.grid(row=0, column=0)
# entry box
self.searchRepositoryEntry = Tkinter.Entry(self)
self.searchRepositoryEntry.grid(row=1, column=0)
# list box
self.searchResults = Tkinter.Listbox(self)
self.searchResults.grid(row=2, column=0)
# search results initial updater
self.getStudentList()
for student in self.studentList:
self.searchResults.insert(Tkinter.END, student)
##### event handler
self.searchRepositoryEntry.bind('<KeyRelease>', self.updateSearch)
This is the relevant code
def updateSearch(self, event):
parameters = self.searchRepositoryEntry.get()
int = 0
currentList = self.searchResults.get(0, Tkinter.END)
length = len(parameters)
print(parameters)
print(length)
for i in currentList:
if not i[0:length] == parameters:
self.searchResults.delete(int)
print(i[0:length] == parameters)
print(i[0:length])
print(int)
int += 1
def getStudentList(self):
global fileDirectory # gets the directory that all the files are in
fileList = listdir(fileDirectory) # makes a list of files from the directory
self.studentList = [] # makes a new list
for file in fileList: # for loop that adds each item from the file list to the student list
self.studentList.append(file[:-4])
When you delete an item, everything below it moves up causing the index of all following items to change. The simplest solution to this sort of a problem (it's also common when deleting words from a text widget) is to delete backwards, starting at the end.
I think you already know the problem. When you delete an item, the index for the rest of the items change. For example, if you delete the 4th item, then the 5th item becomes the "new" 4th item. So you don't want to increment int whenever you delete an item. You can implement that with continue:
for i in currentList:
if not i[0:length] == parameters:
self.searchResults.delete(int)
continue # <-- Use continue so `int` does not increment.
int += 1
PS. It's not good coding style to use int as a variable name -- in Python it masks the built-in function of the same name.