I have several widgets created in a loop, each given a sequential name, eg:
for item in itemlist:
myWidget=tk.Widget(root, name=item)
myWidget.pack()
Now I have widgets with pathnames like
.!mainapplication.!itemframe.item1
is it possible to use the pathname to destroy a widget?
I can't use myWidget.destroy() because then I can't target specific widgets.
If it's not possible I can create an array to hold the widgets and deal with them from there, but I was wondering if there was any way to do it this way.
If you save the return value of tk.Widget(...) to a list or dictionary, you can access any of the widgets without having to use the name. This is by far the most common and convenient way to manage widgets created in a loop.
Example:
widgets = []
for item in itemlist:
myWidget=tk.Widget(root, name=item)
myWidget.pack()
widgets.appen(widget)
...
for widget in widgets:
widget.destroy()
If you really need to convert a name to a widget, tkinter provides a method on every widget called nametowidget which accepts the name of a widget and returns the instance.
root.nametowidget('.!mainapplication.!itemframe.item1').destroy()
Related
I am programmatically adding tag_binds to all objects on my canvas that have the tag "tag":
self.canvas.tag_bind("tag","<Button 2>",self.tag_highlight)
self.canvas contains all the objects that the user has added (all tagged with "tag".
However, in tag_highlight, I would simply like to have a handle on the actual element within the canvas. event.widget doesn't seem to help, its just a tuple of 4 floats that I cannot link to any canvas item. I have tried to use the following, to no avail:
self.canvas.find_closest(event.x,event.y)
What I would like to do, is have a handle like:
t=self.canvas.getitem(event.widget)
so that I can use it for example in:
self.canvas.Move(t,30,20)
print self.canvas.coords(t)
and so forth.
Maybe I am just missing the obvious?
You can use the tag "current", which refers to the "current" object. The current object is described like this in the official tk documentation:
The tag current is managed automatically by Tk; it applies to the
current item, which is the topmost item whose drawn area covers the
position of the mouse cursor (different item types interpret this in
varying ways; see the individual item type documentation for details).
If the mouse is not in the canvas widget or is not over an item, then
no item has the current tag.
I have a QtabWidget and I made a ListWidget inside that tabwidget
self.tabWidget = QtGui.QTabWidget(self.centralwidget)
self.listWidget = QtGui.QListWidget(self.tabWidget)
Then I made a tab:
self.tab1 = QtGui.QWidget()
self.tabWidget.addTab(self.tab1,"hi")
What I'm trying to do is get the listview for inside QTabWidget for tab1.
print self.tabWidget.currentWidget()
It prints out a pointer:
PySide.QtGui.QWidget object at 0x0000000004EA84A4
I want the QListWidget so I can call functions like addItem etc.
Edit: I also have another question. I'm using Pyside and theres a function called retranslateUI and setupUI. I want to add a signal for my QTabWidget,
self.tabWidget.currentChanged.connect(self.showStreamList(self.tabWidget.tabText(self.tabWidget.currentIndex())))
but I'm not sure where to put it. I'm putting it in retranslateUI because thats there button.clicked.connects are but when I run the program, I think it executes this command first. The GUI doesn't even display. In general, where should I group these signals/event listeners?
Taking your comment into account, you seem to want to dynamically add QListWidgets to a QTabWidget and want individual access to each QListWidget.
QTabWidget's addTab() method takes a QWidget and a string as its arguments. A QListWidget, as the name implies, is derived / subclassed from QWidget. Therefore, the addTab() method will accept a QListWidget, if you pass it one. So self.tabWidget.addTab(self.listWidget,"hi") should work just fine.
Next, accessing them. QTabWidget has a method to access any tab by its index, sensibly called widget(index). Therefore, if you want to access the n-th widget, you can get it by calling self.tabWidget.widget(n).
You could therefore get any list widget and do stuff with it:
lw = self.tabWidget.widget(0) # get the 0th widget
lw.addItem(...)
CODE: http://pastebin.com/W4uXmazw
I would like to memorize how to get values from any wx widget with event handling after clicking a wx.Button.
In my program i have two fields, the new filename and the contents.
What are the steps i have to take in order to get the values from each field?
From there, i can use pythons f.open and f.write methods to complete my application.
Thanks!
If you want to get value of a widget, then you need to make that widget accessible throughout the entire class. To do that, you need to make the variable for the widget into an instance variable. So instead of adding the text control directly to the sizer, you'll want to do something like this:
self.newfilename = wx.TextCtrl(panel,-1), 0, wx.TOP, 5)
self.contents = wx.TextCtrl(panel,-1,size=(390,150),style = wx.TE_MULTILINE|wx.TE_PROCESS_TAB)
Then in your button's event handler, you can just do something like this:
valueOne = self.newfilename.GetValue()
contents = self.contents.GetValue()
The other way to do it would be to use your panel. If you use "self.panel", then you could grab all its children via its GetChildren method and then iterate over the list and use Python's "isinstance" builtin to check what kind of widget you're accessing. If you have set the widget's name, you can check that too.
What is the approach to update widgets in a wxPanel based on events from other controls on same panel?
Scenario 1 is updating the list of a comboBox based on what has been selected from another comboBox , where both are in same panel.
Scenario 2 is showing a new control/widget in a panel based on an event.
Basically creating new controls is easy but I dont know how to refresh/update my panel so immedialtly shows them.
Scenario 1
To change the choices of a combobox self.cbx you can use any of the following methods:
self.cbx.SetItems(choices) where choices is the full list of choices.
self.cbx.SetString(n, string) that sets the string at position n.
InsertItems(items, pos) Inserts the list of strings in the items argument into the list box before the position in the pos argument.
Note that the method Set(choices) of listboxes does not exist for the list in comboboxes. You must use SetItems(choices) instead (this is not clearly indicated in some textbooks).
If you want these changes to occur as a result of a selection in another combobox self.cbx_1 , just get the event (self.Bind(wx.EVT_COMBOBOX, on_combo_1, self.cbx_1)) of the first combobox, process your data as you like in the corresponding self.on_combo method and use one of the above methods to modify the second combobox.
For example:
def on_combo_1(self, evt):
"append cbx_1 selection to cbx if not already in cbx"
selection = self.cbx_1.GetStringSelection()
cbx_choices = self.cbx.GetItems()
if selection not in cbx_choices:
cbx_choices.append(selection)
self.cbx.SetItems(cbx_choices)
The fact the comboboxes are in the same or different panel is irrelevant for that.
Scenario 2
Normally you put your widgets inside sizers. To hide or made visible elements on the sizer you call the methods Show, Hide or Layout:
Show(self, item, show=True, recursive=false)
Shows or hides an item managed by the sizer. To make a sizer item disappear or reappear, use Show followed by Layout. The item parameter can be either a window, a sizer, or the zero-based index of the item. Use the recursive parameter to show or hide an item in a subsizer. Returns True if the item was found.
Hide(self, item, recursive)
A convenience method for Show (item, False, recursive).
Layout(self)
This method will force the recalculation and layout of the items controlled by the sizer using the current space allocated to the sizer. Normally this is called automatically from the owning window's EVT_SIZE handler, but it is also useful to call it from user code when one of the items in a sizer change size, or items are added or removed.
References: wxPython in Action, Noel Rappin and Robin Dunn
For scenario one, you'd do something like the following (assuming the first combobox is bound to its EVT_COMBOBOX:
value = self.cboOne.GetValue()
if value == "something":
self.cboTwo.SetItems(someList)
For showing a new widget, you could create it and then use Show()/Hide() as necessary. If the widget is in a sizer, then use the Sizer's Append or Insert methods. It also has a Detach method that can be used to hide widgets or you just call Hide itself. See the documentation for more information: http://www.wxpython.org/docs/api/wx.Sizer-class.html
Let's say that I have the following code:
root = Tk()
open = Button(self.root, text='Open', command=self.open, state='disabled')
open.pack()
close = Button(self.root, text='Close', command=self.close, state='disabled')
close.pack()
I only want to enable the buttons when some action is performed, so I need to access the buttons again later to edit the state variable. Rather than adding the buttons to a separate list and storing that, is there a way of accessing the buttons, or, for that matter, any set of objects that I have attached to the root (Menus, Drop down lists, or whatever), by calling a method on the root?
There is no definitive way to ask the root window for a list of all widgets. You can use pack_slaves or grid_slaves to get a list of widgets managed by a particular container, but depending on how you write your app that's no guarantee you'll get all the widgets.
You can also use winfo_children to get a list of all direct descendants of a widget. If you have a nested hierarchy of widgets (for example, by using frames as intermediary containers for organizational purpose) you may have to do some sort of looping to find a particular widget.
The best and simplest approach is to have your application be an instance of a class. You can then save references to the widgets as attributes of the class. I highly recommend this approach, there's simply no good reason to do it any other way.
For example:
class MyApp(Tk):
def __init__(self, *args, **kwargs):
...
self.open_button = Button(...)
self.close_button = Button(...)
...
def OnSomeEvent(self, event):
if ...:
self.open_button.configure(state="disabled")
else:
self.open_button.configure(state="normal")
Since you are using the pack method you can use the pack_slaves method to find items added. So to iterate over them you can do something like,
for item in root.pack_slaves():
item.do_stuff()
These will be in the root's children dictionary, but with a long int (the value of the pointer in the C layer I believe) as the key. (with newlines added in the dict value for readability)
> >>> from Tkinter import Tk, Button
> >>> root=Tk()
> >>> open=Button(root, text='Open')
> >>> root.__dict__
> {'_tclCommands': ['tkerror', 'exit', '3077241668Ldestroy'],
> 'master': None,
> 'children': {'3077328108L': <Tkinter.Button instance at 0xb76c4cec\>},
> '_tkloaded': 1,
> 'tk': <tkapp object at 0xb76bd560\>}