0

I have a device connected with my interface and want to insert the data into QlineEdit widgets

This function def getdevice_data(self): receaves the data from the device and returns it as string

with self.get_output__button.clicked.connect(self.getdevice_data) I "start" the function

and with self.custom_attribute.connect(self.device_input1.setText) I send the output to the QLineEdit widget

How can I keep the function running and insert the new data from the function into empty line edit widgets, without adding multiple buttons to start the function again and again ?

full code

import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg

import serial
import time


class CustmClass(qtw.QWidget):
    '''
    description einfügen
    '''

    # Attribut Signal
    custom_attribute = qtc.pyqtSignal(str)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # your code will go here


        # Interface
        self.resize(300, 210)
        # button
        self.get_output__button = qtw.QPushButton("start function ?")
        # lineEdit
        self.device_input1 = qtw.QLineEdit()
        self.device_input2 = qtw.QLineEdit()
        # Layout
        vboxlaout = qtw.QVBoxLayout()
        vboxlaout.addWidget(self.get_output__button)
        vboxlaout.addWidget(self.device_input1)
        vboxlaout.addWidget(self.device_input2)

        self.setLayout(vboxlaout)


        self.show()

        # Funktionalität

        self.get_output__button.clicked.connect(self.getdevice_data)

        self.custom_attribute.connect(self.device_input1.setText)
        # self.custom_attribute.connect(self.device_input2.setText)

    def getdevice_data(self):
        try:
            # Serial() opens a serial port
            my_serial = serial.Serial(port='COM6', baudrate=2400, bytesize=7,
                                      parity=serial.PARITY_NONE, timeout=None, stopbits=1)

            if my_serial.is_open:  
                print("port open")
                # log einfügen
                while my_serial.is_open:  

                    data = my_serial.read()  # wait forever till data arives
                    time.sleep(1)  # delay 

                    data_left = my_serial.inWaiting()  
                    data += my_serial.read(data_left)  

                    data = data.decode("utf-8", "strict")

                    if type(data) == str:
                        print(data)
                        return self.custom_attribute.emit(data)
            else:
                print("zu")

        except serial.serialutil.SerialException:
            print("not open")
            # logger hinzufügen


if __name__ == '__main__':
    app = qtw.QApplication(sys.argv)
    w = CustmClass()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Sator
  • 636
  • 4
  • 13
  • 34
  • Is there any specific reason for those `time.sleep` or are they there to emulate the wait? – musicamante Mar 09 '20 at 11:45
  • `time.sleep` is to make sure to get all the data from the device – Sator Mar 09 '20 at 12:06
  • @HoboCoder Explain better what you mean, your question is confusing. – eyllanesc Mar 09 '20 at 15:16
  • @eyllanesc hope the edit make it less confusing – Sator Mar 09 '20 at 15:39
  • @HoboCoder Okay, I understand you better. I still have the following doubts: 1) If you remove the time.sleep() your code still works? 2) How many QLineEdits do you have to add the text? Are they only 2 QLineEdits? Assume that the information was emitted twice, so 2 QLineEdits have already been filled, in a next emit to which QLineEdit should that text be placed? – eyllanesc Mar 09 '20 at 15:49
  • @eyllanesc without time sleep the code did not work. //to clarify : I have a device wich when I push a button on the device I trasnmit the data to the function. with this code so far I can not continuously receave new data.and add it to new line edit/ What I want is to keep the function running and add each new output to a empty line edit so far I can only add one single output to multiple line eddit widgets – Sator Mar 09 '20 at 16:03
  • @HoboCoder Mmm, I don't understand your answer. Be more detailed and answer my questions clearly. The answer to the first question and I understand it but not to the second question: Assuming that text has been placed in both QLineEdit If new text comes, should the text be placed in the first QLineEdit, or in the second QLineEdit or should a new one be created? new QLineEdit? please use `@username` – eyllanesc Mar 09 '20 at 16:07
  • @eyllanesc my function waits for incoming data and returns it as a string I. I want add sequentially each empty line edit with the data/ if lineedit1 is full insert it to lineedit2 and so on – Sator Mar 09 '20 at 16:21
  • @HoboCoder And if lineedit2 is full where the new text should be inserted? – eyllanesc Mar 09 '20 at 16:23
  • @eyllanesc if all lineedits receaved an input the insert of new data should stop – Sator Mar 09 '20 at 16:29

1 Answers1

1

You should not execute time-consuming or time-consuming loops in the main thread since they block the event loop. What you must do is execute it on a secondary thread and send the information through signals. To obtain the data sequentially you can create an iterator and access each element through the next() function

import sys
import threading
import time

import serial

from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg


class SerialWorker(qtw.QObject):
    dataChanged = qtw.pyqtSignal(str)

    def start(self):
        threading.Thread(target=self._execute, daemon=True).start()

    def _execute(self):
        try:
            my_serial = serial.Serial(
                port="COM6",
                baudrate=2400,
                bytesize=7,
                parity=serial.PARITY_NONE,
                timeout=None,
                stopbits=1,
            )
            while my_serial.is_open:
                data = my_serial.read()  # wait forever till data arives
                time.sleep(1)  # delay
                data_left = my_serial.inWaiting()
                data += my_serial.read(data_left)
                data = data.decode("utf-8", "strict")
                print(data)
                self.dataChanged.emit(data)
        except serial.serialutil.SerialException:
            print("not open")


class Widget(qtw.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.resize(300, 210)
        self.get_output__button = qtw.QPushButton("start function ?")
        self.device_input1 = qtw.QLineEdit()
        self.device_input2 = qtw.QLineEdit()
        # Layout
        vboxlaout = qtw.QVBoxLayout(self)
        vboxlaout.addWidget(self.get_output__button)
        vboxlaout.addWidget(self.device_input1)
        vboxlaout.addWidget(self.device_input2)

        self.serial_worker = SerialWorker()

        self.device_iterator = iter([self.device_input1, self.device_input2])

        self.get_output__button.clicked.connect(self.serial_worker.start)
        self.serial_worker.dataChanged.connect(self.on_data_changed)

    @qtw.pyqtSlot(str)
    def on_data_changed(self, data):
        try:
            device = next(self.device_iterator)
            device.setText(data)
        except StopIteration:
            pass


if __name__ == "__main__":
    app = qtw.QApplication(sys.argv)
    w = CustmClass()
    w.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • thank you very much @eyllanesc ! , tried to avoid threading so far I guess I need to dive into it know – Sator Mar 10 '20 at 07:40