Python Forum
[PyQt4] Is it right python coding scheme between TCP Server Thread and GUI class ? - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: GUI (https://python-forum.io/forum-10.html)
+--- Thread: [PyQt4] Is it right python coding scheme between TCP Server Thread and GUI class ? (/thread-12867.html)



[PyQt4] Is it right python coding scheme between TCP Server Thread and GUI class ? - KimTom - Sep-17-2018

Hi, I want to make GUI program that is a TCP image server.
I make a GUI frame using a QT desinger .

It works fine though, I am not used to programming with python.
I wondering it is right way..

TCP Server performs TCP server thread. When it finished to download a file, sending signals to Dialog to Refresh.
And Progress bar is also programmed using signal/slot.

Is there an idea to be better..?

# -*- coding: utf-8 -*-


from PyQt4.QtGui import *
import sys
import os
from PyQt4 import QtCore, QtGui
import socketserver
from os.path import exists
import time, datetime
import threading
from PIL import Image
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
from PyQt4.QtCore import *

HOST = ''
PORT = 7777
progressBar_statusValue =0

# MyDiag.py 모듈 import
import test1

class MySignal(QtCore.QObject):
    signal1 = QtCore.pyqtSignal(QtCore.QObject)
    def run(self):
        self.signal1.emit(self)

class MySignal2(QtCore.QObject):
    signal2 = QtCore.pyqtSignal(QtCore.QObject)
    def run(self):
        self.signal2.emit(self)

mysignal = MySignal()
mysignal2 = MySignal2()

# MyDiag 모듈 안의 Ui_MyDialog 클래스로부터 파생
class XDialog(QDialog, test1.Ui_Dialog):
    global progressBar_statusValue

    def __init__(self):
        QDialog.__init__(self)
        # setupUi() 메서드는 화면에 다이얼로그 보여줌
        self.setupUi(self)
        self.pushButton.clicked.connect(self.run)
        self.pushButton_2.clicked.connect(self.imageRefresh) 
        
        mysignal.signal1.connect(self.imageRefresh)
        mysignal2.signal2.connect(self.resetProgressbar)

    def run(self):
        runServer()
        while progressBar_statusValue < 100:
            self.progressBar.setValue(progressBar_statusValue)
        self.progressBar.setValue(100)
		
    @pyqtSlot()
    def imageRefresh(self):
        #self.setupUi.label.setText("첫번째 버튼")
        im = Image.open('download/test.jpg') # Image Open & Resize
        size = (500,500)
        im.thumbnail(size)
        im.save('download/test.jpg')         # added by tom
        self.label.setPixmap(QPixmap("download/test.jpg"))

    @pyqtSlot()
    def resetProgressbar(self):
        while progressBar_statusValue < 100:
            self.progressBar.setValue(progressBar_statusValue)
        self.progressBar.setValue(100)

class MyTcpHandler(socketserver.BaseRequestHandler):
    def handle(self):
        global progressBar_statusValue
        dataTransferred = 0
        print('[Connected to: %s]' %self.client_address[0])
		
        fileInfo = self.request.recv(1024) # 클라이언트로 부터 파일이름을 전달받음
        fileInfo = fileInfo.decode() # 파일이름 이진 바이트 스트림 데이터를 일반 문자열로 변환
		
        fileInfo_parsing = fileInfo.split(',')
        fileName = fileInfo_parsing[0]
        fileSize = fileInfo_parsing[1]
        print('[fileSize] : ', str(fileSize))

        f = open('download/' + fileName, 'wb')
        data = self.request.recv(4096)
        cur_time = datetime.datetime.now()
        mysignal2.run()
        while  data:
            f.write(data)
            dataTransferred += len(data)
            progressBar_statusValue = ( dataTransferred/int(fileSize) ) * 100
            data = self.request.recv(4096)
        cur_time1 = datetime.datetime.now()

        print('[recved time] : ', str(cur_time))
        print('[recved1 time] : ', str(cur_time1))
        print('[File]: %s , [Size]: %d Bytes' %(fileName, dataTransferred))
        print('[Comeplete]')
        print('[recving time] : ', str(cur_time1-cur_time))
        mysignal.run() 

def runServer():
    print('[Server Start]')
    print("[To terminate, Press 'Ctrl + C']")
 
    try:
        server = socketserver.TCPServer((HOST,PORT),MyTcpHandler)
        #server.serve_forever()
        threading.Thread(target=server.serve_forever).start()
    except KeyboardInterrupt:
        print('[Terminate]')	

app = QApplication(sys.argv)
dlg = XDialog()
dlg.show()
app.exec_()



RE: [PyQt4] Is it right python coding scheme between TCP Server Thread and GUI class ? - Alfalfa - Sep-17-2018

Some improvements would be worthwhile before adding new features. First off, you should clean the imports and avoid using wildcards (from PyQt4.QtGui import *), as it makes the code harder to read and increase the risk of name collisions.

Also, you pass a QObject into your signals, but you don't use it in your slot. Instead, you can simply skip the arguments:

signal1 = QtCore.pyqtSignal()
self.signal1.emit()
Finally, you should move your TCP thread into a QThread, with Qt's moveToThread() method. As shown here.


RE: [PyQt4] Is it right python coding scheme between TCP Server Thread and GUI class ? - KimTom - Sep-18-2018

Thank you Alfalfa!!:)
It is really helpful to me.

May I ask a one more question..?

I create an instance in global field to use the instance in Xdialog class and TCP Thread like below.


mysignal = MySignal()
mysignal2 = MySignal2()
Is it normal coding style? Is there a more efficient way?
Thanks a lot!!!!


RE: [PyQt4] Is it right python coding scheme between TCP Server Thread and GUI class ? - Alfalfa - Sep-18-2018

It is fine to create your gui instance (XDialog) in global, but instead you might want to put the launching code in main() right away, in case you would like to make a package in the future (see here). Also, you shouldn't put your signal in empty class (MySignal and MySignal2), they should be declared into your worker thread (MyTCPHandler), which should be a QObject. Init the object from your gui loop and connect the signals directly:

self.tcpHandler = MyTcpHandler(self)
self.tcpHandler.signal1.connect(self.imageRefresh)
...
Also, avoid using global variables (such as global progressBar_statusValue). Instead of using threading module, initiate the thread in your gui loop and pass self in your thread instance. Then you can refer directly to the variable of the parent (self.parent.progressBar_statusValue) from the worker thread.