Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Implementing a radio style (single selected option) check mark in a forms dialog
-
I would like to use the check type entry in a form dialog but in a radio button fashion. ie only one check mark in that section at a time.
I’m trying to work it out and I think I know how to program it, I just don’t know where to implement it in the _FormDialogController
-
-
-
Wow, and I've just found the segmented control too that @cvp was talking about. Am working to implement that. A single line of options is much better than a list. That's very nice, I'll let you know how I get on
-
@madivad try this and see field under age and value of returned diag when you select a segment
import dialogs import datetime import ui #================ copy dialogs.form_dialog: begin import collections import sys PY3 = sys.version_info[0] >= 3 if PY3: basestring = str def my_form_dialog(title='', fields=None, sections=None, done_button_title='Done'): if not sections and not fields: raise ValueError('sections or fields are required') if not sections: sections = [('', fields)] if not isinstance(title, basestring): raise TypeError('title must be a string') for section in sections: if not isinstance(section, collections.Sequence): raise TypeError('Sections must be sequences (title, fields)') if len(section) < 2: raise TypeError('Sections must have 2 or 3 items (title, fields[, footer]') if not isinstance(section[0], basestring): raise TypeError('Section titles must be strings') if not isinstance(section[1], collections.Sequence): raise TypeError('Expected a sequence of field dicts') for field in section[1]: if not isinstance(field, dict): raise TypeError('fields must be dicts') #========== modify 1: begin c = dialogs._FormDialogController(title, sections, done_button_title=done_button_title) for s in range(0,len(c.sections)): for i in range(0,len(c.cells[s])): # loop on rows of section s cell = c.cells[s][i] if len(cell.content_view.subviews) > 0: tf = cell.content_view.subviews[0] # ui.TextField of value in row item = c.sections[s][1][i] # section s, 1=items, row i if 'segments' in item: segmented = ui.SegmentedControl() segmented.name = cell.text_label.text segmented.frame = tf.frame segmented.x = c.view.width - segmented.width - 8 segmented.segments = item['segments'] cell.content_view.remove_subview(tf) del c.values[tf.name] del tf cell.content_view.add_subview(segmented) #========== modify 1: end c.container_view.present('sheet') c.container_view.wait_modal() # Get rid of the view to avoid a retain cycle: c.container_view = None if c.was_canceled: return None #========== modify 2: begin for s in range(0,len(c.sections)): for i in range(0,len(c.cells[s])): # loop on rows of section s cell = c.cells[s][i] if len(cell.content_view.subviews) > 0: tf = cell.content_view.subviews[0] # ui.TextField of value in row if isinstance(tf, ui.SegmentedControl): if tf.selected_index >= 0: item = c.sections[s][1][i] # section s, 1=items, row i c.values[tf.name] = item['segments'][tf.selected_index] #========== modify 2: end return c.values #================ copy dialogs.form_dialog: end form_list_of_sections = [] sectionA_dicts = [] sectionA_dicts.append(dict(type = 'text', title = 'First Name', key = 'first', placeholder = 'John')) sectionA_dicts.append(dict(type = 'text', title = 'Last Name', key = 'last', placeholder = 'Doe')) sectionA_dicts.append(dict(type = 'number', title = 'age', key = 'age', placeholder='30')) sectionA_dicts.append(dict(type = 'text', title = 'My segmented control', key = 'segm', segments = ['yes','no'])) form_list_of_sections.append(('Section A', sectionA_dicts, 'Section A ends')) sectionB_dicts = [] sectionB_dicts.append(dict(type = 'date', title = 'Date Of Birth', key = 'DOB', value = datetime.date.today())) sectionB_dicts.append(dict(type = 'url', title = 'Home Page', key = 'homepage', placeholder = 'http://example.com')) form_list_of_sections.append(('Section B', sectionB_dicts, 'Section B ends')) sectionC_dicts = [] sectionC_dicts.append(dict(type = 'email', title = 'email', key = 'email', placeholder = 'name@mailserver.com')) sectionC_dicts.append(dict(type = 'switch', title = 'is_married', key = 'is_married', value = True)) sectionC_dicts.append(dict(type = 'check', title = 'is_registered', key = 'is_registered', value = False)) form_list_of_sections.append(('Section C', sectionC_dicts, 'Section C ends')) diag = my_form_dialog(title = 'Form Dialog', sections=form_list_of_sections) print(diag)
-
@madivad said:
What is the method that is called within the form controller that would need to be overwritten/created?
I don't understand the question if it is relative to the switch because your sample already contains a switch.
-
And without your own form_dialog....but it has been hard to find 😅
def segmented_action(sender): global c if sender.selected_index >= 0: c.values[sender.name] = sender.segments[sender.selected_index] def my_tableview_cell_for_row(self,tv, section, row): global c c = self cell = self.cells[section][row] if len(cell.content_view.subviews) > 0: tf = cell.content_view.subviews[0] # ui.TextField of value in row item = self.sections[section][1][row] if 'segments' in item: # check if SegmentedControl already added for sv in cell.content_view.subviews: if type(sv) is ui.SegmentedControl: return cell segmented = ui.SegmentedControl() segmented.name = cell.text_label.text segmented.action = segmented_action segmented.frame = tf.frame segmented.x = c.view.width - segmented.width - 8 segmented.segments = item['segments'] cell.content_view.add_subview(segmented) elif isinstance(tf, ui.TextField): tf.alignment=ui.ALIGN_RIGHT return cell dialogs._FormDialogController.tableview_cell_for_row = my_tableview_cell_for_row diag = dialogs.form_dialog(title = 'Form Dialog', sections=form_list_of_sections)
-
The last code is not correct if you scroll the dialog so the Segments are hidden and reshown back because the code adds a new subview each time. Let me some time to correct it.
That's the problem when you do this process in tableview_cell_for_row -
Code corrected (and edited in the post), sorry for that
-
And if you want a dialog field as a button (radio, checkbox, ...), this code could help you.
You have to design the field with two images for your button, like:sectionA_dicts.append(dict(type = 'text', title = 'My button', key = 'button', button = ['iob:ios7_checkmark_32','iob:ios7_checkmark_outline_32']))
and the associated process:
def button_action(sender): global c sender.idx = 1 - sender.idx sender.image = ui.Image.named(sender.images[sender.idx]) c.values[sender.name] = sender.idx def my_tableview_cell_for_row(self,tv, section, row): global c c = self cell = self.cells[section][row] if len(cell.content_view.subviews) > 0: tf = cell.content_view.subviews[0] # ui.TextField of value in row item = self.sections[section][1][row] if 'segments' in item: # check if SegmentedControl already added for sv in cell.content_view.subviews: if type(sv) is ui.SegmentedControl: return cell segmented = ui.SegmentedControl() segmented.name = cell.text_label.text segmented.action = segmented_action segmented.frame = tf.frame segmented.x = c.view.width - segmented.width - 8 segmented.segments = item['segments'] cell.content_view.add_subview(segmented) elif 'button' in item: # check if Button already added for sv in cell.content_view.subviews: if type(sv) is ui.Button: return cell button = ui.Button() button.name = cell.text_label.text button.action = button_action button.frame = tf.frame button.width = button.height button.x = c.view.width - button.width - 8 button.images = item['button'] button.title = '' button.idx = 0 button.image = ui.Image.named(button.images[button.idx]) cell.content_view.add_subview(button) elif type(tf) is ui.TextField: tf.alignment=ui.ALIGN_RIGHT return cell
-
and supporting color images in button:
. . . sectionA_dicts.append(dict(type = 'text', title = 'My face', key = 'face', button = ['emj:Smiling_1','emj:Disappointed'])) . . . def button_action(sender): global c sender.idx = 1 - sender.idx sender.image = ui.Image.named(sender.images[sender.idx]).with_rendering_mode(ui.RENDERING_MODE_ORIGINAL) c.values[sender.name] = sender.idx . . . button.image = ui.Image.named(button.images[button.idx]).with_rendering_mode(ui.RENDERING_MODE_ORIGINAL) . . .
-
@cvp you are incredible...
I saw your first posts on the way to work and thought, “yeah, I have to get to that!” And now I log back and on and find this!!!! MUCH to digest!
I will be back (busy the next few days, but the kids are on holidays after tomorrow and I’ll slow down on the workload, so I should be able to get into this more)
Seriously, thanks for your contributions, you are awesome!
-
@cvp I finally got back to this, I got it all working as expected, the only issue I have is with the custom rows (My segmented control*, My button, and My face), they allow the cursor into the row label on the left hand side if the user touches near them.
I’ve spent a couple of hours going over the cradle and only minimally beginning to understand it :)
* the segmented control is ok in the custom/my_form_dialog and doesn’t allow the cursor in. It only allows the cursor when using the inbuilt dialog.
-
@madivad It is normal. When we create the new fields types in tableview_cell_for_row, the original TextField still exists. In the other case, the code deletes the TextField.
-
@madivad you can add these lines when you create a new field type
aftercell.content_view.add_subview(segmented)
Add
cell.content_view.remove_subview(tf) del self.values[tf.name] del tf
-
@cvp said:
cell.content_view.remove_subview(tf) del self.values[tf.name] del tf
I knew it was something like that, I was giving it a go but hadn’t got it right.
Thanks.