1

I am building a grid of QTextEdit with HTML Subset to show some data within an interface in PyQt.

At the moment I get the GridLayout and the QFrame that contains it doing whatever they want and there is no way for me to make them fit the QTextEdit size. I plaid with SizePolicy but does not work. see from the image how extra space appears on the side of each QText and how the GridLayout cuts the QTextEdit in height.

The only way to make it work is if I set the correct QFrame size to make everything fit, but being that the size of the QTextEdit is customizable, I would like the QFrame to simply fit whatever it has to contain instead of getting free will +_+

Notice that the GridLayout is usually bigger than the mainwindow so it will not need to fit the window hence why need a scrollArea.

What I do not want: What I do not want to Happen

As it should be:

What I want to happen notice that the image I want has been obtained adding this line (in MainFrame()):

container.resize(1100,1360)

As I said I want to obtain the same behaviour but without specifying the dimension for QFrame, this should fit the content (the subset HTML tables)

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from random import *

class Box(QTextBrowser):

    def __init__(self):
        super().__init__()

        self.setText('''
            <table border="0" cellspacing="0" cellpadding="5" style="background-color: rgba(119, 212, 212, 0.7);">
                <tr>
                    <td width="100">
                    bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
                    </td>
                <tr>
                <tr>
                    <td>
                    bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
                    </td>
                <tr>
            </table>

        ''')

        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.setContentsMargins(0,0,0,0)

        cstring ="""
        QTextBrowser {
            border: 0;
            background-color: #<---->;
            margin: 0px;
            padding-left:0;
            padding-top:0;
            padding-bottom:0;
            padding-right:0;
        }
        """

        ncol = randint(300000, 999999)

        cstring = cstring.replace('<---->', str(ncol))

        self.setStyleSheet(cstring)


class MainFrame(QScrollArea):
    def __init__(self):
        super().__init__()

        container = QFrame(self)


        layout = QGridLayout(container)

        for row in range(0, 5):
            for col in range(0, 10):
                QGridLayout.addWidget(layout, Box(), row, col)

        self.setWidget(container)

        container.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

        layout.setContentsMargins(0,0,0,0)
        layout.setSpacing(0)

        self.show()


if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = MainFrame()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
user3755529
  • 1,050
  • 1
  • 10
  • 30

1 Answers1

2

To get the right size, you must use the idealWidth() method of document(), but this will only be correct when the item is visible so you should apply it when the widget is visible, so you should call the show() method that this change is applied, in addition to calling it every time the text changes.

To get the correct height, use the size() method of QTextDocument()

class Box(QTextBrowser):
    def __init__(self, parent=None):
        QTextBrowser.__init__(self, parent)
        self.setContentsMargins(0, 0, 0, 0)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        cstring = """
        QTextBrowser {
            border: 0;
            background-color: #<---->;
            margin: 0px;
            padding-left:0;
            padding-top:0;
            padding-bottom:0;
            padding-right:0;
        }
        """

        ncol = randint(300000, 999999)
        cstring = cstring.replace('<---->', str(ncol))
        self.setStyleSheet(cstring)

        self.document().contentsChange.connect(lambda: self.customGeometry())
        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        self.setContentsMargins(0, 0, 0, 0)

    def customGeometry(self):
        if self.isVisible():
            self.setFixedWidth(self.document().idealWidth())
            self.setFixedHeight(self.document().size().height())

    def showEvent(self, event):
        self.customGeometry()
        QTextBrowser.showEvent(self, event)


class MainFrame(QScrollArea):
    def __init__(self, parent=None):
        QScrollArea.__init__(self, parent)
        container = QFrame(self)

        layout = QGridLayout(container)
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)
        self.show()

        text = '''
                <table border="0" cellspacing="0" cellpadding="5" style="background-color: rgba(119, 212, 212, 0.7);">
                <tr>
                    <td width="100">
                        bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
                    </td>
                <tr>
                <tr>
                   <td>
                        bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
                    </td>
                <tr>
                </table>
                '''

        for row in range(5):
            for col in range(10):
                box = Box(container)
                box.setText(text)
                box.show()
                layout.addWidget(box, row, col)

        self.setWidget(container)


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    ex = MainFrame()
    ex.show()
    sys.exit(app.exec_())

Output:

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks, I will check later, but looks like it does the job. Still I don't understand why they just don't make it as simple as a HTML table where the cells fit the content with no fuss and in the rows the tallest cell drives the row height and in columns the widest cell drives the column width. Simple. – user3755529 Oct 20 '17 at 17:27
  • HTML does not fit the size if you set fixed sizes, in your case you have placed width = 100 so the widget does not know the right size, the same should happen in a web page. – eyllanesc Oct 20 '17 at 17:30
  • What I am saying is that in HTML if I have a table with no dimensions and inside the TDs of that table I put a table with a dimension the NONdimensional table will fit perfectly the content. PyQt as in my example above seems not to do the same as the NONdimensional QFrame it does not fit my fixed (width=100) table (which is the content) – user3755529 Oct 20 '17 at 17:37
  • if you are interested here is the repo: https://github.com/AskBid/scrap-custom-trading-watchlist/tree/gui-mods (guit.py) – user3755529 Oct 20 '17 at 18:16
  • when I update the MainFrame() with a button the layout gets all messed up – user3755529 Oct 21 '17 at 09:30