-
-
Notifications
You must be signed in to change notification settings - Fork 401
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add radio button #186
Add radio button #186
Conversation
@keliomer Well done, and thank you for contributing. But, are you sure that RadioButtonLabel is useful? I see that 'radio' input accepts text appended, like: input type="radio" name="gender" value="female"> Female so maybe RadioButton itself is enough. |
@keliomer Testing the RadioButton I was unable to generate the on_change event correctly. Have you got it working? |
I see what you mean now! I'll need to look at how we can track those. Do you have example code with a description? I definitely don't mind getting it to do what we need it |
Do you mean example code to reproduce the problem? |
Yep that's what I was going to do. I'll have something up tomorrow.
…On Thu, Jun 1, 2017, 10:19 PM Davide Rosa ***@***.***> wrote:
Do you mean example code to reproduce the problem?
However I think that there is a solution: we have to create an appropriate
container for RadioButtons (Qt calls it QRadioGroup), that listens the
onclick events coming from children and manages the status of them (if one
RadioButton gets clicked, its state is True, the other are False)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#186 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AKhzgNbVEYZkSOhd8VzVPS0W9vJhF2Nkks5r_3FLgaJpZM4NtU0J>
.
|
Consider that, this 'container' have to be NOT a layout. It should be just an event listener. This is because, differently, the user would loose the possibility to choice for a custom layout. |
Hi @dddomodossola thanks |
Just a week ago I created a radio button for another user. I will integrate this soon in remi. I will try to provide you an example tomorrow, I can't promise because I'm a bit busy this period |
Thanks @dddomodossola , this is very kind of you. I will be waiting for your example. Cheers, |
@keliomer @m-kareem Here is a radio button example: # -*- coding: utf-8 -*-
from remi import gui
from remi import start, App
class LabelForInputs(gui.Widget, gui._MixinTextualWidget):
""" Non editable text label widget. Specifically designed to be used in conjunction with checkboxes and radiobuttons
"""
def __init__(self, text, widget_for_instance, *args, **kwargs):
"""
Args:
text (str): The string content that have to be displayed in the Label.
widget_for_instance (gui.Widget): checkbox or radiobutton instance
kwargs: See Container.__init__()
"""
super(LabelForInputs, self).__init__(*args, **kwargs)
self.type = 'label'
self.attributes['for'] = widget_for_instance.identifier
self.set_text(text)
class InputCheckable(gui.Input):
"""It is the base class for checkable widgets (Switch, RadioButton, Checkbox).
Checkable are the widgets that contains attribute 'checked' to determine the status
The developer has to pass the the argument _type to the constructor
to determine the kind of widget.
"""
def __init__(self, status_on=False, input_type='checkbox', *args, **kwargs):
"""
Args:
status_on (bool):
kwargs: See Widget.__init__()
"""
super(InputCheckable, self).__init__(input_type, *args, **kwargs)
self.set_value(status_on)
self.attributes[gui.Widget.EVENT_ONCHANGE] = \
"var params={};params['value']=document.getElementById('%(emitter_identifier)s').checked;" \
"sendCallbackParam('%(emitter_identifier)s','%(event_name)s',params);" % \
{'emitter_identifier': str(self.identifier), 'event_name': gui.Widget.EVENT_ONCHANGE}
@gui.decorate_event
def onchange(self, value):
value = value in ('True', 'true')
self.set_value(value)
self._set_updated()
return (value,)
def set_value(self, status_on):
if status_on:
self.attributes['checked'] = 'checked'
else:
if 'checked' in self.attributes:
del self.attributes['checked']
def get_value(self):
"""
Returns:
bool:
"""
return 'checked' in self.attributes
class RadioButton(InputCheckable):
"""RadioButton widget, useful for exclusive selection.
different radiobuttons have to be assigned to the
same group name in order to switch exclusively.
"""
@property
def attr_name(self):
return self.attributes.get('name', '')
@attr_name.setter
def attr_name(self, value):
self.attributes['name'] = str(value)
def __init__(self, status_on=False, group='group', *args, **kwargs):
"""
Args:
status_on (bool): the initial value
group (str): the group name. RadioButtons with same group will be exclusively activated
kwargs: See Widget.__init__()
"""
super(RadioButton, self).__init__(status_on, input_type='radio', *args, **kwargs)
self.attr_name = group
def set_value(self, status_on):
InputCheckable.set_value(self, status_on)
# if on and has a parent, all other radios with same group name are switched off
if status_on and self.get_parent():
for w in self.get_parent().children.values():
if isinstance(w, type(self)):
if w.identifier != self.identifier:
if w.get_group() == self.get_group():
w.set_value(False)
def set_group(self, group_name):
self.attr_name = group_name
def get_group(self):
return self.attr_name
class RadioButtonWithLabel(gui.Container):
_radio = None
_label = None
@property
def text(self):
return self._label.get_text()
@text.setter
def text(self, value):
self._label.set_text(value)
@property
def attr_name(self):
return self._radio.attr_name
@attr_name.setter
def attr_name(self, value):
self._radio.attr_name = str(value)
def __init__(self, text='radiobutton', status_on=False, group='group', *args, **kwargs):
"""
Args:
text (str): the text label
status_on (bool): the initial value
group (str): the group name. RadioButtons with same group will be exclusively activated
kwargs: See Widget.__init__()
"""
super(RadioButtonWithLabel, self).__init__(*args, **kwargs)
self._radio = RadioButton(status_on, group=group)
self.append(self._radio, key='radio')
self._label = LabelForInputs(text, self._radio)
self.append(self._label, key='label')
self._radio.onchange.connect(self.onchange)
@gui.decorate_event
def onchange(self, widget, value):
self.__update_other_radios()
return (value,)
def get_text(self):
return self._label.text
def set_text(self, text):
self._label.text = text
def set_group(self, group_name):
self.attr_name = group_name
def get_group(self):
return self.attr_name
def get_value(self):
return self._radio.get_value()
def set_value(self, value):
""" Args:
value (bool): defines the checked status for the radio button
"""
self._radio.set_value(value)
self.__update_other_radios()
def __update_other_radios(self):
# if on and has a parent,
# all other radios, in the same container,
# with same group name are switched off
if self.get_value() and self.get_parent():
for w in self.get_parent().children.values():
if isinstance(w, type(self)):
if w.identifier != self.identifier:
if w.get_group() == self.get_group():
w.set_value(False)
class MyApp(App):
def main(self):
container = gui.VBox(style={'margin':'0px auto'})
self.lbl_output = gui.Label()
radio1 = RadioButtonWithLabel('Banana',False, 'groupFruits')
radio2 = RadioButtonWithLabel('Apple',False, 'groupFruits')
radio3 = RadioButtonWithLabel('Orange',False, 'groupFruits')
radio1.onchange.do(self.radio_changed)
radio2.onchange.do(self.radio_changed)
radio3.onchange.do(self.radio_changed)
container.append([self.lbl_output, radio1, radio2, radio3])
return container
def radio_changed(self, emitter, value):
self.lbl_output.set_text("The radio button labeled: %s is %s"%(emitter.get_text(), str(value)))
if __name__ == "__main__":
start(MyApp) |
The above example no longer works, due to a change in REMI, it can be easily fixed by replacing self.attributes[gui.Widget.EVENT_ONCHANGE] = \
"var params={};params['value']=document.getElementById('%(emitter_identifier)s').checked;" \
"sendCallbackParam('%(emitter_identifier)s','%(event_name)s',params);" % \
{'emitter_identifier': str(self.identifier), 'event_name': gui.Widget.EVENT_ONCHANGE} with: self.attributes[gui.Widget.EVENT_ONCHANGE] = \
"var params={};params['value']=document.getElementById('%(emitter_identifier)s').checked;" \
"remi.sendCallbackParam('%(emitter_identifier)s','%(event_name)s',params);" % \
{'emitter_identifier': str(self.identifier), 'event_name': gui.Widget.EVENT_ONCHANGE} (Remi made sendCallbackParam a function of |
Thank you a lot @jimbob88 ;-) |
There also seems to be a strange glitch with this where it doesn't work with the TabBox widget. When one changes tabs after having changed the currently selected radio button, the last checked radio is not saved (moreover the html tag for that radio button never reads <"checked"="checked">) So, for the first radio button that you use HTML.mp4# -*- coding: utf-8 -*-
from remi import gui
from remi import start, App
class LabelForInputs(gui.Widget, gui._MixinTextualWidget):
""" Non editable text label widget. Specifically designed to be used in conjunction with checkboxes and radiobuttons
"""
def __init__(self, text, widget_for_instance, *args, **kwargs):
"""
Args:
text (str): The string content that have to be displayed in the Label.
widget_for_instance (gui.Widget): checkbox or radiobutton instance
kwargs: See Container.__init__()
"""
super(LabelForInputs, self).__init__(*args, **kwargs)
self.type = 'label'
self.attributes['for'] = widget_for_instance.identifier
self.set_text(text)
class InputCheckable(gui.Input):
"""It is the base class for checkable widgets (Switch, RadioButton, Checkbox).
Checkable are the widgets that contains attribute 'checked' to determine the status
The developer has to pass the the argument _type to the constructor
to determine the kind of widget.
"""
def __init__(self, status_on=False, input_type='checkbox', *args, **kwargs):
"""
Args:
status_on (bool):
kwargs: See Widget.__init__()
"""
super(InputCheckable, self).__init__(input_type, *args, **kwargs)
self.set_value(status_on)
self.attributes[gui.Widget.EVENT_ONCHANGE] = \
"var params={};params['value']=document.getElementById('%(emitter_identifier)s').checked;" \
"remi.sendCallbackParam('%(emitter_identifier)s','%(event_name)s',params);" % \
{'emitter_identifier': str(self.identifier), 'event_name': gui.Widget.EVENT_ONCHANGE}
@gui.decorate_event
def onchange(self, value):
value = value in ('True', 'true')
self.set_value(value)
self._set_updated()
return (value,)
def set_value(self, status_on):
if status_on:
self.attributes['checked'] = 'checked'
else:
if 'checked' in self.attributes:
del self.attributes['checked']
def get_value(self):
"""
Returns:
bool:
"""
return 'checked' in self.attributes
class RadioButton(InputCheckable):
"""RadioButton widget, useful for exclusive selection.
different radiobuttons have to be assigned to the
same group name in order to switch exclusively.
"""
@property
def attr_name(self):
return self.attributes.get('name', '')
@attr_name.setter
def attr_name(self, value):
self.attributes['name'] = str(value)
def __init__(self, status_on=False, group='group', *args, **kwargs):
"""
Args:
status_on (bool): the initial value
group (str): the group name. RadioButtons with same group will be exclusively activated
kwargs: See Widget.__init__()
"""
super(RadioButton, self).__init__(status_on, input_type='radio', *args, **kwargs)
self.attr_name = group
def set_value(self, status_on):
InputCheckable.set_value(self, status_on)
# if on and has a parent, all other radios with same group name are switched off
if status_on and self.get_parent():
for w in self.get_parent().children.values():
if isinstance(w, type(self)):
if w.identifier != self.identifier:
if w.get_group() == self.get_group():
w.set_value(False)
def set_group(self, group_name):
self.attr_name = group_name
def get_group(self):
return self.attr_name
class RadioButtonWithLabel(gui.Container):
_radio = None
_label = None
@property
def text(self):
return self._label.get_text()
@text.setter
def text(self, value):
self._label.set_text(value)
@property
def attr_name(self):
return self._radio.attr_name
@attr_name.setter
def attr_name(self, value):
self._radio.attr_name = str(value)
def __init__(self, text='radiobutton', status_on=False, group='group', *args, **kwargs):
"""
Args:
text (str): the text label
status_on (bool): the initial value
group (str): the group name. RadioButtons with same group will be exclusively activated
kwargs: See Widget.__init__()
"""
super(RadioButtonWithLabel, self).__init__(*args, **kwargs)
self._radio = RadioButton(status_on, group=group)
self.append(self._radio, key='radio')
self._label = LabelForInputs(text, self._radio)
self.append(self._label, key='label')
self._radio.onchange.connect(self.onchange)
@gui.decorate_event
def onchange(self, widget, value):
self.__update_other_radios()
return (value,)
def get_text(self):
return self._label.text
def set_text(self, text):
self._label.text = text
def set_group(self, group_name):
self.attr_name = group_name
def get_group(self):
return self.attr_name
def get_value(self):
return self._radio.get_value()
def set_value(self, value):
""" Args:
value (bool): defines the checked status for the radio button
"""
self._radio.set_value(value)
self.__update_other_radios()
def __update_other_radios(self):
# if on and has a parent,
# all other radios, in the same container,
# with same group name are switched off
if self.get_value() and self.get_parent():
for w in self.get_parent().children.values():
if isinstance(w, type(self)):
if w.identifier != self.identifier:
if w.get_group() == self.get_group():
w.set_value(False)
class MyApp(App):
def main(self):
tb = gui.TabBox()
tb.style.update({"margin": "0px", "width": "800px", "height": "680px",
"top": "5%", "left": "15px", "position": "absolute", "overflow": "auto"})
container = gui.VBox(style={'margin':'0px auto'})
self.lbl_output = gui.Label()
radio1 = RadioButtonWithLabel('Banana',False, 'groupFruits')
radio2 = RadioButtonWithLabel('Apple',False, 'groupFruits')
radio3 = RadioButtonWithLabel('Orange',False, 'groupFruits')
radio1.onchange.do(self.radio_changed)
radio2.onchange.do(self.radio_changed)
radio3.onchange.do(self.radio_changed)
radio1.set_value(True)
container.append([radio1, radio2, radio3])
container.style['position'] = 'relative'
container2 = gui.VBox(style={'margin':'0px auto'})
container2.style['position'] = 'relative'
container2.append([self.lbl_output])
tb.add_tab(container, "Container", None)
tb.add_tab(container2, "Container2", None)
return tb
def radio_changed(self, emitter, value):
print("The radio button labeled: %s is %s"%(emitter.get_text(), str(value)))
self.lbl_output.set_text("The radio button labeled: %s is %s"%(emitter.get_text(), str(value)))
if __name__ == "__main__":
start(MyApp, port=8081, start_browser=False) |
Comment this line self._set_updated() in class InputCheckable(gui.Input): , you can solve this problem |
Thank you very much ;-) |
Added RadioButton and RadioButtonLabel widgets