I needed a way to display multiple forms in an alert in sequence, like a typical wizard interface, so I wrote a wizard form to handle the grunt work. Posted here in the hopes it’ll be useful for someone else: Anvil | Login
If you just want to see how it works, here’s the link to the most current version: https://honest-trusty-airport.anvil.app
There’s basic support for validation of each step of the wizard, and aggregating the results at the end. You can also hook actions in the steps up to the next button, e.g. hitting Enter in a text field can automatically move to the next step.
Edit: I’ve added enough customization that some documentation seems warranted.
Showing The Wizard
Create an instance of the wizard component by passing it a list of forms that make up the steps. Call the show method and if it returns True, that means the user finished the wizard:
from Wizard_Component.Wizard import Wizard
wizard = Wizard(item=steps)
if wizard.show():
print(wizard.get_data())
To prevent the user from cancelling the wizard, pass in allow_cancel=False:
wizard = Wizard(item=steps, allow_cancel=False)
Steps That Provide Information Only
The most basic step is a blank panel form that provides the user with information only. It needs nothing extra beyond the labels that display the information.
Steps That Take User Input
A step that takes user input must implement the get_data
method:
def get_data(self):
return {'real_name': self.text_box_1.text,
'use_nickname': self.use_nickname.checked}
Steps Where The User Can Enter Invalid Input
In steps where the user might enter something invalid, the step can use the validate
method to let the wizard know if the data in it is valid. Steps must display their own error messages.
def validate(self):
self.error_label.visible = not self.text_box_1.text
return bool(self.text_box_1.text)
Steps That Might Be Skipped
A step that might not show must implement the pre_show
method to tell the wizard whether the step should be shown, based on the data entered in previous steps:
def pre_show(self, data):
# Only show this step if they are a customer
return data['role'] == 'customer'
Steps That End The Wizard Early
If you have a branching set of steps, a step in the middle of the list might be the end of one branch. That step must set final_step
to True to tell the wizard that it’s the ending step of its branch.
def __init__(self, **properties):
self.init_components(**properties)
self.final_step = True
Steps That Need To Customize The Next/Finish Button
Especially with branching sequences, the text “Finish” might not be appropriate for every final step. A step can customize the text that appears in the Next/Finish button by setting the next_text property:
def __init__(self, **properties):
self.init_components(**properties)
self.next_text = "Start Using The Site"
self.final_step = True
Events Steps Can Use
There are events that steps can use to communicate back to the wizard:
x-next
allows a step to programmatically trigger the Next button click. Useful if your step has a single text box, to allow the user to press Enter to continue.
def text_box_1_pressed_enter(self, **event_args):
self.raise_event('x-next')
x-data
allows a step to get the current state of the wizard’s data. This cannot be used in the __init__
method of the step, since the wizard has not added the event to the step yet.
data = self.raise_event('x-data')
Adjusting Step Form Based On Data
The normal way to adjust the content on the step form based on the current data would be to add a pre_show
method, use the data parameter to modify the look of the form, and then return True. That all happens before the form is visible.