QWebEnginePage API for callbacks

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

QWebEnginePage API for callbacks

David Cortesi
In Qt5.4, the new QWebEngine interface takes account of the fact that the underlying Chromium engine is asynchronous. Four of the methods of QWebEnginePage take an argument "FunctorOrLambda" as a callback to receive control when the result is ready (for example, [1]).

Using PyQt, I assume we can pass a Python defined function or lambda in this position?

I'm a bit at a loss what to do following a call to such a method. What is the best way to "idle" until the callback comes? n.b. I don't see any WebEngine specific guidance at the PyQt5 doc [2].

Thanks for any suggestions,
Dave Cortesi

_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: QWebEnginePage API for callbacks

Andreas Pakulat
Hi David,

On Mon, Jan 5, 2015 at 11:06 PM, David Cortesi <[hidden email]> wrote:
In Qt5.4, the new QWebEngine interface takes account of the fact that the underlying Chromium engine is asynchronous. Four of the methods of QWebEnginePage take an argument "FunctorOrLambda" as a callback to receive control when the result is ready (for example, [1]).

Using PyQt, I assume we can pass a Python defined function or lambda in this position?

I'm a bit at a loss what to do following a call to such a method. What is the best way to "idle" until the callback comes? n.b. I don't see any WebEngine specific guidance at the PyQt5 doc [2].

I'd say just as all other callbacks in Qt (i.e. signal/slots), return control to the qt event loop.

Andreas 

_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: QWebEnginePage API for callbacks

David Cortesi


On Mon, Jan 5, 2015 at 3:26 PM, Andreas Pakulat <[hidden email]> wrote:

I'm a bit at a loss what to do following a call to such a method. What is the best way to "idle" until the callback comes? n.b. I don't see any WebEngine specific guidance at the PyQt5 doc [2].

I'd say just as all other callbacks in Qt (i.e. signal/slots), return control to the qt event loop.

Could you clarify a bit? The doc [1] for QWebEnginePage.toPlainText() will at some unknown future time call my callback passing the text of the page. But I would make that call in some code that needs that text -- to write it to a file, say. So in a custom class based on QWebEngineView, I capture the ^S key, perhaps, for Save. I put a findSaveDialog and get a path string and open a text stream for output. Then...

    self.page().toPlainText( lambda s : self.save_plain_text = s )
    # Here --  twiddle my thumbs until I can...
    output_stream << self.save_plain_text

Is this the kind of thing you have in mind?

    self.save_plain_text = None
    self.page().toPlainText( lambda s : self.save_plain_text = s )
    while self.save_plain_text is None : QCoreApplication.processEvents()
    output_stream << self.save_plain_text



_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: QWebEnginePage API for callbacks

Florian Bruhin
* David Cortesi <[hidden email]> [2015-01-05 19:59:13 -0800]:

> On Mon, Jan 5, 2015 at 3:26 PM, Andreas Pakulat <[hidden email]> wrote:
>
> >
> > I'm a bit at a loss what to do following a call to such a method. What is
> >> the best way to "idle" until the callback comes? n.b. I don't see any
> >> WebEngine specific guidance at the PyQt5 doc [2].
> >>
> >
> > I'd say just as all other callbacks in Qt (i.e. signal/slots), return
> > control to the qt event loop.
> >
>
> Could you clarify a bit? The doc [1] for QWebEnginePage.toPlainText() will
> at some unknown future time call my callback passing the text of the page.
> But I would make that call in some code that needs that text -- to write it
> to a file, say. So in a custom class based on QWebEngineView, I capture the
> ^S key, perhaps, for Save. I put a findSaveDialog and get a path string and
> open a text stream for output. Then...
>
>     self.page().toPlainText( lambda s : self.save_plain_text = s )
>     # Here --  twiddle my thumbs until I can...
>     output_stream << self.save_plain_text
>
> Is this the kind of thing you have in mind?
>
>     self.save_plain_text = None
>     self.page().toPlainText( lambda s : self.save_plain_text = s )
>     while self.save_plain_text is None : QCoreApplication.processEvents()
>     output_stream << self.save_plain_text
Probably something like this:

    def handle_ctrl_s(self):
        self.save_filename = get_filename_from_user()
        self.page().toPlainText(self.do_save)

    def do_save(self, data):
        with open(self.save_filename, 'w') as f:
            f.write(data)

Or this using functools.partial, i.e. it won't break if the user
presses Ctrl-S again before the text is ready:

    def handle_ctrl_s(self):
        filename = get_filename_from_user()
        self.page().toPlainText(partial(self.do_save, filename))

    def do_save(self, filename, data):
        with open(filename, 'w') as f:
            f.write(data)

I think this is a general concept which is very important to grasp
(and also took me a while) when programming with something like PyQt:

Try to make everything happen async - the majority of the time should
be spent in the Qt event loop (i.e. the app.exec_() call). Any code
you write gets called from that event loop usually, and should finish
"immediately". So here, you don't "wait" until the data is ready, you
tell Qt "call me back when the data is ready", return to the event
loop, and *then* save it when it *is* ready.

Florian

--
http://www.the-compiler.org | [hidden email] (Mail/XMPP)
   GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc
         I love long mails! | http://email.is-not-s.ms/

_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt

attachment0 (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: QWebEnginePage API for callbacks

Kevin Mcintyre
I too am curious, my software uses QWebElement extensively, and was a little surprised how page visibility there is available.

On Mon, Jan 5, 2015 at 8:27 PM, Florian Bruhin <[hidden email]> wrote:
* David Cortesi <[hidden email]> [2015-01-05 19:59:13 -0800]:
> On Mon, Jan 5, 2015 at 3:26 PM, Andreas Pakulat <[hidden email]> wrote:
>
> >
> > I'm a bit at a loss what to do following a call to such a method. What is
> >> the best way to "idle" until the callback comes? n.b. I don't see any
> >> WebEngine specific guidance at the PyQt5 doc [2].
> >>
> >
> > I'd say just as all other callbacks in Qt (i.e. signal/slots), return
> > control to the qt event loop.
> >
>
> Could you clarify a bit? The doc [1] for QWebEnginePage.toPlainText() will
> at some unknown future time call my callback passing the text of the page.
> But I would make that call in some code that needs that text -- to write it
> to a file, say. So in a custom class based on QWebEngineView, I capture the
> ^S key, perhaps, for Save. I put a findSaveDialog and get a path string and
> open a text stream for output. Then...
>
>     self.page().toPlainText( lambda s : self.save_plain_text = s )
>     # Here --  twiddle my thumbs until I can...
>     output_stream << self.save_plain_text
>
> Is this the kind of thing you have in mind?
>
>     self.save_plain_text = None
>     self.page().toPlainText( lambda s : self.save_plain_text = s )
>     while self.save_plain_text is None : QCoreApplication.processEvents()
>     output_stream << self.save_plain_text

Probably something like this:

    def handle_ctrl_s(self):
        self.save_filename = get_filename_from_user()
        self.page().toPlainText(self.do_save)

    def do_save(self, data):
        with open(self.save_filename, 'w') as f:
            f.write(data)

Or this using functools.partial, i.e. it won't break if the user
presses Ctrl-S again before the text is ready:

    def handle_ctrl_s(self):
        filename = get_filename_from_user()
        self.page().toPlainText(partial(self.do_save, filename))

    def do_save(self, filename, data):
        with open(filename, 'w') as f:
            f.write(data)

I think this is a general concept which is very important to grasp
(and also took me a while) when programming with something like PyQt:

Try to make everything happen async - the majority of the time should
be spent in the Qt event loop (i.e. the app.exec_() call). Any code
you write gets called from that event loop usually, and should finish
"immediately". So here, you don't "wait" until the data is ready, you
tell Qt "call me back when the data is ready", return to the event
loop, and *then* save it when it *is* ready.

Florian

--
http://www.the-compiler.org | [hidden email] (Mail/XMPP)
   GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc
         I love long mails! | http://email.is-not-s.ms/

_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt


_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: QWebEnginePage API for callbacks

Kovid Goyal
In reply to this post by David Cortesi
There is no direct way to convert an asynchronous API into a synchronous
one.

Here is a hackish way to do it.

def save(self):
  text = None
  def finished(x):
    text = x
     
  self.view.toPlainText(finished)
  while text is None:
      QApplication.instance().processEvents(QEventLoop.ExcludeUserInputEvents | QEventLoop.ExcludeSocketNotifiers | QEventLoop.WaitForMoreEvents)
  # now save the text

This is the simplest (somewhat robust) way to simulate the old blocking
behavior of toPlainText(). There are some problems with this
approach:

Spinning the event loop means that other parts of your code might be
called, for instance in response to timer events, or events from the OS.
With the old synchronous API that could not happen.

However, for most use cases it will work fine.

What is really needed is for Qt to provide a synchronous wrapper around
the API that avoids these problems. In other words a flag to
processEvents that causes it to only deliver webkit related events and
hold everything else. That would make porting to
QWebEngine somewhat easier.

Kovid.

On Mon, Jan 05, 2015 at 02:06:25PM -0800, David Cortesi wrote:

> In Qt5.4, the new QWebEngine interface takes account of the fact that the
> underlying Chromium engine is asynchronous. Four of the methods of
> QWebEnginePage take an argument "FunctorOrLambda" as a callback to receive
> control when the result is ready (for example, [1]).
>
> Using PyQt, I assume we can pass a Python defined function or lambda in
> this position?
>
> I'm a bit at a loss what to do following a call to such a method. What is
> the best way to "idle" until the callback comes? n.b. I don't see any
> WebEngine specific guidance at the PyQt5 doc [2].
>
> Thanks for any suggestions,
> Dave Cortesi
>
> [1] http://doc.qt.io/qt-5/qwebenginepage.html#toPlainText
>
> [2] http://pyqt.sourceforge.net/Docs/PyQt5/pyqt4_differences.html
>
>
> !DSPAM:3,54ab105d17503335820283!

> _______________________________________________
> PyQt mailing list    [hidden email]
> http://www.riverbankcomputing.com/mailman/listinfo/pyqt
>
> !DSPAM:3,54ab105d17503335820283!


--
_____________________________________

Dr. Kovid Goyal
http://www.kovidgoyal.net
http://calibre-ebook.com
_____________________________________
_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: QWebEnginePage API for callbacks

Florian Bruhin
In reply to this post by Kevin Mcintyre
* Kevin Mcintyre <[hidden email]> [2015-01-05 21:44:41 -0800]:
> I too am curious, my software uses QWebElement extensively, and was a
> little surprised how page visibility there is available.

What do you mean with "page visibility" exactly?

I opened an issue for a QWebElement-like API here:
https://bugreports.qt-project.org/browse/QTBUG-42302

Depending on what you want to do, it might be possible using a small
javascript snippet instead:

http://doc-snapshot.qt-project.org/qt5-5.4/qwebenginepage.html#runJavaScript

Florian

--
http://www.the-compiler.org | [hidden email] (Mail/XMPP)
   GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc
         I love long mails! | http://email.is-not-s.ms/

_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt

attachment0 (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: QWebEnginePage API for callbacks

Florian Bruhin
In reply to this post by Kovid Goyal
* Kovid Goyal <[hidden email]> [2015-01-06 11:56:11 +0530]:
> What is really needed is for Qt to provide a synchronous wrapper around
> the API that avoids these problems. In other words a flag to
> processEvents that causes it to only deliver webkit related events and
> hold everything else. That would make porting to
> QWebEngine somewhat easier.

That is a good idea - has this ever been brought up with the
QtWebEngine developers, i.e. via their mailinglist[1] or an issue in
the tracker[2]?

[1] http://lists.qt-project.org/mailman/listinfo/qtwebengine
[2] https://bugreports.qt-project.org/secure/Dashboard.jspa

Florian

--
http://www.the-compiler.org | [hidden email] (Mail/XMPP)
   GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc
         I love long mails! | http://email.is-not-s.ms/

_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt

attachment0 (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: QWebEnginePage API for callbacks

Kovid Goyal
Not that I am aware of, feel free to suggest it.

Kovid.

On Tue, Jan 06, 2015 at 08:03:51AM +0100, Florian Bruhin wrote:

> * Kovid Goyal <[hidden email]> [2015-01-06 11:56:11 +0530]:
> > What is really needed is for Qt to provide a synchronous wrapper around
> > the API that avoids these problems. In other words a flag to
> > processEvents that causes it to only deliver webkit related events and
> > hold everything else. That would make porting to
> > QWebEngine somewhat easier.
>
> That is a good idea - has this ever been brought up with the
> QtWebEngine developers, i.e. via their mailinglist[1] or an issue in
> the tracker[2]?
>
> [1] http://lists.qt-project.org/mailman/listinfo/qtwebengine
> [2] https://bugreports.qt-project.org/secure/Dashboard.jspa
>
> Florian
>
> --
> http://www.the-compiler.org | [hidden email] (Mail/XMPP)
>    GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc
>          I love long mails! | http://email.is-not-s.ms/



> _______________________________________________
> PyQt mailing list    [hidden email]
> http://www.riverbankcomputing.com/mailman/listinfo/pyqt


--
_____________________________________

Dr. Kovid Goyal
http://www.kovidgoyal.net
http://calibre-ebook.com
_____________________________________
_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Reply | Threaded
Open this post in threaded view
|

Re: QWebEnginePage API for callbacks

Kevin Mcintyre
page visibility ... yeah that's not very clear ... I meant methods like mainFrame QWebFrame and other methods for gaining access to content within the page.

I'm aware the snippets of javascript will suffice for retrieving elements.  I've just been trying to understand how I'll work with these objects.

Another example would be QTest.qWait -- what will this do in QWebEngine?  Nothing I suppose.

On Mon, Jan 5, 2015 at 11:18 PM, Kovid Goyal <[hidden email]> wrote:
Not that I am aware of, feel free to suggest it.

Kovid.

On Tue, Jan 06, 2015 at 08:03:51AM +0100, Florian Bruhin wrote:
> * Kovid Goyal <[hidden email]> [2015-01-06 11:56:11 +0530]:
> > What is really needed is for Qt to provide a synchronous wrapper around
> > the API that avoids these problems. In other words a flag to
> > processEvents that causes it to only deliver webkit related events and
> > hold everything else. That would make porting to
> > QWebEngine somewhat easier.
>
> That is a good idea - has this ever been brought up with the
> QtWebEngine developers, i.e. via their mailinglist[1] or an issue in
> the tracker[2]?
>
> [1] http://lists.qt-project.org/mailman/listinfo/qtwebengine
> [2] https://bugreports.qt-project.org/secure/Dashboard.jspa
>
> Florian
>
> --
> http://www.the-compiler.org | [hidden email] (Mail/XMPP)
>    GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc
>          I love long mails! | http://email.is-not-s.ms/



> _______________________________________________
> PyQt mailing list    [hidden email]
> http://www.riverbankcomputing.com/mailman/listinfo/pyqt


--
_____________________________________

Dr. Kovid Goyal
http://www.kovidgoyal.net
http://calibre-ebook.com
_____________________________________
_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt


_______________________________________________
PyQt mailing list    [hidden email]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt