pythonhyperlinkpyqt5qtextbrowser

Open external file-path links with spaces in QTextBrowser


I'm working in a Python App. In some parts of the program I inform the user that different files are created. I show this information in a QTextBrowser widget. I want that this text is hyperlinked, so if the user clicks on the hyperlink, the file opens in an external application. If the path of file has no blank spaces, the links work - but if the path has blank spaces the links don't work.

I read a lot of questions about this, but I don't find a solution.

I wrote these two tests.

Code 1 - I use QLabel and the link works perfectly, but in QTextBrowser it opens inside the browser.

Option 1 works, but the rest of the options don't work because the path has blank spaces.

Option 7 and 10, open the file but inside the browser.

CODE 1:

import sys

from PyQt5.QtWidgets import QApplication, QTextBrowser,QTextEdit,QLabel
from PyQt5.QtCore import QUrl

app = QApplication(sys.argv)
label=QLabel()
file_2='c:/temp/test 2/test.docx'
urlLink="<a href='file:///%s'>'Option_12'</a>"%(file_2)
label.setText(urlLink)
label.setOpenExternalLinks(True)
label.show()
sys.exit(app.exec_())

CODE 2:

import sys

from PyQt5.QtWidgets import QApplication, QTextBrowser,QTextEdit
from PyQt5.QtCore import QUrl

if __name__ == '__main__':
    app = QApplication(sys.argv)
    text_area = QTextBrowser()
    file='c:/temp/test.docx'
    link='<a href='"'{}'"'>Option_1</a>'.format(file)
    text_area.insertHtml(link)
    
    
    file_2='c:/temp/test 2/test.docx'
    link='<br><a href='"'{}'"'>Option_2</a></br>'.format(file_2)
    text_area.insertHtml(link)

    file_2_reformated=file_2.replace(" ", "\\ ")
    link='<br><a href='"'{}'"'>Option_3</a></br>'.format(file_2_reformated)
    text_area.insertHtml(link)

    file_2_reformated=file_2.replace(" ", "%20")
    link='<br><a href='"'{}'"'>Option_4</a></br>'.format(file_2_reformated)
    text_area.insertHtml(link)

    file_2_reformated=chr(34)+file_2+chr(34)
    link='<br><a href='"'{}'"'>Option_5</a></br>'.format(file_2_reformated)
    text_area.insertHtml(link)

    file_2_reformated = " \"" + file_2 + " \""
    link='<br><a href='"'{}'"'>Option_6</a></br>'.format(file_2_reformated)
    text_area.insertHtml(link)

    link='<br><a href='"'file:///{}'"'>Option_7</a></br>'.format(file_2)
    text_area.insertHtml(link)

    link='<br><a href='"'https://{}'"'>Option_8</a></br>'.format(file_2)
    text_area.insertHtml(link)

    file_3="file:///c:/temp/test 2/test.docx"
    link='<br><a href='"'https://{}'"'>Option_9</a></br>'.format(file_3)
    text_area.insertHtml(link)

    file_2='c:/temp/test 2/test.docx'
    link = '<br><a href="{}">Option_10</a></br>'.format(QUrl.fromLocalFile(file_2).toString())
    text_area.insertHtml(link)

    file_2='c:/temp/test 2/test.docx'
    link = '<br><a href="\'{}\'">Option_11</a></br>'.format(QUrl.fromLocalFile(file_2).toString())
    text_area.insertHtml(link)


    from pathlib import PureWindowsPath

    file_3 = PureWindowsPath("c:/temp/test 2/test.docx")
    link = '<br><a href="{}">Option_13</a></br>'.format(file_3.as_uri())
    text_area.insertHtml(link)
    
    text_area.setOpenExternalLinks(True)
    text_area.show()
    sys.exit(app.exec_())
 

SOLUTION BY @ekhumoro

import sys
from PyQt5.QtWidgets import QApplication, QTextBrowser
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtCore import QUrl

if __name__ == '__main__':

    app = QApplication(sys.argv)

    text_area = QTextBrowser()
    text_area.setOpenLinks(False)

    def handle_links(url):
        if not url.scheme():
            url = QUrl.fromLocalFile(url.toString())
        QDesktopServices.openUrl(url)

    text_area.anchorClicked.connect(handle_links)

    file='c:/temp/test.docx'
    link='<a href='"'{}'"'>Option_1</a>'.format(file)
    text_area.insertHtml(link)   

    file_2='c:/temp/test 2/test.docx'    
    link='<br><a href='"'file:///{}'"'>Option_7</a></br>'.format(file_2)
    text_area.insertHtml(link)

    link = '<br><a href="{}">Option_10</a></br>'.format(QUrl.fromLocalFile(file_2).toString())
    text_area.insertHtml(link)

    from pathlib import PureWindowsPath

    file_3 = PureWindowsPath("c:/temp/test 2/test.docx")
    link = '<br><a href="{}">Option_13</a></br>'.format(file_3.as_uri())
    text_area.insertHtml(link)

    text_area.show()
    sys.exit(app.exec_())

Solution

  • The problem is that setOpenExternalLinks(True) will not open urls with a file: scheme - but you must use a file: scheme to open file-paths that contain spaces. To work around this, you can use a custom link handler. The following script shows how to do that:

    import sys
    from PyQt5.QtWidgets import QApplication, QTextBrowser
    from PyQt5.QtGui import QDesktopServices
    from PyQt5.QtCore import QUrl
    
    if __name__ == '__main__':
    
        app = QApplication(sys.argv)
    
        text_area = QTextBrowser()
        text_area.setOpenLinks(False)
    
        def handle_links(url):
            if not url.scheme():
                url = QUrl.fromLocalFile(url.toString())
            QDesktopServices.openUrl(url)
    
        text_area.anchorClicked.connect(handle_links)
    
        file = 'c:/temp/test.docx'
        link = '<a href="{}">Option_1</a>'.format(file)
        text_area.insertHtml(link)
    
        file_2 = 'c:/temp/test 2/test.docx'
        link = '<br><a href="{}">Option_2</a></br>'.format(file_2)
        text_area.insertHtml(link)
    
        text_area.show()
        sys.exit(app.exec_())