使用PyQt的线程终端

时间:2012-05-08 18:08:24

标签: python pyqt pyqt4 pyserial

我正在尝试构建一个PyQt应用程序(其中包括)通过QTextEdit Box的功能就像一个串行终端程序(HyperTerminal,TeraTerm等)。我已经通过一些例子来阅读PySerial页面,我想我已经设法让接收数据线程正常工作,但可能没有尽可能高效。

我的问题是如何获取QTextEdit框中的最后一个类型字符并将其发送出串口连接?我已经尝试使用QTextEdit发出的textChanged信号,但是然后它会发送我键入的所有内容以及它收到的内容。我已经尝试在我的主GUI类中设置eventFilter,但我无法弄清楚如何将其转换为另一个文件中的串行函数。我是否想要一个单独的线程来监听eventFilter发出的信号?我怎么做?有更优雅的方式吗?

我确信我已经设法过度思考这个并且解决方案很简单,但我有点挣扎。我将附上相关的代码片段(不是完整的代码集),也许有人可以指出我正确的方向。如果有人也认为我正在做的线程可以更有效的方式完成,那么请转发给我!

感谢任何人提供的任何帮助!

主档案:

import sys
from PyQt4 import QtGui
from MainGUI import TestGUI
from SerialClasses import *
from SerialMiniterm import *

class StartMainWindow(QtGui.QMainWindow):      
    def __init__(self, parent=None):
        super(StartMainWindow, self).__init__(parent)
        self.ui = TestGUI()
        self.ui.setupUi(self)    
        self.ui.serialTextEditBox.installEventFilter(self)

    def eventFilter(self, source, event):
        if (event.type() == QtCore.QEvent.KeyPress and source is self.ui.serialTextEditBox):
            # print some debug statements to console
            if (event.key() == QtCore.Qt.Key_Tab):
                print ('Tab pressed')
            print ('key pressed: %s' % event.text())
            print ('code pressed: %d' % event.key())
            # do i emit a signal here?  how do i catch it in thread?
            self.emit(QtCore.SIGNAL('transmitSerialData(QString)'), event.key())
            return True
        return QtGui.QTextEdit.eventFilter(self, source, event)   

    def serialConnectCallback(self):
        self.miniterm = SerialMiniterm(self.ui, self.SerialSettings)
        self.miniterm.start()
        temp = self.SerialSettings.Port + 1
        self.ui.serialLabel.setText("<font color = green>Serial Terminal Connected on COM%d" % temp) 

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    app.setStyle("Cleanlooks")
    myapp = StartMainWindow()
    myapp.show()
    sys.exit(app.exec_())

SerialMiniterm.py:

import serial
from PyQt4 import QtGui, QtCore

def character(b):
    return b

class SerialMiniterm(object):
    def __init__(self, ui, SerialSettings):
        self.SerialSettings = SerialSettings
        self.ui = ui
        self.serial = serial.Serial(self.SerialSettings.Port, self.SerialSettings.BaudRate, parity=self.SerialSettings.Parity, rtscts=self.SerialSettings.RTS_CTS, xonxoff=self.SerialSettings.Xon_Xoff, timeout=1)
        self.repr_mode = self.SerialSettings.RxMode
        self.convert_outgoing = self.SerialSettings.NewlineMode
        self.newline = NEWLINE_CONVERISON_MAP[self.convert_outgoing]
        self.dtr_state = True
        self.rts_state = True
        self.break_state = False

    def _start_reader(self):
        """Start reader thread"""
        self._reader_alive = True
        self.receiver_thread = ReaderThread(self.alive, self._reader_alive, self.repr_mode, self.convert_outgoing, self.serial)
        self.receiver_thread.connect(self.receiver_thread, QtCore.SIGNAL("updateSerialTextBox(QString)"), self.updateTextBox)
        self.receiver_thread.start()

    def _stop_reader(self):
        """Stop reader thread only, wait for clean exit of thread"""
        self._reader_alive = False
        self.receiver_thread.join()

    def updateTextBox(self, q):
        self.ui.serialTextEditBox.insertPlainText(q)
        self.ui.serialTextEditBox.moveCursor(QtGui.QTextCursor.End)
        #print "got here with value %s..." % q

    def start(self):
        self.alive = True
        self._start_reader()
        # how do i handle transmitter thread?

    def stop(self):
        self.alive = False

    def join(self, transmit_only=False):
        self.transmitter_thread.join()
        if not transmit_only:
            self.receiver_thread.join()

class ReaderThread(QtCore.QThread):       
    def __init__(self, alive, _reader_alive, repr_mode, convert_outgoing, serial, parent=None):
        QtCore.QThread.__init__(self, parent)
        self.alive = alive
        self._reader_alive = _reader_alive
        self.repr_mode = repr_mode
        self.convert_outgoing = convert_outgoing
        self.serial = serial

    def __del__(self):
        self.wait()

    def run(self):
        """loop and copy serial->console"""
        while self.alive and self._reader_alive:
            data = self.serial.read(self.serial.inWaiting())
            if data:                            #check if not timeout
                q = data
                self.emit(QtCore.SIGNAL('updateSerialTextBox(QString)'), q)

1 个答案:

答案 0 :(得分:2)

这样的东西?

from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])

class Terminal(QtGui.QPlainTextEdit):
    def keyPressEvent(self, event):
        print event.text()
        return QtGui.QPlainTextEdit.keyPressEvent(self, event)

term = Terminal()
term.show()