2

So I just started working with PyQt5. Right now I only programmed 1 button that's supposed to take text from a line edit, store it in a global variable and put it in a text browser. Now it does this... but with issues. The text browser does NOT update until I click another program/window and then click my app again When the line edit is cleared there is a bug which is basically text not being cleared properly but only it's top half. This goes away when I type again.

I tried calling the .update() methods for the widgets and QApplication.process_events()

Here's the code

from PyQt5 import QtCore, QtGui, QtWidgets

lyrics = ''
adlib = ' (Placeholder adlib)'

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(742, 680)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.addLineBtn = QtWidgets.QPushButton(self.centralwidget)
        self.addLineBtn.setGeometry(QtCore.QRect(530, 0, 91, 51))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setItalic(True)
        self.addLineBtn.setFont(font)
        self.addLineBtn.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.addLineBtn.setObjectName("addLineBtn")
        self.deleteBtn = QtWidgets.QPushButton(self.centralwidget)
        self.deleteBtn.setGeometry(QtCore.QRect(120, 80, 91, 32))
        self.deleteBtn.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.deleteBtn.setObjectName("deleteBtn")
        self.saveBtn = QtWidgets.QPushButton(self.centralwidget)
        self.saveBtn.setGeometry(QtCore.QRect(30, 80, 91, 32))
        self.saveBtn.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.saveBtn.setObjectName("saveBtn")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(30, 20, 501, 51))
        self.lineEdit.setObjectName("lineEdit")
        self.dialLabel = QtWidgets.QLabel(self.centralwidget)
        self.dialLabel.setGeometry(QtCore.QRect(640, 20, 71, 16))
        self.dialLabel.setObjectName("dialLabel")
        self.rtdSlider = QtWidgets.QSlider(self.centralwidget)
        self.rtdSlider.setGeometry(QtCore.QRect(620, 40, 101, 22))
        self.rtdSlider.setOrientation(QtCore.Qt.Horizontal)
        self.rtdSlider.setObjectName("rtdSlider")
        self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
        self.textBrowser.setGeometry(QtCore.QRect(20, 120, 701, 501))
        self.textBrowser.setObjectName("textBrowser")
        self.noadlibBtn = QtWidgets.QPushButton(self.centralwidget)
        self.noadlibBtn.setGeometry(QtCore.QRect(530, 50, 91, 51))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setItalic(True)
        self.noadlibBtn.setFont(font)
        self.noadlibBtn.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.noadlibBtn.setObjectName("noadlibBtn")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 742, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.addLineBtn.clicked.connect(self.addLineAdlib)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.addLineBtn.setText(_translate("MainWindow", "Adlib"))
        self.deleteBtn.setText(_translate("MainWindow", "Delete"))
        self.saveBtn.setText(_translate("MainWindow", "Save"))
        self.dialLabel.setText(_translate("MainWindow", "RTD Level"))
        self.noadlibBtn.setText(_translate("MainWindow", "No Adlib"))

    def addLineAdlib(self):
        global lyrics
        lyrics += self.lineEdit.text() + adlib + '\n'
        self.lineEdit.clear()
        self.textBrowser.setText(lyrics)
    def addLineNoAdlib(self):
        pass

    def save(self):
        pass

    def deleteLine(self):
        pass


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Okay your first issue is you used the Designer instead of making the GUI from scratch like you should have and now you are trying to trouble shoot the garbage code it spewed out -- which makes things 5 times harder to trouble shoot. I will look this over and see if I cannot extract the bug. But maybe you might take a stab at designing this from scratch rather than using the Designer that might not only fix the bug but give you a much better understanding of just how easy from scratch is – Dennis Jensen Jul 23 '19 at 18:21
  • @DennisJensen alright, noted. I guess I'll try to redesign this thing from scratch. Will probably use designer to map out how I want everything to be and then copy the coordinates / dimensions of widgets and write it from scratch. Fingers crossed that it will solve the issue. Thanks for the feedback – Expected2BlankLines Jul 23 '19 at 18:38
  • Working on a structured rewrite I have done several of these already so should not take me too long then you can use that to build from and as a template going forward from now on – Dennis Jensen Jul 23 '19 at 18:48

4 Answers4

4

I found the same problem as yours and I use MacOS Mojave 10.14.6. This problem maybe due to OS, but I downgraded pyqt5 from the latest 5.14.1 to a stable version 5.9.2, the problem was solved.

Coneain
  • 198
  • 12
1

This problem also happens with macos 10.15.6 + pyqt 5.15.0. I created a small example with qtdesigner (with 1 lineEdit box, 1 label box, 1 button), and then created python file with pyuic5 as well as with pyside2-uic.

Both the generated python files have the same problem - when "click" is pressed I have to move out of the window and back again to see the results. But if I just press enter after the input text then it shows up immediately.

The problem is solved by adding an extra line in the main class, for repainting the GUI, as shown below:

import sys
from PyQt5.QtWidgets import QDialog, QApplication
from demo_ui_pyuic5 import *

class MyForm(QDialog):
    def __init__(self):
        super().__init__()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)
        self.ui.buttonClick.clicked.connect(self.dispmessage)
        self.show()
    def dispmessage(self):
        self.ui.labelResponse.setText("Hello " + self.ui.lineEditName.text())
        self.ui.labelResponse.repaint() # this line added to fix the problem

if __name__=="__main__":
    app = QApplication(sys.argv)
    w = MyForm()
    w.show()
    sys.exit(app.exec_())
R71
  • 4,283
  • 7
  • 32
  • 60
0


1. The text browser does NOT update until I click another program/window and then click my app again - this issue can be related with your OS. I have got incorrect PyQT5 behavior on Ubuntu 16.04 while on Ubuntu 18.04 everything was working fine. Can you share more info?
Note: I tested your script on Ubuntu 18.04, I didn't need to click another program/window to refresh it

2. When the line edit is cleared there is a bug which is basically text not being cleared properly but only it's top half. This goes away when I type again. - Can you explain what do you mean by it's top half? If you meant that there is still (Placeholder adlib) text, you should modify your function to check lineEdit textbox before adding something to lyrics variable. For example, like this:

def addLineAdlib(self):
        if self.lineEdit.text():
                global lyrics
                lyrics += self.lineEdit.text() + adlib + '\n'
                self.lineEdit.clear()
                self.textBrowser.setText(lyrics)
Veniamin
  • 774
  • 5
  • 12
  • 1
    1. I have a Mac with Mac OS Mojave 10.14.1 might be related to that. 2. I mean that when I enter the text in the line edit and click to add it to the rest, instead of completely clearing the line edit I can still see PARTS of letters like the whole word was cut in half horizontally. So if I typed 'Hi' I'd then see the 3 vertical lines that would be left if you cut the word 'Hi' in half horizontally. Hard to explain but I hope you got it. It's purely a visual bug and I suspect it's related to my window not updating properly Edit: here's what I mean https://imgur.com/a/mb80hqh – Expected2BlankLines Jul 23 '19 at 18:54
  • I understand you, can you make a screenshot of this visual bug? – Veniamin Jul 23 '19 at 19:00
  • Yep, already done, check the comment you just replied to for an edit. – Expected2BlankLines Jul 23 '19 at 19:03
  • I think, that I found the answer, try to call .repaint() method on the text box. Read more about it here - https://stackoverflow.com/questions/56553257/pyinstaller-and-pyqt5-macos-mojave-compatibility-issues – Veniamin Jul 24 '19 at 07:51
0

Here is a cleaner more class-ified (more pythonic pyqt) version of your program I have left commented out stuff in for you to see where it would have been but I removed your coordinate system and replaced it with the more standard Layout style of creating a GUI.

I tested this using python 3.7 pyqt5 on win10 so if there is OS issue you will know it but my guess (without digging into that ugly mess) is that there was a disconnection some where which created the issue you were experiencing.

Also your button as designed will never create a blank line since its always putting something on a line -- I tested this by just clicking the button without entering anything

from sys import exit as sysExit

from PyQt5.QtCore import Qt
from PyQt5.QtGui  import QFont, QCursor
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QHBoxLayout, QVBoxLayout, QDockWidget, QStyleFactory
from PyQt5.QtWidgets import QPushButton, QLineEdit, QLabel, QSlider, QTextBrowser, QMenuBar, QStatusBar

class MenuToolBar(QDockWidget):
    def __init__(self, MainWin):
        QDockWidget.__init__(self)
        self.MainWin = MainWin
        self.MainMenu = MainWin.menuBar()

        # ******* Create the Help Menu *******
        self.HelpMenu  = self.MainMenu.addMenu('Help')

class CenterPanel(QWidget):
    def __init__(self, parent):
        QWidget.__init__(self)

    # General Font Object for a couple of Buttons
        btnFont = QFont()
        btnFont.setFamily('Arial')
        btnFont.setItalic(True)

    # First Item Horizontal Box 1 Containing the AddLib Entry and Button
        self.lnAdlibEntry = QLineEdit(self)
#        self.lnAdlibEntry.setGeometry(QRect(30, 20, 501, 51))
#        self.lnAdlibEntry.resize(501, 51)

        self.btnAddLine = QPushButton(self)
#                                       Left, Top, Width, Height
#        self.btnAddLine.setGeometry(QRect(530, 0, 91, 51))
#                            Width, Height
#        self.btnAddLine.resize(91, 51)
        self.btnAddLine.setFont(btnFont)
        self.btnAddLine.setCursor(QCursor(Qt.PointingHandCursor))
        self.btnAddLine.setText('Adlib')
        self.btnAddLine.clicked.connect(parent.AddLineAdlib)

        HBox1 = QHBoxLayout()
        HBox1.addWidget(self.lnAdlibEntry)
        HBox1.addWidget(self.btnAddLine)

    # Second Item Vertical Box 1 Containing the AdlibEntry LineEdit and RTD Label and RTD Slider

        self.lblDial = QLabel(self)
#        self.lblDial.setGeometry(QRect(640, 20, 71, 16))
#        self.lblDial.resize(71, 16)
        self.lblDial.setText("RTD Level")

        self.sldrRtd = QSlider(self)
#        self.sldrRtd.setGeometry(QRect(620, 40, 101, 22))
#        self.sldrRtd.resize(101, 22)
        self.sldrRtd.setOrientation(Qt.Horizontal)

        VBox1 = QVBoxLayout()
        VBox1.addWidget(self.lblDial)
        VBox1.addWidget(self.sldrRtd)

    # Third Item Horizontal Box 2 containing the Save, No Adlib and Delete buttons
        self.btnNoAdlib = QPushButton(self)
#        self.btnNoAdlib.setGeometry(QRect(530, 50, 91, 51))
#        self.btnNoAdlib.resize(91, 51)
        self.btnNoAdlib.setFont(btnFont)
        self.btnNoAdlib.setCursor(QCursor(Qt.PointingHandCursor))
        self.btnNoAdlib.setText("No Adlib")

        self.btnSave = QPushButton(self)
#        self.btnSave.setGeometry(QRect(30, 80, 91, 32))
#        self.btnSave.resize(91, 32)
        self.btnSave.setCursor(QCursor(Qt.PointingHandCursor))
        self.btnSave.setText('Save')

        self.btnDelete = QPushButton(self)
#        self.btnDelete.setGeometry(QRect(120, 80, 91, 32))
#        self.btnDelete.resize(91, 32)
        self.btnDelete.setCursor(QCursor(Qt.PointingHandCursor))
        self.btnDelete.setText('Delete')

        HBox2 = QHBoxLayout()
        HBox2.addWidget(self.btnSave)
        HBox2.addStretch(1)
        HBox2.addWidget(self.btnNoAdlib)
        HBox2.addStretch(1)
        HBox2.addWidget(self.btnDelete)

    # Sixth Item Text Browser
        self.txtBrowser = QTextBrowser(self)
#        self.txtBrowser.setGeometry(QRect(20, 120, 701, 501))
#        self.txtBrowser.resize(701, 501)

        VBox2 = QVBoxLayout()
        VBox2.addLayout(HBox1)
        VBox2.addLayout(VBox1)
        VBox2.addLayout(HBox2)
        VBox2.addWidget(self.txtBrowser)

        self.setLayout(VBox2)

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.Lyrics = ''
        self.Adlib = ' (Placeholder adlib)'

        self.setWindowTitle('Main Window')
        self.resize(742, 680)

        self.CenterPane = CenterPanel(self)
        self.setCentralWidget(self.CenterPane)

        self.MenuBar = MenuToolBar(self)
#        self.MenuBar.setGeometry(QRect(0, 0, 742, 22))

        self.SetStatusBar(self)
        self.setStyle(QStyleFactory.create('Cleanlooks'))

    def SetStatusBar(self, parent):
        StatusMsg = ''
        parent.StatBar = parent.statusBar()

        if len(StatusMsg) < 1:
            StatusMsg = 'Ready'

        parent.StatBar.showMessage(StatusMsg)

    def AddLineAdlib(self):
      # This statement retains everything previously in Lyrics and 
      # everything in the AdlibEntry box and everything in Adlib which
      # I am not sure is what you are wanting but it is what you had
        self.Lyrics += self.CenterPane.lnAdlibEntry.text() + self.Adlib + '\n'
        self.CenterPane.lnAdlibEntry.clear()
        self.CenterPane.txtBrowser.setText(self.Lyrics)

    def AddLineNoAdlib(self):
        pass

    def Save(self):
        pass

    def DeleteLine(self):
        pass

if __name__ == "__main__":
    MainThred = QApplication([])

    MainGUI = MainWindow()
    MainGUI.show()

    sysExit(MainThred.exec_())

Edited: I had an odd arrow appearing on my screen which it appears the QStyleFactory call removes and I adjust the StatusBar declaration to be more modular in case you want to Class-ify it later

Dennis Jensen
  • 214
  • 1
  • 14
  • Oh my god thank you. Cant believe someone would take their time to redo my crappy code. Unfortunately the issue is still there but at least now I am 100% sure that the issue is caused by Mac OS. Also I'm aware that it will always put something in the line, there's a 'No Ad-lib' button if you don't want it to add anything. The functionality is of course far from finished I just wanted to see if I can at least get something to work. Cheers! – Expected2BlankLines Jul 23 '19 at 20:15
  • Also your code is really helpful, I saved it for future reference – Expected2BlankLines Jul 23 '19 at 20:22
  • @Expected2BlankLines note I made a couple of edits to the above that you might want to save off as they should have been there to begin with just overlooked them. Oh and that QStyleFactory thing might clear up the issue do not know exactly what it does still learning pyqt5 myself – Dennis Jensen Jul 23 '19 at 20:25
  • thanks for the heads up, the edit actually eliminated the visual but in the line edit I only have the non-updating text to worry about. I think I might narrow it down once get more comfortable with PyQt5 – Expected2BlankLines Jul 23 '19 at 20:31