get current id of widget on python / kivy - python

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

Related

How to Set and Get "comment" text using setText?

I am trying to store string data within a QAbstractButton.text().
Why?
I want to display the short name in the text() itself, but be able to call the long name via the text() "comment" through code.
You are able to write "comments" within QT Designer, but I have been unable to replicate this in Python.
Looking at the code in notepad, it appears the "comment" text is created within the text string itself:
<property name="text">
<string extracomment="toast">Select object and click here</string>
What I currently have in python is:
Xsl = cmds.ls(sl=1)[0]
Xbutton.setText(Xsl)
How can I also set and get the comment part of this text?
Any advice would be appreciated!
If you want to add extra data to a widget why not just subclass it and create your own?
class MyCustomButton(QtWidgets.QPushButton):
def __init__(self, parent=None):
super(MyCustomButton, self).__init__(parent)
self.my_variable = None
Now you can continue using MyCustomButton just like a normal button, and also add whatever you like to my_variable.
I have found that every object contains a variable for windowTitle. If this isn't the main window, the window title is generally left blank, therefore I can store data here.
Granted, this probably isn't the cleanest approach, but it'll serve for now.
Green Cell's subclassing is most likely the best way to resolve this issue. However, I am mainly building the UI using Qt Designer, and want to primarily keep any edits within that wrapper.
def store_selected_node_on_button(self):
"""
Changes the text of a given button to store an object's name
As the button isn't a window, I can set the window title to store the long name of the selected object.
:return: None
"""
button = self.sender()
sl = cmds.ls(sl=1, long=True)
if not sl:
button.setText("Select object and click here")
button.setWindowTitle("")
else:
button.setText(sl[0].split("|")[-1])
button.setWindowTitle(sl[0])
return

PyQt5 double spin box returning none value

I have this: (there are class methods, which inherience from QWizard)
def getForms(self):
return [
(
QtWidgets.QLabel("Name"),
QtWidgets.QLineEdit()
),
(
QtWidgets.QLabel("Roll"),
QtWidgets.QDoubleSpinBox()
)
]
def registerFields(self, page, forms):
page.registerField("name*", forms[0][1])
page.registerField("roll", forms[1][1])
And in other place in code
id = self.currentId()
if id == 1:
print self.field("name") # this rightly give me a name from LineEdit
print self.field("roll") # but this give me just None, why?
When I changed
QtWidgets.QDoubleSpinBox()
to
QtWidgets.QSpinBox()
Line:
print self.field("roll")
works fine.
Why do I get None instead double value?
EDIT
I've just noticed that when I'm trying make 'roll' field as a mandatory.
page.registerField("roll*", forms[1][1])
And I fill this 'spinbox' in program, I can not click 'next' (next is disabled). I have spinbox in my form in program. I can set the value there. But this looks like this field is not connected with QWizard(?)?
The QWizardPage class only has internal knowledge of a few widget types. When registering a widget it does not know about, you need to specify the property for reading the value, along with the signal that is emitted when a value is changed, as a string.
For QDoubleSpinBox this would be:
page.registerField("roll", forms[1][1], "value", "valueChanged")
The list of widget types QWizardPage knows about is listed in the c++ documentation here.
You can also register this information globally using a method of QWizard, so that you don't have to specify it each time you call registerField(). To do this, call:
my_wizard.setDefaultProperty("QDoubleSpinBox", "value", "valueChanged")
Note: This is a method of the wizard, not the page.

Kivy dynamic widget issue

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.

Getting multiple wx widget values with Event Handling

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.

Access gtk.TreeIter inside render() Function of gtk.CellRenderer -- pygtk

I am trying to code the following: Two Columns. One contains a itemId, the other one contains a typeId. I want to render the itemId only when the typeId equals a specific value.
class IDRenderer(gtk.CellRendererText):
def __init__(self):
gtk.CellRendererText.__init__(self)
def do_render(self,window, widget, background_area, cell_area, expose_area, flags):
if ----} Condition to ask for value of the typeId - Cell {-----:
gtk.CellRendererText.do_render(self, window, widget, background_area, cell_area,
expose_area, flags)
gobject.type_register(IDRenderer)
I don't know how to get the iter of the currently rendered row which i need to determine the value of the typeId. Is this even possible?
I now found out, thanks to a nice guy on #pygtk on gimpIRC:
You can do that, with binding so called cell data functions to the corresponding gtk.TreeViewColumn as done here in this example
def renderId(celllayout, cell, model, iter):
if model.get_value(iter,1) == 3:
cell.set_property('visible',True)
else:
cell.set_property('visible',False)
treeviewcolumn = gtk.TreeViewColumn()
renderer = gtk.CellRendererText()
treeviewcolumn.add_attribute(renderer,'text',0)
treeviewcolumn.set_cell_data_func(renderer,renderId)
I ommited some code relevant to render a complete treeview, but i think it shows what i wanted to do and how to do it.
The column renderes the value in the first column (0) of the model only if the value in the second modelcolumn (1) equals 3
I hope this could help someone some time.
It's not possible as far as I know. You need to use properties of the custom renderer which will be set automatically by the code calling the rendering function. (Like the text property of CellRendererText -- the rendering code doesn't get the text from the tree model, but the tree model sets the text property of the renderer before calling the rendering code.)

Categories