Archive: page navigation buttons slow GUI update


page navigation buttons slow GUI update
Buttons sometimes get updated too early or too late. If the computer is slow you can see enabled buttons for some seconds which should not be there (or should be disabled).

I see this sometimes, if I skip pages using the page functions (pre). Maybe the order is suboptimal. The buttons should be enabled after a page is really displayes (just before going idle and waiting for user input) and disabled before code continues. After each enabled/disabled state change the GUI should be updated.

One problem was that the user sees "Continue" button (enabled) but can't click it due to functions running. If the installer goes idle (waiting for user input) the button has changed to "Install" (INSTALLFILES page). So the user wants to click on "Continue" but in fact could accidently click on "Install". I think "Continue" should be disabled after clicking (with screen refresh) BEFORE running code. So the user can see that he already clicked and the installer got this event.

I couldn't reproduce this 100% using the Sleep function. But some aspects are here, too:

Outfile "text.exe"

!include "MUI.nsh"

!insertmacro MUI_PAGE_WELCOME

!define MUI_PAGE_CUSTOMFUNCTION_PRE Pre
!insertmacro MUI_PAGE_WELCOME

!define MUI_PAGE_CUSTOMFUNCTION_LEAVE Leave
!define MUI_PAGE_CUSTOMFUNCTION_SHOW Show
!insertmacro MUI_PAGE_LICENSE "test.nsi"

!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH

!insertmacro MUI_LANGUAGE "English"

Section bla
SectionEnd

Function Pre
Sleep 2000
Abort
FunctionEnd

Function Show
Sleep 2000
FunctionEnd

Function Leave
Sleep 2000
FunctionEnd


Button states are changed before the pre function is called. They cannot be changed after it, because that won't work for custom pages. However, that's not before it goes idle and waits for user input. Until a page is shown, no user input is processed. The pre function, page creation and show function are all invoked while processing the same message (WM_NOTIFY_OUTER_NEXT). The user can't really click a button while the page is being replaced, only see the button.

As I understand, you're talking about a situation where the pre function takes a while to execute. That shouldn't happen. As this function is called while processing a message, it shouldn't do lengthy operations.

It's possible that I didn't understand exactly what you've meant. If you have clarifications, or suggestions how to confuse the user less, I'd like to hear them.


I build a script to reproduce the same behaviour what I get with my real world installer. The Sleep-commands simulate some processing I do in Pre/Leave. Of course there aren't any Sleep's in the real code but executing that code can result in a similar delay.

Issue 1: Next button changes BEFORE the next screen is displayed. :-(

Issue 2: The button is active but the next screen is INSTFILES so the button gets deactivated. The user can see a active button for some time. :-(

The combination of these two issues is very bad because the button changes, remains active (but isn't clickable) and then changes again (e.g. gets disabled). If the button does not change in text it is bad, too, because the user may think he didn't hit the button and tries again. If the new screen gets visible in the meantime the user may click on the button of the next screen but wanted to click again on the button of the previous screen.

Suggestions:
1. Why not disable the (all?) buttons after they got clicked ?

2. Why is the button relabeled before the screen gets refreshed? Ok, could be some order problem, but couldn't customization be done in Show function?


Outfile "test.exe"

!include "MUI.nsh"

!insertmacro MUI_PAGE_LICENSE "test.nsi"

!define MUI_PAGE_CUSTOMFUNCTION_PRE Pre
!insertmacro MUI_PAGE_COMPONENTS

!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH

!insertmacro MUI_LANGUAGE "English"

Section bla
DetailPrint "installing 1..."
Sleep 100
DetailPrint "installing 2..."
Sleep 100
DetailPrint "installing 3..."
Sleep 100
DetailPrint "installing 4..."
Sleep 100
DetailPrint "installing 5..."
Sleep 100
DetailPrint "installing 6..."
Sleep 100
DetailPrint "installing 7..."
Sleep 100
DetailPrint "installing 8..."
Sleep 100
DetailPrint "installing 9..."
Sleep 100
DetailPrint "ready."
Sleep 500
SectionEnd

Function Pre
Sleep 1000
Abort
FunctionEnd

You're not supposed to perform lengthy operations in the page callback functions because it delays the UI. The buttons change text and enabled status before the pre function because that's where custom pages are created. Buttons are not disabled when clicked because, as they are instantly enabled again, that causes a flicker.

It seems all of the problems you're talking about are caused by lengthy operations in the page callback functions. If you want to perform lengthy operations there, you can disable the buttons on your own using EnableWindow.


Ok, I now use EnableWindow function to disable the next button. Not really perfect but somewhat satisfying.

Some other solution could be changing the workflow to run that operation in Leave (may be better than Pre) and/or to add an additional page. This isn't better for me.

Thank you anyway.


An installer should never ever perform any real processing before the last step expcept gather user data. Only and I mean only when the user clicks Install button, the installer should start the lengthy operations and actually do the install. A user don't want to wait during configuration of the install.


You're right. In fact my code does not need to be executed before Sections. I moved the code from the pre-function to a new section. There was is no user interaction between pre-function and sections anyway, because the page was skipped in case of code execution.

Thanks for the hint.