Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

qtextedit settext/setmarkdown not updating



  • Dear all,

    Once again, I'm stuck and would like to ask for your advice concerning an issue with qtextedit.
    I have a qtextedit widget and can at initialization write text A to it with settext (or setMarkdown at 5.14). So far this works nicely.
    Next to the qtextedit, I have a Qtreeview filled by QfilesystemModel. When the user selects a new file B, I want the qtextedit to be updated. The connection to the selectionchanged event works and settext is called on the qtextedit.
    The problem: The text is not updated. Only if I select yet another file "C", the previous selected file (B) is shown.
    I found online some pages mentioninga similar issue claiming to use qthreads (which does not match my usecase) or to call qapplication.processevents, which does not help either...

    Any clues?
    Any hints are apprechiated!

    Ulrich

    python on windows 10 qt5.14


  • Qt Champions 2019

    @hermes said in qtextedit settext/setmarkdown not updating:

    event works and settext is called on the qtextedit.

    How? Please show us some code.



  • Sorry,... the basic mistake...
    It's ugly, but only my start...

    to execute it:
    python.exe .\mynotes.py ..\test-file\ test.md
    where
    mynnotes.py is the file with the following code.
    ..\test-file\ is a folder with markdown or textfiles
    test.md is the first file it should show.

    import sys, os, re
    from PyQt5.QtWidgets import QApplication, QFileSystemModel, QTreeView, QWidget, QVBoxLayout, QHBoxLayout, QMainWindow
    from PyQt5.QtGui import QIcon, QFont, QImage, QTextDocument
    from PyQt5 import QtCore, QtGui, QtWidgets
    from PyQt5.QtCore import PYQT_VERSION_STR
    
    IMAGE_EXTENSIONS = ['.jpg','.png','.bmp']
    
    def splitext(p):
        return os.path.splitext(p)[1].lower()
    
    class TextEdit(QtWidgets.QTextEdit):
    
        def canInsertFromMimeData(self, source):
    
            if source.hasImage():
                return True
            else:
                return super(TextEdit, self).canInsertFromMimeData(source)
    
        def insertFromMimeData(self, source):
    
            cursor = self.textCursor()
            document = self.document()
    
            if source.hasUrls():
    
                for u in source.urls():
                    file_ext = splitext(str(u.toLocalFile()))
                    if u.isLocalFile() and file_ext in IMAGE_EXTENSIONS:
                        image = QImage(u.toLocalFile())
                        document.addResource(QTextDocument.ImageResource, u, image)
                        cursor.insertImage(u.toLocalFile())
    
                    else:
                        # If we hit a non-image or non-local URL break the loop and fall out
                        # to the super call & let Qt handle it
                        break
    
                else:
                    # If all were valid images, finish here.
                    return
    
            elif source.hasImage():
                image = source.imageData()
                uuid = hexuuid()
                document.addResource(QTextDocument.ImageResource, uuid, image)
                cursor.insertImage(uuid)
                return
    
            super(TextEdit, self).insertFromMimeData(source)
    
    class window(QMainWindow):
        def __init__(self):
            super().__init__()
    
        def treeselectionChanged(self, selected, deselected):
            filename = self.model.filePath(selected.indexes()[0])
            if os.path.isfile(filename) and filename != self.c_file:
                self.savefile()
                print('changing file to ', filename)
                self.loadfile(filename)
                self.c_file = filename
    
        def settext(self, c_text):
            qt_subversion = int(re.match('5\.(\d*)',PYQT_VERSION_STR).group(1))
            if qt_subversion >= 14:
                self.textedit.setMarkdown(c_text)
                # to automatttically change some formatting, e.g. * to bulleted list
                #self.textedit.setAutoFormatting(QtWidgets.QTextEdit.AutoAll)
            else:
                self.textedit.setText(c_text)
            return True
    
        def savefile(self):
            """saves the current qtextedit content to file"""
            #save the old file
            out = self.textedit.toMarkdown()
            tmp = open(self.filename,'w')
            tmp.write(out)
            tmp.close()
            
        def loadfile(self, filename):
            c_text = open(self.c_file, 'r').read()
            self.settext(c_text)
            self.filename = filename
            self.setWindowTitle(os.path.basename(filename))
            print('new file loaded: ', filename)
            return True 
        
    
        def eventFilter(self, obj, event):
            if event.type() == QtCore.QEvent.KeyPress and obj is self.textedit:
                if event.key() == QtCore.Qt.Key_Return and self.textedit.hasFocus():
                    self.textedit.setMarkdown(self.textedit.toMarkdown())
            return super().eventFilter(obj, event)
    
        def closeEvent(self, event):
            """" called if program is closed, to save the current file"""
            self.savefile()
            
        def createUI(self, basepath, filename):
            self.centralwidget = QWidget()
            self.windowLayout = QHBoxLayout()
            
            self.c_file = os.path.join(basepath, filename)
    
            # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX        
            # the left  side of the file viewer
            self.model = QFileSystemModel()
            root = self.model.setRootPath(basepath)
            self.model.setNameFilters(['*.md'])
            self.model.setNameFilterDisables(False)
            self.tree = QTreeView()
            self.tree.setModel(self.model)
            self.tree.setRootIndex(root)
            self.tree.setColumnHidden(1, True)
            self.tree.setColumnHidden(2, True)
            self.tree.setColumnHidden(3, True)
            self.tree.setAnimated(False)
            self.tree.setIndentation(20)
            self.tree.setSortingEnabled(True)
            self.tree.setWindowTitle("Dir View")
            self.tree.resize(640, 480)
            self.tree.selectionModel().selectionChanged.connect(self.treeselectionChanged)
            self.windowLayout.addWidget(self.tree)
    
            # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    
            # the edit window on the left side
            self.textedit = TextEdit()
            self.loadfile(self.c_file)
            self.windowLayout.addWidget(self.textedit)
    
            # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
            self.centralwidget.setLayout(self.windowLayout)
            self.setCentralWidget(self.centralwidget)
            self.show()
    
    def main(basepath, filename):
        main = QApplication(sys.argv)
        u_window = window()
        u_window.createUI(basepath, filename)
        u_window.show()
        sys.exit(main.exec_())
      
        
    if __name__ == '__main__':
        print('len', len(sys.argv))
        print(sys.argv)
        if len(sys.argv) != 3:
            print("usage: python mynotes basepath filename")
        else:
            main(sys.argv[1], sys.argv[2])
    
    

  • Banned

    Give an example of what is supposed to be contained within self.c_file



  • self.c_file contains a string of the currently displayed file.
    The files themselves are plain text files (or with QT 5.14 added markdown support) and markdown ascii text. With self.model.setNameFilters(['*.md']) I currently filter for fileextensions ".md"


  • Banned

    Okay yes I know that the variable self.c_file contains the name of the file what I am asking is what is contained within that file -- what are the files contents this way when I run your program and get to self.loadfile(self.c_file) I have something to load appropriate to what it is expecting -- so if that file is large (lots of entries) then just give me the first 10 lines of it



  • Dear Denni,

    I'm very sorry for not having replied earlier - I somehow did not get a notification and was moving flat in the meantime, so I forgot about this pet-project for a while.

    Any ascii file will do - if you have qt > 5.14 it could also be markdown formatted. So it could e.g. be

    this is the heading

    • this is the first line
    • this is the second line

    end.

    The files are meant to contain a kind of todo list for myself.


  • Banned

    Okay not sure why you did not just supply the first 10 lines but okay the first 10 lines of the file consists of something like:

    To Do List
    1st Item To Do
    2nd Item To Do
    3rd Item To Do
    4th Item To Do
    5th Item To Do
    6th Item To Do
    7th Item To Do
    8th Item To Do
    9th Item To Do
    

    Basically a single column table of text with the first row being a header -- is that correct?


  • Banned

    Okay using the above file contents and restructuring you code a bit and removing the elements that were not doing anything currently -- which I am sure you can add back in now so they work appropriately with the new code layout -- here is a version that I hope helps you understand how to go about doing some of what you wanted to do as well as showing other aspects of it to help make it clearer over all --- note instead of call backs to your Parent you could use Signal/Slots but unless you are going to be Threading it -- it really is not necessary to add that level of complexity

    from PyQt5.QtCore    import Qt
    #from PyQt5.QtGui     import 
    from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QVBoxLayout, QFrame
    from PyQt5.QtWidgets import QLabel, QPushButton, QLineEdit
    
    from zTest_03 import ObjectEncoder as objEncodr
    
    class TopFrame(QFrame):
        def __init__(self, parent):
            QFrame.__init__(self)
            self.Parent = parent
    
            self.setFrameShape(QFrame.Box)
            self.setFrameShadow(QFrame.Sunken)
          # ----- First Row
            self.lblQuestion = QLabel("Enter a question:")
    
            self.lneQuestion = QLineEdit()
            self.lneQuestion.setToolTip("Unesite pitanje te pritisnite dugme Unesi pitanje")
            self.lneQuestion.setToolTipDuration(-1)
    
            self.btnQuestion = QPushButton("Enter Question")
            self.btnQuestion.setToolTip("Pritisnite ovo")
            self.btnQuestion.clicked.connect(self.AddQuestion)
          # ----- Second Row
            self.lblTAnswer = QLabel("Enter the correct answer:")
    
            self.lneTAnswer = QLineEdit()
    
            self.btnTAnswer = QPushButton("Enter True Answer")
            self.btnTAnswer.clicked.connect(self.AddTAnswer)
          # ----- Third Row
            self.lblFAnswer = QLabel("Enter all possible answers:")
    
            self.lneFAnswer = QLineEdit()
    
            self.btnFAnswer = QPushButton("Enter False Answer")
            self.btnFAnswer.pressed.connect(self.AddFAnswer)
    
            self.btnNewQuestion = QPushButton("New Question")
            self.btnNewQuestion.clicked.connect(self.NewQuestionReset)
          # ----- Fourth Row
            self.btnDone = QPushButton("Done")
            self.btnDone.clicked.connect(self.Done)
    
            grdArea = QGridLayout()
    
            grdArea.addWidget(self.lblQuestion, 0, 0)
            grdArea.addWidget(self.lneQuestion, 0, 1)
            grdArea.addWidget(self.btnQuestion, 0, 2)
    
            grdArea.addWidget(self.lblTAnswer, 1, 0)
            grdArea.addWidget(self.lneTAnswer, 1, 1)
            grdArea.addWidget(self.btnTAnswer, 1, 2)
    
            grdArea.addWidget(self.lblFAnswer, 2, 0, 1, 1)
            grdArea.addWidget(self.lneFAnswer, 2, 1, 1, 1)
            grdArea.addWidget(self.btnFAnswer, 2, 2, 1, 1)
            grdArea.addWidget(self.btnNewQuestion, 2, 3, 1, 1)
    
            grdArea.addWidget(self.btnDone, 5, 2, 1, 1)
    
            self.setLayout(grdArea)
    
        def CurrentlyDoNothing(self):
            self.Parent.CurrentlyDoNothing()
    
        def AddQuestion(self):
            self.Parent.AddQuestion()
    
        def AddTAnswer(self):
            self.Parent.AddTAnswer()
    
        def AddFAnswer(self):
            self.Parent.AddFAnswer()
            self.lneFAnswer.clear()
    
        def Done(self):
            self.Parent.Done()
    
        def NewQuestionReset(self):
            self.Parent.NewQuestionReset()
    
    class MidFrame(QFrame):
        def __init__(self, parent):
            QFrame.__init__(self)
            self.Parent = parent
    
            self.setFrameShape(QFrame.Box)
            self.setFrameShadow(QFrame.Sunken)
    
            self.lblFileName = QLabel("Enter the name of the file:")
    
            self.lneFileName = QLineEdit()
    
            self.btnFileName = QPushButton("Enter File")
            self.btnFileName.clicked.connect(self.CurrentlyDoNothing)
    
            grdArea = QGridLayout()
    
            grdArea.addWidget(self.lblFileName, 0, 0, 1, 1)
            grdArea.addWidget(self.lneFileName, 0, 1, 1, 1)
            grdArea.addWidget(self.btnFileName, 0, 2, 1, 1)
    
            self.setLayout(grdArea)
    
        def CurrentlyDoNothing(self):
            self.Parent.CurrentlyDoNothing()
    
    class BtmFrame(QFrame):
        def __init__(self, parent):
            QFrame.__init__(self)
            self.Parent = parent
    
            self.setFrameShape(QFrame.Box)
            self.setFrameShadow(QFrame.Sunken)
    
            self.lblNumQuests = QLabel("Number of questions in exam:")
    
            self.lneNumQuests = QLineEdit()
    
            self.btnNumQuests = QPushButton("Enter Number")
            self.btnNumQuests.clicked.connect(self.CurrentlyDoNothing)
    
            self.btnGenerate = QPushButton("Create Exam")
            self.btnGenerate.clicked.connect(self.CreateExamSetup)
    
            grdArea = QGridLayout()
    
            grdArea.addWidget(self.lblNumQuests, 0, 0, 1, 1)
            grdArea.addWidget(self.lneNumQuests, 0, 1, 1, 1)
            grdArea.addWidget(self.btnNumQuests, 0, 2, 1, 1)
            grdArea.addWidget(self.btnGenerate,  0, 3, 1, 1)
    
            self.setLayout(grdArea)
    
        def CurrentlyDoNothing(self):
            self.Parent.CurrentlyDoNothing()
    
        def CreateExamSetup(self):
            self.Parent.CreateExamSetup()
    
    class UI_Form(QWidget):
        def __init__(self):
            QWidget.__init__(self)
    
            self.setWindowTitle("Kolokvij")
            self.resize(500, 300)
    
            self.FileHndlr = objEncodr()
            self.FileData = self.FileHndlr.GetFileData()
            print('File Data :',self.FileData)
            
            self.Question = {}
            self.QustnCnt = 1
    
            self.TopArea = TopFrame(self)
            self.MidArea = MidFrame(self)
            self.BtmArea = BtmFrame(self)
    
            VBox = QVBoxLayout()
            VBox.addWidget(self.TopArea)
            VBox.addWidget(self.MidArea)
            VBox.addWidget(self.BtmArea)
            
            self.setLayout(VBox)
    
        def CurrentlyDoNothing(self):
            print('I will eventually do something?')
    
        def AddQuestion(self):
            self.Question[0] = self.TopArea.lneQuestion.text()
    
        def AddTAnswer(self):
            self.Question[1] = self.TopArea.lneTAnswer.text()
    
        def AddFAnswer(self):
            self.QustnCnt += 1
            self.Question[self.QustnCnt] = self.TopArea.lneFAnswer.text()
    
        def Done(self):
            print('Question & Answers :',self.Question)
    
        def NewQuestionReset(self):
            self.Question = {}
            self.TopArea.lneQuestion.clear()
            self.TopArea.lneTAnswer.clear()
            self.TopArea.lneFAnswer.clear()
    
        def CreateExamSetup(self):
            self.MidArea.lneFileName.clear()
            self.BtmArea.lneNumQuests.clear()
    
    if __name__ == "__main__":
        EvntThred = QApplication([])
    
        Form = UI_Form()
        Form.show()
    
        EvntThred.exec()
    
      # If anyone wants more extensive free help I run an online lab-like classroom-like 
      # message server feel free and drop by you will not be able to post until I clear 
      # you as a student as this prevents spammers so if interested here is the invite
      # https://discord.gg/3D8huKC
    


  • I figures out that I was chasing something completly wrong.. In the end it was simply that I had incorrectly switched the order of two commands...
    self.loadfile(filename)
    self.c_file = filename
    ... What a basic mistake...


Log in to reply