1

I would like to show a local html file when a user clicks on a help icon. The method shown below is connected to the triggered signal from the icon. In my method shown below, the html file is not being opened in my default browser and the except part of the script is not being activated. I have two questions:

  1. What is the best approach to showing a local html file with PyQt5?

  2. How to make the script throw an exception when a html file is not located?

    def helpScreen(self):
        try:
            urlLink = QUrl.fromLocalFile(':/plugins/geomAttribute/help/index_en.html')
            QDesktopServices.openUrl(urlLink)
        except:
            QMessageBox.warning(None, 'Warning', 'Unable to locate help file')
    
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Philip Whitten
  • 293
  • 2
  • 16

1 Answers1

0

Why is HTML not shown?

The path starts with : which indicates that you are using qresource, the first thing you must do is convert the .rc to .py with the command:

pyrcc your_resource.qrc -o your_resource_rc.py

In my case my qresource is resource.qrc generating the resource_rc.py file so you must import it into the .py.

The qresource paths are virtual, they do not exist in the hard disk so when wanting to use that file the browser will not find it, so the solution is to convert it into a local file, we can save it with a QFile but this file must be temporary so what better is to save it with a QTemporaryFile.

In your case, the code should be the following:

from PyQt5 import QtCore, QtGui, QtWidgets


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        lay = QtWidgets.QVBoxLayout(self)
        button = QtWidgets.QPushButton("Help")
        button.clicked.connect(self.helpScreen)
        lay.addWidget(button)

    def helpScreen(self):
        resource_path = ":/plugins/geomAttribute/help/index_en.html"
        resource_file = QtCore.QFile(resource_path)
        if resource_file.open(QtCore.QIODevice.ReadOnly):
            tmp_file = QtCore.QTemporaryFile(self)
            tmp_file.setFileTemplate("XXXXXX.html")
            if tmp_file.open():
                tmp_file.write(resource_file.readAll())
                resource_file.close()
                tmp_file.flush()
            url = QtCore.QUrl.fromLocalFile(tmp_file.fileName())
            if QtGui.QDesktopServices.openUrl(url):
                return
        QtWidgets.QMessageBox.warning(None, 'Warning', 'Unable to locate help file')


import resource_rc


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

1. What is the best approach to showing a local html file with PyQt5?

There are several ways to display an HTML and the choice of the best depends on you, for example there are the following methods:

  • QDesktopServices::openUrl()
  • QLabel
  • QTextEdit, QPlainTextEdit, etc.
  • QWebEngineView, QWebView, etc.

2. How to make the script throw an exception when a html file is not located?

Qt for efficiency reasons will not throw exceptions, so you do not use try-except in the part of the code that directly depends on Qt, Qt has 2 main mechanisms to notify you that it is wrong, if the task is synchronous the function will return a Boolean that indicates that the task finished correctly or not, and if the error is given asynchronously will issue a signal indicating it, in the case of QDesktopServices::openUrl() is a synchronous task so it will return a boolean indicating if the task was executed successfully:

bool QDesktopServices::openUrl(const QUrl &url)

Opens the given url in the appropriate Web browser for the user's desktop environment, and returns true if successful; otherwise returns false.

[...]

Community
  • 1
  • 1
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • I got this solution to work. It took a few days as I didn't understand where each component was being instantiated. – Philip Whitten Oct 17 '18 at 23:56
  • @PhilipWhitten Many I give a solution using the [mcve] provided by the OP, but if the OP does not provide it or what it provides is not an MCVE I will have to create an MCVE that does not necessarily look like the code that the OP could provide, what if you want help using your code you should provide an MCVE. :-) – eyllanesc Oct 17 '18 at 23:59