I'm creating a tkinter GUI and I have two list boxes that are supposed to have the same single line of text inserted into them upon initialization. The listboxes have separate names, but each time I run .insert for either of the listboxes, both of them get the line added to them and I can't figure out why. The same thing happens when they get their unique data. Here is example code copied from my program:
names = ["+ Add New Condition"]
bcList_lsb = tk.Listbox(bc_frm,listvariable=names)
bcList_lsb.grid(row = 1, column =1)
bcList_lsb.bind('<<ListboxSelect>>',command = bcLbClick)
bcList_lsb.insert("end",names[0])
solNames = ["+ Add New Condition"]
solBcList_lsb = tk.Listbox(solBc_frm,listvariable = solNames)
solBcList_lsb.grid(row = 1, column =1)
solBcList_lsb.bind('<<ListboxSelect>>',command = solBcLbClick)
solBcList_lsb.insert("end",solNames[0])
The setup for the two frames is identical except for their names and their commands.
Here is what it looks like in the GUI upon initialization:
Any suggestions would be appreciated.
You have in effect given both listboxes the same listvariable which forces them to be in sync. When you specify the listvariable option, the string representation of what you give it becomes an internal variable name. Both widgets end up with a variable named "['+ Add New Condition']" (eg: str(["+ Add New Condition"])) which means they are the same variable internally.
Related
What I`m using: Tkinter lib, setattr() function
What I want: by using a for loop create some number of widgets with some parameters and roughly similar names. Then, I want to be able to set their location using the same loop
How it looks for me for now:
class Window(Tk):
def __init__(self):
Tk.__init__(self)
for i in range(n):
setattr(Label(self, text=f"name{i}", OTHER_OPTIONS), f"name{i}", _value)
name{i}.place(y=0+10*i)
What I expect to see: a column of text from name0 to nameN with 10 units between each
For what I need it?: to create a function in which I can send parameters like name of object, text, background and other of label options
Thanks in advance for the answer!
You're making this more difficult than it needs to be. Just store the labels in a list or dictionary.
self.labels = []
for i in range(n):
label = Label(self, ...)
self.labels.append(label)
I also strongly recommend against place. It's much easier to create responsive applications using pack and grid. With place you have to a lot more work, and it's easy to create a UI that looks good only looks good for one specific configuration (resolution, default font, window size).
I have a bunch of screens in my app that all have the same icon that I always want to change together. So I currently have it hard coded and everytime I add a new screen I have to add a new line and it's getting cumbersome:
self.tcs_screen.ids.statusicon.source = "/imgs/..."
self.eclss_screen.ids.statusicon.source = "/imgs/..."
self.gnc_screen.ids.statusicon.source = "/imgs/..."
...
Is it possible to do this from a loop over a list of the screens? I've been trying the following with no success (how do you insert a variable into a property assignment?):
ScreenList = ['tcs_screen', 'eclss_screen', 'gnc_screen']
for x in xrange(len(ScreenList)):
self.ScreenList[x].ids.statusicon.source = "/imgs/..."
Or is there a better way to accomplish this?
Thanks
You have to use getattr() to get the property using the name.
screen_list = ['tcs_screen', 'eclss_screen', 'gnc_screen']
for e in screen_list:
getattr(self, e).ids.statusicon.source = "/imgs/..."
I am trying to build an interface as part of a console application that reads an output file and displays part of its contents in a window (split vertically) as a scrollable list. The user should be able to choose items from this list, which when selected show up in the adjacent window. Switching to this adjacent window and selecting items should then remove them. When the user hits 'Q' or some other appropriate keypress, the interface should exit and the choices are then available to the main program for further processing.
I am trying to build this using urwid. I can get the results to show up in a ListBox widget, but when I try to wrap this and a separate instance of a ListBox widget in a Columns widget, the program throws an error on calling the mainloop. Basically, something like this:
listbox1 = urwid.ListBox(urwid.SimpleListWalker[<lines>])
listbox2 = urwid.ListBox(urwid.SimpleListWalker[])
urwid.MainLoop(urwid.Columns([listbox1, listbox2])).run()
I then get:
AttributeError: 'listbox1' object has no attribute 'rows'
I guess because it is a 'flow' style widget it has no specified number of rows, and since the Columns object would be the top level widget, calls to render fail due to not being able to determine the overall size of the screen? If so, what is the best way to work around this?
EDIT: Can simply wrap the columns object in Frame without calling header or footer and get desired output.
I am trying to create new checkboxes from a list of checkboxes but in a new frame. The newly created checkboxes however act like radiobuttons when created at the same time. Here is the code (only for the function creating the boxes)
def printcheckbuttons():
val=StringVar()#checkboxlist is a list of checkbox widgets
for x in range (len(checkboxlist)):
for ki in checkboxlist:
if ki.var.get() != 'null':
sale=Checkbutton(frameright,text=ki.var.get()[0:],variable=val,onvalue=ki.var.get(),offvalue='null')
sale.val=val
saletracker.append(sale)#saletracker is a list to track selected checkboxes in checkboxlist ant post them to a second frame
sale.pack(anchor=NW)
checkboxlist.remove(ki)
ki.destroy()
print 'checkboxlist 1',checkboxlist
destroyboxes(checkboxlist)#destroys and removes all checkboxes in checkbuttonlist
print 'checkboxlist',checkboxlist
print "saletracker ", saletracker
You are giving them all the same value for variable attribute -- they each need to each have their own instance of a StringVar. You need to move creation of val inside the loop so that each checkbutton gets a unique StringVar.
You also have the problem that, after creating the new variable, you aren't setting it to a value. When creating checkbuttons, you need to make sure that the associated variable is set to either the on value or the off value.
There are two issues with the code above. First the creation of the variable val ought to be for every checkbox created and failing to initialse the boxes to one of the values. After making these two corrections the code worked fine.
def printcheckbuttons():
for x in range (len(checkboxlist)):
for ki in checkboxlist:
#val=StringVar()
if ki.var.get() != 'null':
val=StringVar()
sale=Checkbutton(frameright,text=ki.var.get()[0:],variable=val,onvalue=ki.var.get(),offvalue='null')
sale.val=val
saletracker.append(sale)
sale.pack(anchor=NW)
sale.deselect()
checkboxlist.remove(ki)
ki.destroy()
print 'checkboxlist 1',checkboxlist
destroyboxes(checkboxlist)
print 'checkboxlist',checkboxlist
print "saletracker ", saletracker
So I did earlier, a few months ago, ask a similar question but I can't seem to apply the same rules/laws as were applied in a previous question of mine. Like my name suggest my understanding of Python is very basic and so I am confused at why his code won't work...
Every time I load a new screen, the old set of boxes should disappear and new only the new ones should be left there. However this is not what happens. Here are pictures to demonstrate:
Link to the full code.
However I think the problem may lie here in this part of the code:
def deletePanes(self):
print("delete panes")
Panes = []
self.NoOfPanes = 0
I also call Panes = [] in an earlier section of the code which lies in class Application():. Is the problem possibly that I am calling it twice? What I mean by this is that is it possible that one Panes list has the old boxes in it and one Panes has the new set in it and so when it comes to draw on the PyGame screen it draw both old and new boxes? (All of this might make more sense if you have a look at the full code)
Thank you for any help in advance.
When you call
Panes = []
inside a function, it creates a new local variable Panes and sets it to an empty list.
If it is a global variable, you should call
Panes[:] = []
If it is in the class, you should call
self.Panes = []
Panes is a local variable and will not change the value of your other use of Panes. You need to either make Panes global or an instance variable. Do the same in each place in your code that references Panes