2

I am preparing a catalog for a small library. All books with main data are displayed. Next to each title there is a button that must show the cover image and a short description of the content. Something like this.

enter image description hereUntil now I have not found anything that could help me, all the options present in designer do not allow to have the text arranged as I would like

Ryan Day
  • 113
  • 1
  • 8
  • You will need to use a `QWebEngineView`. Widgets like `QLabel` and `QTextEdit` only support a [limited subset of HTML4](https://doc.qt.io/qt-5/richtext-html-subset.html). The CSS isn't sophisticated enough to produce that kind of text layout. – ekhumoro Sep 07 '22 at 12:33
  • Thank you. I'll try it and let you know – Ryan Day Sep 07 '22 at 14:21
  • @ekhumoro Actually, it is sophisticated enough, since the `float` property is supported for tables and images. – musicamante Sep 08 '22 at 00:49
  • @musicamante Well, that is really weird because when I tried `float` yesterday, I couldn't get it to work. Somehow, the image was positioned on the right, but always ended up *below* the text, no matter where I inserted it. As far as I can recall, I used the Qt Designer text-edit dialog on a QLabel with just a simple block of text and a single image tag, with no other html. But when I try the same thing today, I cannot reproduce the previous behaviour. Presumably, there was something weird about the text I copied yesterday that messed up the preview somehow. Never mind... – ekhumoro Sep 08 '22 at 10:43

1 Answers1

2

You cannot achieve that layout using Designer, because the layout management of Qt always considers objects (widgets) having a rectangular shape, even if they contain text: text based widgets are just like other "rectangular widgets" and their content is not considered nor changed based on the "shape" of other elements in the layout: Qt layout managers always consider widgets as rectangles.

It can be done, though, using rich-text based widgets like QLabel (discouraged for this purpose[1]) or QTextEdit, by embedding the image in the document[2], since the (limited) HTML subset provided by the Qt rich text engine supports the basic float property[3] for images and tables.

The following basic HTML can be used with QTextEdit.setHtml():

<img src="path/to/image.png" style="float: right;">
Some very long text...
...
...
...

Here is the result:

Screenshot of the example

The only issue is the path of the image.

If the image is stored with the Qt resource system, use that path (src=":path/in/resources")[4].

If the image is a local file, then just use python formatting with the path to that file, and ensure that that path is correct (consider that relative paths always use the working directory, which is the path from which the python interpreter is launched).

If the image is loaded internally (for instance, from the network) and not stored as a physical file, you can use the base64 encoding to show the image:

import base64
# ...

# assuming "imageData" is a Python "bytes" object
base64data = base64.b64encode(imageData).decode()
html = '''
<img src="data:image/whatever;base64,{}" style="float: right;">
'''.format(base64data)

# to avoid escaping of curly brackets for format() or f-string
html += '''
Some very long text...
'''

textEdit = QTextEdit(readOnly=True)
textEdit.setHtml(html)

Note that the value of data: in <img src=""> is actually pointless: you only need to provide the data: part, the value is actually not that relevant since Qt just uses QImage.loadFromData() and automatically guesses the format from the file using QImageReader. The result is the same that you would get by doing img = QImage('myimage') even if you don't specify the format and the file name has no specific/valid extension. This also obviously means that if the file/data is corrupted, the image might not be shown (and a "broken image" icon will be shown as a placeholder).

If the image was retrieved through Qt (for instance, using QFile.readAll() or downloaded with QNetworkAccessManager), then the the raw data is stored as a QByteArray, and the base64 data used above can be created with the following:

base64data = imageData.toBase64().data().decode()

as in:

# - encode using base64, as another QByteArray:
qtBase64 = imageData.toBase64()
# - convert it to a Python "bytes" object (b"..."):
pyBase64 = qtBase64.data()
# - make it a string:
base64data = pyBase64.decode()

The above is also valid if the image is stored on a database as raw data.


[1] QLabel obviously lacks direct support for scrolling, and it also has some important limitations when using rich text contents (most importantly, word wrapped contents) and the label is part of a complex layout.

[2] QLabel actually uses QTextDocument features internally, which enables rich text features (most importantly, word wrapping; see the above note) whenever it detects what could possibly be HTML formatted content (based on the return value of Qt.mightBeRichText()).

[3] Remember that the current Qt rich-text support is based on HTML4 and CSS2.1, so the only valid values of float are: left, right and none (the default). The CSS inherit value is also not supported.

[4] Be aware that PyQt6 dropped support for the pyrcc utility, but resource files can still be used (since they're implemented on the Qt side, not in Python) and built with the rcc utility provided by Qt: they added the -g python flag, similarly to what done for uic, which creates python compatible resource files. You only need to edit the import statement of the generated file to avoid issues (remember that PyQt and PySide can not be used together, and PySide might not be installed in the target system). See this answer.

musicamante
  • 41,230
  • 6
  • 33
  • 58
  • It's perfect. I had to adapt part of my code to your suggestions but in the end everything was OK. Now I just have to resize the image and, if possible, the scrollbar. Thank you – Ryan Day Sep 08 '22 at 12:08
  • You can specify a reference dimension in the `` tag and it will show the image scaled to that dimension while keeping the aspect ratio. The scroll bar, instead, is part of the *widget*, so you cannot "style" it as you could in a web browser. Depending on your needs, there is some level of customization. Eventually consider using Qt Style Sheets (see the [examples](https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar), but also carefully read the QSS documentation). – musicamante Sep 08 '22 at 16:13
  • I searched my old HTML scripts and found the answer to resize the image (height = x and width = y) at the end of – Ryan Day Sep 08 '22 at 20:09