1. Daniel Vivier
  2. PowerBuilder
  3. Thursday, 22 October 2020 17:36 PM UTC

I'm considering testing the new WebBrowser control to see whether it can be used to invisibly load HTML files then save them as PDF. The idea would be to load the HTML into an invisible WebBrowser with Navigate(), then when that is complete, print them with PrintAsPDF().

The only problem is it doesn't seem at all clear from the documentation how you know when the navigation is completed, so that the PrintAsPDF can be done. (There's a very clear event to know when the PDF is done, PDFPrintFinished.)

Help, please? Also, if anyone has done this and can tell us how successful it was, that would be great!


Daniel Vivier Accepted Answer Pending Moderation
  1. Thursday, 21 April 2022 20:55 PM UTC
  2. PowerBuilder
  3. # 1

OK I have come back to this and found a solution that is a bit complex but seems to be really reliable, and follows standards to at least some extent.

Window instance variables:

Boolean ib_navigate_called // have we called navigate on the source file?
Boolean ib_navigate_started // has it really started navigating, after we called it?

Script to start navigation:

ib_navigate_called = FALSE
ib_navigate_started = FALSE

if wb_1.navigate(as_source) <> 1 then
    // give error message
end if

ib_navigate_called = TRUE // indicate we have tried to start navigating

WebBrowser control NavigationStart event:

// We need to know it has really started navigating before we try to determine whether it has finished
if ib_navigate_called then ib_navigate_started = TRUE

WebBrowser control NavigationProgressIndex event:

// Navigation has been started. If it indicates 100 percent finished, check the document.readyState.
// If that is "complete", print the PDF file.

string lsRet

if NOT ib_navigate_started then return

if progressindex < 100 then return

EvaluateJavaScriptSync("document.readyState", REF lsRet)
if Pos(lsRet, '"complete"') = 0 then
end if
ib_navigate_started = FALSE // prevent recursion & thus doing any following steps twice

// now do whatever you need to do, it should be fully loaded!


  1. Miguel Leeuwe
  2. Friday, 22 April 2022 05:16 AM UTC
Thanks for sharing Dan, this is awesome!

  1. Helpful
There are no comments made yet.
Uri Netanel Accepted Answer Pending Moderation
  1. Thursday, 8 July 2021 12:22 PM UTC
  2. PowerBuilder
  3. # 2

Having read Dan's question and all responses and seeing that the page itself's load event has been mentioned several times I would like to share my code to test if it has been fully loaded:

function boolean uf_is_page_loaded()
//iwb is a reference to the current webbrowser

string ls_script, ls_result 

ib_processing = true
ls_script = '(function(){return (document.readyState === "complete");})();'

if iwb.evaluatejavascriptSync(ls_script, ls_result) = 1 then
ls_result = uf_get_parsed_json(ls_result)
if ls_result = "true" then
return true
end if
end if

return false


function string uf_get_parsed_json(string as_json_value)

string ls_result
JsonParser lnv_JsonParser
Long ll_RootObject

lnv_JsonParser = Create JsonParser
ll_RootObject = lnv_JsonParser.GetRootItem()
ls_result = lnv_JsonParser.GetItemString(ll_RootObject, "value")
destroy lnv_JsonParser

return ls_result


I wasn't aware of the navigationprogressindex event. Is checking it effectively the same as my uf_is_page_loaded and which is prefferable?

  1. Miguel Leeuwe
  2. Sunday, 11 July 2021 04:52 AM UTC
Thanks for sharing. I'm not much of a JS expert, so I cannot tell if effectively it's the same as using the navigationprogressindex. All I know is that that event is fired multiple times with a value of 100 %, so it's not a reliable way of checking if the page has been fully loaded or not.


(I'll definitely try out your method !)
  1. Helpful
  1. Daniel Vivier
  2. Friday, 22 April 2022 12:05 PM UTC
I just want to add a comment about the script used above, in the line:

ls_script = '(function(){return (document.readyState === "complete");})();'

I think defining a function and calling it (with the parentheses at the end) is suggested by at least one example in the PB help, but there is absolutely no reason for that. The following simpler script line will give the exact same result:

ls_script = 'document.readyState === "complete"'

That will return JSON that includes "true" or "false". Or, to keep it even simpler, just use the following:

ls_script = 'document.readyState'

Then test whether the JSON returned includes "complete".
  1. Helpful 1
  1. Miguel Leeuwe
  2. Friday, 22 April 2022 13:01 PM UTC
Thanks again!
  1. Helpful
There are no comments made yet.
Kai Zhao @Appeon Accepted Answer Pending Moderation
  1. Friday, 23 October 2020 01:56 AM UTC
  2. PowerBuilder
  3. # 3

Hi Dan,

For the navigation completed issue, CEF doesn’t provide a conventional interface to load the page completely. So technically it is not supported.

Please use the navigationprogressindex event to determine the page loading process, you can consider it is complete when it returns 100.

For the GetSource issue, we will record it (GetSource() returns the text of all frames) as a requirement in our CR pool, I will get back to you once we have a plan to support this feature.


There are no comments made yet.
Miguel Leeuwe Accepted Answer Pending Moderation
  1. Friday, 23 October 2020 01:17 AM UTC
  2. PowerBuilder
  3. # 4

I've tried to use the "downloadstatuschanged" event to know whether a pdf has fully downloaded and ... there's a bug: The event is fired multiple times with the parameter "percent" having a value of "100".
I've reported it as a (private) bug yesterday and Appeon is going to deal with it.

That makes the webbrowser control unfit for use for what we want to do with it. I'll just wait.

  1. Miguel Leeuwe
  2. Friday, 23 October 2020 01:23 AM UTC
To be fully clear: This is a different event than the one for loading a page itself. DownloadStatusChanged is the event we check after having clicked on a link to a pdf file. The problem exists also in the beta, not only in R2.

  1. Helpful
There are no comments made yet.
Brad Wery Accepted Answer Pending Moderation
  1. Friday, 23 October 2020 00:00 AM UTC
  2. PowerBuilder
  3. # 5

When developing a test browser using the new browser control (https://powertothebuilder.blogspot.com/2020/08/develop-web-browser-in-powerbuilder.html), I found that the NavigationStateChanged event was the best event to use. I display a spinning circle in the tab when the page is loading. In the NavigationStateChanged event, I turn the spinner off. Seems to work well.

I hope that helps.

  1. Daniel Vivier
  2. Friday, 23 October 2020 00:12 AM UTC
Are you saying the first time that fired, the navigation was completed?
  1. Helpful
  1. Brad Wery
  2. Friday, 23 October 2020 00:48 AM UTC
Seems to be the case. Maybe the first occurence after the NavigationStart event? I would need to double check to be sure. The spinner works though so I think it's the right event.
  1. Helpful
There are no comments made yet.
Daniel Vivier Accepted Answer Pending Moderation
  1. Thursday, 22 October 2020 21:08 PM UTC
  2. PowerBuilder
  3. # 6

Having stared at the WebBrowser docs some more I'm really concerned that there may currently be no solution to this.

With the Microsoft WebBrowser control that we already use (as an HTML editor in DesignMode, as well as for viewing mail-merge results), we use the DocumentComplete event (which the WebBrowser docs say it doesn't have an equivalent for) to determine whether a navigation is completed. Within that event script, we also check the Busy and ReadyState properties (which again the WebBrowser docs say it has no equivalents for).

I don't suppose the Other event might help, to catch some Chromium event that PowerBuilder's control isn't explicitly providing an interface to?

I see that there's a GetSource() method, which I suppose you could use to see whether the entire source has been loaded (if you had also read the HTML some other way, and could compare that to the results of GetSource()), but that wouldn't tell you for instance whether any images had been loaded. And for pages with frames, GetSource() returns only the text of the main frame.

There are no comments made yet.
  • Page :
  • 1

There are no replies made for this question yet.
However, you are not allowed to reply to this question.