1

I actually have 3 questions in this.

  1. I have a pushbutton which calls an external function (code example given below). when I press Run button, and function is being executed. I want to display message from that function to my Qlabel in window. so far, i am getting that message displayed when function is completely executed and returns to the main function. but i want to see that while function execution is in process. is there a way to fix it?

  2. Secondly, My GUI goes in 'not responding' mode when it is executing any external functions. what could be the possible reason for this and way to fix it?

  3. I want to dynamically adjust the size of all widgets when I open GUI in any other resolution(ScreenSize). right now, the size of QTablewidget is fixed in any case. How can I get it? can this be achieved through any settings in QTDesigner?

enter image description here

enter image description here

Code Generated by UI Designer:

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1150, 905)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(290, 820, 161, 41))
        self.pushButton.setObjectName("pushButton")
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(10, 10, 1131, 791))
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(0)
        self.tableWidget.setRowCount(0)
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(580, 820, 191, 41))
        self.label.setText("")
        self.label.setObjectName("label")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "Run"))


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_())

Main Script:

from PyQt5 import QtWidgets

from demoUI import Ui_MainWindow

from callingexternalfunction import callingexternalfunction

class DemoCode(QtWidgets.QMainWindow, Ui_MainWindow):                    
    def __init__(self):
        super(DemoCode, self).__init__()
        self.setupUi(self)

        self.pushButton.clicked.connect(self.button_clicked)

    def button_clicked(self):
        callingexternalfunction(self)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = DemoCode()    
    window.show()
    sys.exit(app.exec_())

Function callingexternalfunction:

import time

def callingexternalfunction(self):
    for i in range(0,5):
        time.sleep(3)
        self.label.setText('3 Second Pause '+ str(i))
halfer
  • 19,824
  • 17
  • 99
  • 186
Vi_py123
  • 73
  • 1
  • 9

1 Answers1

1

Questions 1 and 2 are related so I will solve them together:

The GUI freezes because the sleep function blocks the GUI event loop so the logic is to run it in another thread. On the other hand, the GUI cannot be accessed directly from another thread since it is not thread-safe, so you must use signals.

main.py

from PyQt5 import QtCore, QtWidgets

import threading

from demoUI import Ui_MainWindow

from callingexternalfunction import callingexternalfunction


class DemoCode(QtWidgets.QMainWindow, Ui_MainWindow):
    signal = QtCore.pyqtSignal(str)

    def __init__(self):
        super(DemoCode, self).__init__()
        self.setupUi(self)

        self.pushButton.clicked.connect(self.button_clicked)
        self.signal.connect(self.label.setText)

    def button_clicked(self):
        threading.Thread(
            target=callingexternalfunction, args=(self.signal,), daemon=True
        ).start()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    window = DemoCode()
    window.show()
    sys.exit(app.exec_())

callingexternalfunction.py

import time

def callingexternalfunction(signal):
    for i in range(0,5):
        time.sleep(3)
        signal.emit('3 Second Pause '+ str(i))

Layouts must be used to resize the widgets (Here is an official tutorial where they are explained), in this case you can use a QGridLayout plus other modifications:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
    <item row="0" column="0" colspan="2">
     <widget class="QTableWidget" name="tableWidget"/>
    </item>
    <item row="1" column="0">
     <widget class="QPushButton" name="pushButton">
      <property name="minimumSize">
       <size>
        <width>160</width>
        <height>40</height>
       </size>
      </property>
      <property name="baseSize">
       <size>
        <width>0</width>
        <height>0</height>
       </size>
      </property>
      <property name="text">
       <string>Run</string>
      </property>
     </widget>
    </item>
    <item row="1" column="1">
     <widget class="QLabel" name="label">
      <property name="text">
       <string/>
      </property>
      <property name="margin">
       <number>0</number>
      </property>
      <property name="indent">
       <number>40</number>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>26</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks! it worked as expected!! about resizing widgets, i tried using layouts but GUI that i have is bit complicated. is there any other workaround? i wanted to use group box with layouts. would it be hard to implement? – Vi_py123 Mar 26 '20 at 04:00