开发者

Asynchronous validation in QWizard

开发者 https://www.devze.com 2023-02-06 07:18 出处:网络
I\'m writing a wizard UI based on the QWizard Qt object. There\'s one particular situation where I want the user to log in to a service using host, username, and password. The rest of the wizard then

I'm writing a wizard UI based on the QWizard Qt object. There's one particular situation where I want the user to log in to a service using host, username, and password. The rest of the wizard then manipulates this service to do various setup tasks. The login may take a while, especially in error cases where the DNS name takes a long time to resolve -- or perhaps it may not even resolve at all.

So my idea is to make all three fields mandatory using the registerField mechanism, and when the user hits Next, we show a little throbber on the wizard page saying "Connecting to server, please wait..." while we try to connect in the background. If the connection succeeds, we advance to the next page. If not, we highlight the offending field and ask the user to try again.

However, I'm at a loss for how to accomplish this. The options I've thought of:

1) Override validatePage and have it start a thread in the background. Enter a wait inside validatePage() that pumps the Qt event loop until the thread finishes. You'd think this was the ugliest solution, but...

2) Hide the real Next button and add a custom Next button that, whe开发者_运维百科n clicked, dispatches my long running function in a thread and waits for a 'validation complete' signal to be raised by something. When that happens, we manually call QWizard::next() (and we completely bypass the real validation logic from validatePage and friends.) This is even uglier, but moves the ugliness to a different level that may make development easier.

Surely there's a better way?


It's not as visually appealing, but you could add a connecting page, and move to that page. If the connection succeeds, call next() on the wizard, and if the connection fails, call previous() and highlight the appropriate fields. It has the advantage of being relatively straightforward to code.


My final choice was #2 (override the Next button, simulate its behavior, but capture its click events manually and do the things I want to with it.) Writing the glue to define the Next button's behavior was minimal, and I was able to subclass QWizardPage with a number of hooks that let me run my task ON the same page, instead of having to switch to an interstitial page and worry about whether to go forwards or backwards. Thanks Caleb for your answer though.


I know this has already been answered (a long time ago!) but in case anyone else is having the same challenge. Another method for this is to create a QLineEdit, initiate it as empty and set it as a mandatory registered field. This will mean that "Next" is not enabled until it is filled with some text. Run your connection task as normal and when it completes use setText to update the QLineEdit to "True" or "Logged in" or anything other than empty. This will then mean the built in isComplete function will be passed as this previously missing mandatory field is now complete. If you never add it to the layout then it won't be seen and the user won't be able to interact with it.

As an example ...

self.validated_field = QLineEdit("")
self.registerField('validated*', self.validated_field)

and then when your login process completes successfully

self.validated_field.setText("True")

This should do it and is very lightweight. Be sure though that you consider the scenario where a user then goes back to that page and whether you need to reset the field to blank. If that's the case then just add in the initialisePage() function to set it back to blank

self.validated_field.setText("")

Thinking about it you could also add the line edit to the display and disable it so that a user cannot update it and then give it a meaningful completion message to act as a status update...

self.validated_field = QLineEdit("")
self.validated_field.setDisabled(True)
self.validated_field.setStyleSheet("border:0;background-color:none")
self.main_layout.addWidget(self.validated_field)
self.registerField('validated*', self.validated_field)

and then when you update it..

self.validated_field.setText("Logged in")
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号