Forum Discussion

roquoonewbie's avatar
14 years ago

EnableBackButton does not work unless AddButton is used

I think there is a bug with the roMessageDialog object. Specifically, I cannot get the back button event unless I also add a button to the dialog.

I do not want to have any button on the dialog, but I do want the user to be able to press back to quit the dialog. However, in the below code, the only way I can get the event is if I include a dummy button. Can anyone confirm they see the same? Can Roku confirm this is a bug?


Function testBackButton() As Void

port = CreateObject("roMessagePort")
dialog = CreateObject("roMessageDialog")
dialog.SetMessagePort(port)
dialog.SetText("Testing Back Button")
dialog.EnableBackButton(true)
dialog.AddButton(1, "Go Back") 'This line must be present otherwise back button event never occurs
dialog.Show()

while true
dlgMsg = wait(0, port)
if type(dlgMsg) = "roMessageDialogEvent"
Dbg("EVENT RECEIVED") 'Never gets executed unless AddButton is included above
if dlgMsg.isScreenClosed() or dlgMsg.isButtonPressed()
exit while
end if
end if
end while

End Function

19 Replies

  • So you are saying there is no way at all in a Roku channel to present a "Please wait" message which gives the user an option of canceling the operation they are currently waiting for?

    The operation could be as simple as one HTTP request which may take a long time (if the network is slow, for instance). It's the equivalent of canceling a browser navigation to a new page after it takes longer than the user would like to wait.

    It seems hard to believe that Roku devs did not provide some way to listen for a user-driven event and completely (and instantly) close out of a screen when that event arrives.
  • I don't think that's what he's saying at all. You just have to get a little creative. This is how I'd do it...

    WARNING: psuedo-code

    ' Create message port that everything will use
    messagePort = CreateObject("roMessagePort")

    ' Create url transfer for first URL
    download1 = CreateObject("roUrlTransfer")
    download1.SetPort(messagePort)
    download1.SetUrl(url1)

    Create url transfer for second URL
    download2 = CreateObject("roUrlTransfer")
    download2.SetPort(messagePort)
    download2.SetUrl(url2)

    ' Create and show wait dialog
    waitDialog = CreateObject("roMessageDialog")
    waitDialog.SetMessagePort(messagePort)
    ' Add your waitDialog button(s)
    ' Show waitDialog
    waitDialog.Show()

    ' Start downloads
    download1.AsyncGetToString()
    download2.AsyncGetToString()

    ' Listen for message
    While True
    msg = wait(10, messagePort)
    If msg <> invalid Then
    If Type(msg) = "roUrlEvent" Then
    ' Got a URL event, figure out which download it's for and process it
    If msg.GetSourceIdentity() = download1.GetIdentity() Then
    download1Result = msg.GetString()
    ' Do download1 processing
    Else If msg.GetSourceIdentity() = download2.GetIdentity() Then
    download2Result = msg.GetString()
    ' Do download2 processing
    End If
    Else If Type(msg) = "roMessageDialogEvent") Then
    ' Got a message dialog event, probably cancel
    If msg.IsButtonPressed() Then
    If msg.GetIndex() = cancelButton Then
    ' Kill the active downloads, and close the wait dialog
    download1.AsyncCancel()
    download2.AsyncCancel()
    waitDialog.Close()
    Exit While
    End If
    End If
    End If
    End If
    End While
  • Thank you both very much. I was able to use your proposed method such that I can now give the user the ability to cancel the async HTTP request by pressing back or clicking on a dialog "cancel" button (thought it is still a mystery why the back button will not fire an event unless there is also a dialog button).

    However, as best as I can tell, your proposed method will only work for Async HTTP calls, correct?

    In other words, if I have a function that "does a lot of stuff" which takes a while (but not necessarily makes HTTP calls), is there a way to set it up to run asyncronously (like the built in AsyncGetToString() method), so that I can cancel it via something similar to the HTTP AsyncCancel() ?

    Is it possible to define our own Async functions? Or are we relegated to the few Async functions that are provided by the Roku API?
  • "roquoonewbie" wrote:

    In other words, if I have a function that "does a lot of stuff" which takes a while (but not necessarily makes HTTP calls), is there a way to set it up to run asyncronously (like the built in AsyncGetToString() method), so that I can cancel it via something similar to the HTTP AsyncCancel() ?

    Is it possible to define our own Async functions? Or are we relegated to the few Async functions that are provided by the Roku API?

    Brightscript is not multi-threaded at the moment, except in a few instances where there are Async functions, which allow you to initiate an action, and then perform other actions while waiting for that first action to complete. You are not able to define your own Async functions at the present time.

    - Joel
  • Thank you for the information, Joel. So, just to confirm my understanding 100%, is there currently no way at all in Brightscript to present a "waiting" dialog message to users while waiting for time-intensive logic to complete, and give the user an option to cancel (or go back) such that the logic which was running is cancelled/aborted? No way at all?

    Also, can you comment on why the EnableBackButton property does not work unless AddButton is also used? Is that intended or is it a bug?
  • I haven't tested that myself, but if it is behaving as described, it might be considered a bug.

    There is no reason why, within any logic I can imagine, you cannot simply check a message port every so often to see if a button has been pressed, and if you are using multiple functions within your logic, then pass the port and dialog box variables from function to function so that it is available in each function. Then if a button has been pressed, you return from wherever you are to the calling function. You may need to use a return value to notify the calling functions that you are aborting your logic.

    You could also use global variables to make your dialog and port available everywhere, instead of the more tedious parameter passing.

    - Joel
  • I thought Brightscript did not support global variables?

    From the Brightscript reference manual:

    "BrightScript does not support global variables. Except, there is one hard-coded global variable "global" that is an interface to the global BrightScript Component. The global component contains all global library functions."

    Also, how exactly do you check a message port for the last message? Is a "wait()" required? In other words, would this simply return the last message which the port received, or is there a better way?

    dlgMsg = wait(1, port)
  • you would use the m variable to create your port and dialog:

    m.port=createobject("romessageport")
    m.dialog=CreateObject("roMessageDialog")

    "roquoonewbie" wrote:

    Also, how exactly do you check a message port for the last message? Is a "wait()" required? In other words, would this simply return the last message which the port received, or is there a better way?

    There is a way to do it without using wait:

    msg = port.GetMessage()
    if type(msg) = "roUniversalControlEvent" then
    <act on message>
    end if


    but wait is a pretty simple way to go. I would use the above method for a game that has high performance demands on your device, otherwise, msg=wait(25,port) would be my suggestion.

    - Joel
  • Thanks to all of you. Passing the handle to the dialog port down into the time intensive function, and querying the last message posted to it on each loop inside that function worked perfectly.

    All it took was this:


    msg = dialogport.GetMessage()
    if type(msg) = "roMessageDialogEvent" then
    if msg.IsButtonPressed() or msg.isScreenClosed() then
    return 3
    end if
    end if



    The simplest solutions are always the best ones. I had no idea you could poll the port for it's latest message (as opposed to listening to events from it).

    Thanks again!