1

I would like to have my PyQT widget interface be changeable while in the background thread, I would like to send the values from my edit boxes when the checkbox is selected over udp while it is still selected. However, when I try to this do, my GUI is freezing since it seems it gets stuck in the while loop(I think) reading the value and checking the checkbox the whole time. I created a Thread and queue to pass the data from the main Thread to my background thread, thinking it would handle this, while I could still the values on the main GUI thread but it doesnt work. Can someone please help? Is there a way to access all of my main thread widgets in my background thread so i can do the loop in the background to send the data?

import sys, os , queue, multiprocessing, threading
import socket
import numpy as np
from PyQt5.QtWidgets import QMainWindow,QHBoxLayout,QLabel,QRadioButton, QTextEdit, \
    QApplication, QWidget, QVBoxLayout, QFormLayout,\
    QMessageBox

from PyQt5.QtGui import QIcon, QFont, QDoubleValidator
from PyQt5.QtCore import pyqtSlot, QThread, QObject , pyqtSignal
from PyQt5 import QtCore, QtWidgets, Qt

class ThreadProcessor(QObject):

    # network code goes here
    completed = pyqtSignal()
    begin = pyqtSignal()
    finish = pyqtSignal()

    def weBegin(self):
        print("er begin")

    def ShutDown(self):
        self.finish.emit()

    def doSend(self):
        number = None
        print("hey")
        # print(self.list)
        if self.conSend :
            print("hellow")
        self.begin.emit()

        # todo code here

        # after a whole lot of code
        # self.completed.emit()


class App(QMainWindow):
    def __init__(self):
        super().__init__()
        '''self.title = 'INTERFACE GUI'
        self.left = 0
        self.top = 0
        self.width = 900
        self.height = 700

        self.setGeometry(self.left, self.top, self.width, self.height)
        self.setWindowIcon(QIcon("am.png"))'''
        self.setWindowTitle("Title")
        # self.setWindowIcon(QIcon('am.png'))
        self.resize(579, 353)
        self.table_widget = MyTableWidget(self)
        self.setCentralWidget(self.table_widget)
        self.show()

class MyTableWidget(QWidget):
    def __init__(self, parent):
        super(QWidget, self).__init__(parent)
        self.initUI()
        self.setupThread()

    @pyqtSlot()
    def completed(self):
        self.continous_send.setEnabled(False)
        self.pushButton1.setEnabled(True)


    @pyqtSlot()
    def begin(self):
        self.pushButton1.setEnabled(True)

    def setupThread(self):
        self.thread = QThread()
        self.worker = ThreadProcessor()
        self.worker.moveToThread(self.thread)

        self.thread.started.connect(self.worker.weBegin)
        # self.thread.terminate.connect(self.worker.ShutDown)
        self.worker.completed.connect(self.completed)
        self.worker.begin.connect(self.begin)
        # todo send the list form the line edits here somehow
        list = [self.textInput.text(), self.val2.text()]
        self.pushButton1.clicked.connect(self.worker.doSend)

        self.thread.start()




    def initUI(self):
        # Networking Stuff
        # self.udpSocket = QtNetwork.QUdpSocket()
        # self.udpSocket.connectToHost(self.appr, self.port)

        # layout
        self.layout = QVBoxLayout(self)
        self.label = QLabel("testLabel")
        self.layout.addWidget(self.label)
        # Initialize tab screen
        self.tabs = QtWidgets.QTabWidget()
        self.tab1 = QtWidgets.QWidget()
        self.tab2 = QtWidgets.QWidget()
        self.tab3 = QtWidgets.QWidget()
        self.tabs.setGeometry(0, 0, 200, 200)
        self.resize(200, 200)
        # Add tabs
        self.tabs.addTab(self.tab1, "tab1")

        # Create first tab
        # self.tab1.layout = QHBoxLayout(self)
        self.pushButton1 = QtWidgets.QPushButton(self.tab1)
        self.pushButton1.setText("send udp")
        self.pbleft = 0
        self.pbtop = 40

        self.pushButton1.setGeometry(QtCore.QRect(0, 0, 150, 25))
        # self.tab1.setLayout(self.tab1.layout)
        # creating radiobutton to continuosly send udp
        self.continous_send = QtWidgets.QRadioButton(self.tab1)
        self.continous_send.setText("Send Forever")
        self.continous_send.setChecked(False)
        # self.continous_send.setGeometry(QtCore.QRect(160,100,40,40))
        self.continous_send.move(160, 100)
        # creating a integer text input
        self.textInput = QtWidgets.QLineEdit(self.tab1)
        self.textInput.setPlaceholderText("enter value")
        self.textInput.setValidator(QDoubleValidator())
        self.textInput.setGeometry(QtCore.QRect(160, 0, 150, 25))
        # second integer box
        self.val2 = QtWidgets.QLineEdit(self.tab1)
        self.val2.setPlaceholderText("enter value")
        self.val2.setValidator(QDoubleValidator())
        self.val2.setGeometry(QtCore.QRect(160, 50, 150, 25))
        # create the Second Tab

        # Add tabs to widget
        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)

    def click(self):
        print('began Thread')

    def changed(self):
        if self.thread.isRunning():
            self.thread.terminate()
        print('Killed Thread')




'''
    def click(self):

        # self.checkSend = self.continous_send.isChecked()
        try :
            self.thread.start()
            self.pushButton1.setEnabled(False)
        except KeyboardInterrupt:
            self.finishQueueProcess()

    def finishQueueProcess(self):
        self.inq.put(None)
        self.inq.join()
        self.tdPro.shutThread()
        self.tdPro.join()
        os._exit(-1)
'''

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())
Aboogie
  • 450
  • 2
  • 9
  • 27
  • You seem to be using Python multiprocessing rather than Python threading and it really seems like you should be using Qt threading rather than either of those. It is not easy to understand what you are doing from your code, but I would suggest you should look at connecting the appropriate `QLineEdit` [signal](http://doc.qt.io/qt-5/qlineedit.html#signals) to a slot in a `QThread` to transfer the data rather than a scheme that requires constantly reading the value from the widget. Consider looking at some `QThread` examples like [this](http://stackoverflow.com/a/35534047/1994235). – three_pineapples Mar 22 '17 at 02:56
  • I will also reiterate that you cannot directly access GUI objects from another thread or process. You need to transfer the data via signals/slots or some other thread safe object (like a Python Queue, which is distinct from the Python multiproessing.Queue). See [here](http://stackoverflow.com/documentation/pyqt/2775/using-threads-with-pyqt#t=20161111002348120811) for some more PyQt threading tips. – three_pineapples Mar 22 '17 at 02:58
  • hey @three_pineapples I updated my code and it runs where i can notify my gui that something has happened from the thread, however, im not sure on how to go about sending the list I have set up from my gui to the thread (and update the list on the thread as the list changes in the gui) . – Aboogie Mar 22 '17 at 21:06
  • I don't have time right now to write a full answer, but instead of directly connecting the signal to the worker slot, I think you need to define an intermediate signal in the `QWidget` that has a list as an argument (`relay_signal = pyqtSignal(list)` or `pyqtSignal(object)`). Connect this signal to the worker slot (and modify it to accept an argument of your list). Then for the button, do `self.pushButton1.clicked.connect(lambda: self.relay_signal.emit(self.list))`. Note that the contents of the lambda are evaluated each time it executes so will always use the current value of `self.list`. – three_pineapples Mar 23 '17 at 09:59
  • I'll try and come back to this tomorrow and write up a full answer :) – three_pineapples Mar 23 '17 at 10:00

0 Answers0