4

I have a line editor that inherits from QTextEdit, and I am using it to edit view items that show rich text. The second parameter for QTextEdit.setAlignment is `QtAligntment' and the docs say:

Valid alignments are Qt.AlignLeft, Qt.AlignRight, Qt.AlignJustify and Qt.AlignCenter (which centers horizontally).

That is, there is no native support for vertical alignment. Is there an indirect way to vertically center the text in QTextEdit?

Related link

Center the Text of QTextEdit horizontally and vertically : Unfortunately, the accepted answer uses QLineEdit which won't work for me.

A clue?

At the following I found a clue about how to do it in C++/Qt. I am almost able to follow it, but not quite, as it is for c++:

http://www.qtcentre.org/threads/26003-Vertical-centering-of-a-QTextEdit

I will hack at it on my own for a couple of days and try to answer it myself, but wanted to post this now in case someone has already cracked it already or done it in a different/better way.

Community
  • 1
  • 1
eric
  • 7,142
  • 12
  • 72
  • 138

2 Answers2

2

For a single-line edit centred vertically, you just need to calculate a correct fixed height.

Using the example delegate from your previous question, it can be achieved like this:

class RichTextLineEdit(QtGui.QTextEdit):   
    def __init__(self, parent=None):
        ...    
        margin = 1
        self.document().setDocumentMargin(margin)
        fontMetrics = QtGui.QFontMetrics(self.font())
        height = fontMetrics.height() + (margin + self.frameWidth()) * 2
        self.setFixedHeight(height)

(NB: the reimplemented sizeHint and minimumSizeHint methods are probably redundant in the original example).

Community
  • 1
  • 1
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • That works great and is much simpler than the method I was going to try to impelement from the clue. – eric Oct 05 '15 at 20:14
  • so it turns out when I change the font size, this starts to act very strange (the text toggles between two vertical positions, switching back and forth with each key stroke). When I increase the margin enough, this stops happening, but the margin needed to stop it depends on the font size! I'm working on figuring this out right now, constructing a SSCCE, and will post here or a separate question when I've figured out the mystery. – eric Dec 30 '15 at 20:48
  • I put it as a separate answer: if you want arbitrary font sizes, the above approach gets complicated.... – eric Jan 02 '16 at 19:16
1

While the accepted answer works for default font size, it breaks when I change the font size or vertical margins (see comments). The text line edit class below centers the text vertically, for all font sizes and vertical margins that I've tested.

It sets up the editor using QTextDocument which is then assigned to the QTextEdit instance. QTextDocuments provide the back-end containers for QTextEdits anyway, and have built-in functionality for handling font sizes and margins, and give an additional layer of control over the editor.

In practice, I found using QTextDocument let me solve the problem in a more intuitive way without having, you don't have to delve into the nitty-gritty mechanics of frame widths, font metrics, and all that, which we did when working solely using native QTextEdit methods.

Note it uses setViewportMargins() instead of setContentMargins() (which is what you might expect it to use) because the latter is for setting margins for something that is inserted into a layout. The following editor is a standalone widget, not put into any layout, so setContentMargins() won't do anything.

import sys
from PySide import QtGui, QtCore
         
class TextLineEdit(QtGui.QTextEdit):
    topMarginCorrection = -4 #not sure why needed    
    returnPressed = QtCore.Signal()
    def __init__(self, fontSize = 10, verticalMargin = 2, parent = None):
        QtGui.QTextEdit.__init__(self, parent)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose) 
        self.setLineWrapMode(QtGui.QTextEdit.NoWrap)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setFontPointSize(fontSize)
        self.setViewportMargins(-verticalMargin, self.topMarginCorrection , 0, 0)  #left, top, right, bottom
        #Set up document with appropriate margins and font
        document = QtGui.QTextDocument()
        currentFont = self.currentFont()
        currentFont.setPointSize(fontSize)
        document.setDefaultFont(currentFont)
        document.setDocumentMargin(verticalMargin)  
        self.setFixedHeight(document.size().height())
        self.setDocument(document)

    def keyPressEvent(self, event):
        '''stops retun from returning newline'''
        if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
            self.returnPressed.emit()
            event.accept()
        else:
            QtGui.QTextEdit.keyPressEvent(self, event)

            
def main():
    app = QtGui.QApplication(sys.argv)
    myLine = TextLineEdit(fontSize = 15, verticalMargin = 8)
    myLine.show()    
    sys.exit(app.exec_())
    
    
if __name__ == "__main__":
    main()
Chnossos
  • 9,971
  • 4
  • 28
  • 40
eric
  • 7,142
  • 12
  • 72
  • 138