I am trying to add a full-width horizontal line in QTextEdit from PyQt5.QtWidgets.
My function looks like this:
def print_results(self, results):
self.result_text_box.clear()
self.cursor = self.result_text_box.textCursor()
self.cursor.insertText(results[0])
for result in results[1:]:
# how do I add a horizontal line here?
self.cursor.insertText(result)
results is a list of strings (possibly with newline characters) and self.result_text_box is an instance of QTextEdit.
When I tried self.cursor.insertHtml("<hr/>") I got weird results. Starting with the second string, a horizontal line was added whenever there was a newline character. For whatever reason, self.cursor.insertHtml("<p/><hr/><p/>") solved that problem, but only on macOS, while on Windows it didn't. I tried using just insertHtml, for the text too, but that didn't do the trick.
I would appreciate your help with this. Thanks!
The difference between support and compliance of HTML
An important thing that should always be kept in mind is that, while Qt "supports" HTML, it is NOT a web browser [see note].
Whenever a QtGui/QtWidget class or function provides HTML functionalities, it always follows a limited HTML subset support (see the foot note).
Whenever a function like
setHtml()(orsetText()for optional rich-text objects like QLabel) is called, the given HTML is parsed and converted into a QTextDocument: if the text engine parser doesn't support a certain HTML tag/attribute or CSS syntax, it will be completely ignored and will revert to the most possible way to show the given content considering the context and the HTML object tree.The
<hr>(aka, "Horizontal Rule") element is a peculiar one, even in the HTML world.In Qt, it is an element that is always part of the current QTextBlock (a "paragraph", as in
<p>...</p>) and shown at its bottom.I'll repeat this, as it is extremely important: the
<hr>line is always part of a previous block, it is not a separate element.Add lines as separators between elements
Now, while we could go extremely into deep of the QTextDocument structure, it seems clear that you just want to show plain text entries that are separated by a horizontal line.
So, let's keep this simple.
If you only want lines between elements, it's quite easy:
Note that I removed
self.result_text_box.clear(), which is completely pointless when usingsetHtml(), because that function always overwrites the current contents.A further line, allowing user insertion after it
In case you want to add a further line at the end of the last entry and also allow insertion of further elements, things get a bit trickier.
As said above, the horizontal line is always part of a QTextBlock. This means that if you try to do
insertHtml()the insertion will always be within the current text block of the text cursor, and since insertion of new block always inherits the block format of the current block, you'll end up with two or more consecutive lines.The proper way to add a line at the end and allow insertion of new text after that is the following:
<hr>element;Here is a possible implementation of the above:
Note that I just used a local variable for the QTextCursor; creating an instance attribute for it is not only pointless (you're probably going to call that function more than once, so you will also be overwriting it every time), but wrong, since
cursor()is an existing property/function of all QWidgets and, as such, should never be overwritten, especially with something that is completely unrelated to the original purpose.Be aware that the differences you've seen between macOS and Window might be related to two different aspects:
If you want proper HTML compliance, the only way to do so in Qt is through the Qt WebEngine API; in PyQt5 most of the important classes are within the
QtWebEngine,QtWebEngineWidgetsandQtWebEngineCoremodules, while theQtWebEnginemodule classes have all been moved to theQtWebEngineCoremodule in PyQt6.