2

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_())
RBenet
  • 171
  • 1
  • 10
  • QTextBrowser is not capable of rendering pdf so you have to use other options like QWebEngineView – eyllanesc Jan 26 '21 at 21:18
  • Thank you very much for your answer. But I don't want to open only a pdf file. I want windows to open any type of file for me. Option 1 that I have posted does what I want. The problem is if there is a blank space in the file name. – RBenet Jan 26 '21 at 21:29
  • The quoting looks messed up. If you want to get a single-quoted file-path inside a double-quoted href, try this: `'Option_1'.format(file)`. – ekhumoro Jan 27 '21 at 01:33
  • Thank you @eyllanesc To avoid confusion I have change the document like a docx and not a pdf. – RBenet Jan 27 '21 at 05:45
  • Thank you @ekhumoro, I show your answer like option 11, This option not works (nothing happends) – RBenet Jan 27 '21 at 05:45

1 Answers1

2

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_())
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • NB: this works for me on linux, but I have not tested it on windows. – ekhumoro Jan 27 '21 at 19:31
  • THANK YOU SO MUCH!!! You give me the solution. In windows option 2 don't works, but options 7,10 and 13 works perfect!!!! I will put the code in my answer. – RBenet Jan 27 '21 at 20:26