How can I get the maximum and current value of the verticalScrollBar when displaying html with QWebEngineView

强颜欢笑 提交于 2019-12-24 11:50:01

问题


I'm attempting to create a UI in Maya (Python 2.7.11 and Maya Qt 5.6.1. and PySide2) where the OK button is grayed out until the user scrolls to the bottom. I can do this easily with QTextEdit by grabbing the value and maximum from the verticalScrollBar but I can't seem to find similar objects in QWebEngineView or QWebEnginePage. Any Ideas?


回答1:


In the case you want to get some information from the DOM you have to do it with javascript, in this case we will create an object that will have the required information and export it to the HTML so that each time the scroll status changes it will be updated.

from PySide2 import QtCore, QtWidgets, QtWebEngineWidgets, QtWebChannel
from jinja2 import Template

class Element(QtCore.QObject):
    def __init__(self, name, parent=None):
        super(Element, self).__init__(parent)
        self._name = name

    @property
    def name(self):
        return self._name

    def script(self):
        return ''

class YScrollBarListener(Element):
    valueChanged = QtCore.Signal(int)
    maximumChanged = QtCore.Signal(int)

    def __init__(self, name, parent=None):
        super(YScrollBarListener, self).__init__(name, parent)
        self._value = -1
        self._maximum = -1

    @QtCore.Property(int, notify=valueChanged)
    def value(self):
        return self._value

    @QtCore.Property(int, notify=maximumChanged)
    def maximum(self):
        return self._maximum

    def script(self):
        _script = '''
        window.addEventListener("scroll", function(event){
            {{name}}.update_value(this.scrollY);
            // https://stackoverflow.com/a/43571388/6622587
            var scrollMaxY = window.scrollMaxY || (document.documentElement.scrollHeight - document.documentElement.clientHeight)
            {{name}}.update_maximum(scrollMaxY)
        });
        '''
        return Template(_script).render(name=self.name)

    @QtCore.Slot(int)
    def update_value(self, value):
        if self._value != value:
            self._value = value
            self.valueChanged.emit(value)

    @QtCore.Slot(int)
    def update_maximum(self, maximum):
        if self._maximum != maximum:
            self._maximum = maximum
            self.maximumChanged.emit(maximum)

class WebEnginePage(QtWebEngineWidgets.QWebEnginePage):
    def __init__(self, *args, **kwargs):
        super(WebEnginePage, self).__init__(*args, **kwargs)
        self.loadFinished.connect(self.onLoadFinished)
        self._objects = []

    def add_object(self, obj):
        self._objects.append(obj)

    @QtCore.Slot(bool)
    def onLoadFinished(self, ok):
        print("Finished loading: ", ok)
        if ok:
            self.load_qwebchannel()
            self.add_objects()

    def load_qwebchannel(self):
        file = QtCore.QFile(":/qtwebchannel/qwebchannel.js")
        if file.open(QtCore.QIODevice.ReadOnly):
            content = file.readAll()
            file.close()
            self.runJavaScript(content.data().decode())
        if self.webChannel() is None:
            channel = QtWebChannel.QWebChannel(self)
            self.setWebChannel(channel)

    def add_objects(self):
        if self.webChannel() is not None:
            objects = {obj.name : obj for obj in self._objects}
            self.webChannel().registerObjects(objects)
            _script = '''
            {% for obj in objects %}
            var {{obj}};
            {% endfor %}
            new QWebChannel(qt.webChannelTransport, function (channel) {
            {% for obj in objects %}
                {{obj}} = channel.objects.{{obj}};
            {% endfor %}
            }); 
            '''
            self.runJavaScript(Template(_script).render(objects=objects.keys()))
            for obj in self._objects:
                if isinstance(obj, Element):
                    self.runJavaScript(obj.script())

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)

        self._scrollbar_listener = YScrollBarListener("y_scrollbar_listener", self)
        self._scrollbar_listener.valueChanged.connect(self.on_y_value_changed)
        view = QtWebEngineWidgets.QWebEngineView()
        page = WebEnginePage(view)
        page.add_object(self._scrollbar_listener)
        view.setPage(page)

        view.load(QtCore.QUrl("https://stackoverflow.com/questions/43282899"))

        self._button = QtWidgets.QPushButton("button")
        progressbar = QtWidgets.QProgressBar(maximum=100)
        view.loadProgress.connect(progressbar.setValue)

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(view)
        lay.addWidget(self._button)
        lay.addWidget(progressbar)

        self.resize(640, 480)

    def on_y_value_changed(self, value):
        self._button.setEnabled(self._scrollbar_listener.maximum != value)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle('fusion')
    app.setStyleSheet('''
    QPushButton
    {
        background-color: #2E8B57;
    }
    QPushButton:disabled
    {
        background-color: #FFFAFA;
    }
    ''')
    w = Widget()
    w.show()
    sys.exit(app.exec_())


来源:https://stackoverflow.com/questions/55290759/how-can-i-get-the-maximum-and-current-value-of-the-verticalscrollbar-when-displa

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!