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.
Related
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()
i'm making a sort of android lock thing on kivy, and to draw the line, I need to get the id of the widget the mouse is on, so I assing an id to each one like this in the .kv file:
ClickableImage:
id: one
source: 'button.png'
etc.
and I know I can get all the ids (I have 9, of course), with the
self.parent.ids.id
or
self.parent.ids['id']
but is there a way to get the ID the mouse is in? or the one I click? I have a hoverable class so it detects when it enters in a Widget, but I don't really know how to get its position, or change its source.
Is there any:
self.parten.ids.current
or something like that?
thanks for the help
You can use collide_widget or collide_point and in the widget set a method that will change a variable in the parent, let's say selected_widget to the current widget's like this:
if self.collide_point(*Window.mouse_pos):
self.parent.selected_widget = self # or its id
Then you can do with it anything. Maybe it'd be even better to put your logic into the widget itself and handle collision directly there. Obviously you'll need to bind a method you create with that if block above to an event such as on_release or on_press so run the method, otherwise it won't do a thing.
You can also get a hoverable behavior from this PR or even from this snippet.
Edit:
Please note that the id will not be available in the widget instance
Which means self.ids.my_id.id == None and therefore to actually get id you need to do this:
def find(self, parent, widget):
for id, obj in parent.ids.items():
if obj == widget:
print id
return id
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.
It looks like the only way to get the selected item of a gtk.TreeView() is to actually click on it :
tree_selection = self.treeview.get_selection()
tree_selection.connect('changed', self.my_callback)
self.treeview.connect('row-activated', self.my_other_callback)
But what if I'm listing files in my treeview, and need a "file properties" menu item?
Or a play button, that needs to access selected file to pass the filename to a player class / method ?
Bonus question : How to call my_other_callback from tree_selection.connect('changed', ...) (that does not seem to return all the row data..?) or in other words, how to pass treeview and path to the callback?
To get the selection of a tree view, call the get_selected_rows method of the gtk.TreeSelection object. You can call it at any place from which you can access the tree view.
It is unclear why you want to pass the tree view to my_other_callback since it, being a method on your class, can access it as self.treeview. But if you want to do it anyway, you can add the tree view (or any other Python object) as an additional argument to connect:
tree_selection.connect('changed', self.my_other_callback, self.treeview)
For an even finer-grained control of how the callback is invoked, use a lambda:
tree_selection.connect('changed', lambda *args: self.my_other_callback(self.treeview))
This allows you to use the same handler for multiple signals without having to declare the handler as accepting *args.
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