0

I have a class of textboxs subclassed from QTextEdit, it automatically resizes to its content and it also resizes when the window is resized.

The texts can be very long, and the textboxs automatically line-wrap the texts, so when the horizontal space increases, the textboxs can shrunk in height, because of less wrapped lines.

The problem is when the textboxs shrunk, their bottom border will be missing, they will only have left, top, and right borders unless the window's width shrunk.

Minimal, reproducible example:

from PyQt6.QtCore import *
from PyQt6.QtGui import *
from PyQt6.QtWidgets import *

class Editor(QTextEdit):
    def __init__(self):
        super().__init__()
        self.textChanged.connect(self.autoResize)
    
    def autoResize(self):
        self.document().setTextWidth(self.viewport().width())
        margins = self.contentsMargins()
        height = int(self.document().size().height() + margins.top() + margins.bottom())
        self.setFixedHeight(height)
    
    def resizeEvent(self, e: QResizeEvent) -> None:
        self.autoResize()

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(405, 720)
        frame = self.frameGeometry()
        center = self.screen().availableGeometry().center()
        frame.moveCenter(center)
        self.move(frame.topLeft())
        self.vbox = QVBoxLayout(self)
        self.vbox.setAlignment(Qt.AlignmentFlag.AlignTop)
        self.textbox = Editor()
        self.textbox.setText(
            'Symphony No.6 in F, Op.68 \u2014Pastoral\u2014I. Erwachen heiterer Empfindungen bei der Ankunft auf dem Lande\u2014 Allegro ma non troppo'
        )
        self.vbox.addWidget(self.textbox)

app = QApplication([])
window = Window()
window.show()
app.exec()

When you click the maximize button, the textbox goes from three wrapped lines to one line, and the bottom border will be missing until you restore the window.

I would like to redraw the borders, I have Google searched for 8+ hours and can't find a solution, and I have tried to the add following autoResize function to no avail:

self.update()
self.viewport().update()
self.repaint()
self.viewport().repaint()
self.setFrameRect(QRect(0, 0, self.width(), height))

How can this be done?

Ξένη Γήινος
  • 2,181
  • 1
  • 9
  • 35
  • I cannot reproduce the issue (and it shouldn't happen) with your provided code, can you please provide an image showing what you're getting? – musicamante Jul 08 '21 at 14:21

1 Answers1

0

I have got it, the border will be recalculated if the number of lines of text changed, so just define a resizeEvent in whatever is the parent of the QTextEdit, add a new line and remove the new line, job done.

The code:

def resizeEvent(self, e: QResizeEvent) -> None:
    text = self.textbox.toPlainText()
    self.textbox.setText(text + '\n')
    self.textbox.setText(text)

On a second thought, it is better to use a widget that can intercept the resizeEvent, and create a signal and make it emit the signal every time the window is resized, and connect the signal to the slots.

I used the QMainWindow the intercept the event.

Example code:

class  UI_MainWindow(QMainWindow):
    resized = pyqtSignal(QMainWindow)
    def __init__(self):
        super().__init__()
        ...
    def resizeEvent(self, e: QResizeEvent) -> None:
        self.resized.emit(self)

The above is the main window.

Window = UI_MainWindow()
class TextCell(QVBoxLayout):
    ...
    Window.resized.connect(self.redraw_border)
    def redraw_border(self):
        text = self.editor.toPlainText()
        self.editor.setText(text + '\n')
        self.editor.setText(text)

TextCell is the container of the textboxs, and editor is the auto-resizing textbox.

Ξένη Γήινος
  • 2,181
  • 1
  • 9
  • 35
  • This doesn't seem a good and practical solution, but a workaround that it's not guaranteed to always work, since the source of the problem is elsewhere. Then, as already said, subclassing a layout is not suggested, as conceptually objects are only managed by it, but their ownership belongs to the parent widget. If you do some research you'll see that almost *nobody* subclasses layouts just to "group" objects. If you subclass a layout it's because you need to implement or override its behavior. Then, you should not access a global variable from within an instance to create a signal connection. – musicamante Jul 08 '21 at 14:27