Where is my server side GUI?!(using pyqt)should I use thread? - python

I want to create a simple server/client app using python socket programming and PyQt.The client can send files to the server side.It worked.But I can't see my server side GUI!
After taking the Dikei's advice I changed my server side code by creating a new thread to handle socket part.
Here is my server side code:
#! /usr/bin/python
import sys
import socket
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtNetwork import *
HOST = '127.0.0.1'
PORT = 9996
SIZEOF_UINT32 = 4
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.worker = Worker()
self.connect(self.worker, SIGNAL("received"), self.updateUi)
self.connect(self.worker, SIGNAL("finished()"), self.updateUi)
self.connect(self.worker, SIGNAL("terminated()"), self.updateUi)
# Create widgets/layout
self.browser = QTextBrowser()
self.selectButton = QPushButton('Close server')
layout = QVBoxLayout()
layout.addWidget(self.browser)
layout.addWidget(self.selectButton)
self.setLayout(layout)
self.setWindowTitle("Server")
def updateUi(self, text):
self.browser.append(text)
class Worker(QThread):
def __init__(self,parent = None):
super(Worker, self).__init__(parent)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def receiveFile(self):
self.conn, self.addr = self.socket.accept()
totalData = ''
while 1:
data = self.conn.recv(1024)
if not data: break
totalData += data
print totalData
f = open('/home/jacos/downfrom','w')
f.write(totalData)
f.close()
self.emit(SIGNAL("received"),"received a file")
self.conn.close()
def run(self):
self.socket.bind((HOST, PORT))
self.socket.listen(5)
while 1:
self.receiveFile()
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
here is my client side code:
#! /usr/bin/python
# -*- coding: utf8 -*-
import sys
import socket
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtNetwork import *
HOST = '127.0.0.1'
PORT = 9996
SIZEOF_UINT32 = 4
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
# Create widgets/layout
self.browser = QTextBrowser()
self.selectButton = QPushButton('Send a File')
self.connectButton = QPushButton("Connect")
self.connectButton.setEnabled(True)
layout = QVBoxLayout()
layout.addWidget(self.browser)
layout.addWidget(self.selectButton)
layout.addWidget(self.connectButton)
self.setLayout(layout)
# Signals and slots for line edit and connect button
self.selectButton.clicked.connect(self.sendFile)
self.connectButton.clicked.connect(self.connectToServer)
self.setWindowTitle("Client")
# Update GUI
def updateUi(self, text):
self.browser.append(text)
def sendFile(self):
filename=QFileDialog.getOpenFileName(self, 'Open File', '.')
self.socket.sendall(open(filename,'rb').read())
self.updateUi("Sent a file:" + filename)
self.socket.close()
self.connectButton.setEnabled(True)
def connectToServer(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((HOST, PORT))
self.connectButton.setEnabled(False)
self.updateUi("Connected")
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
The problems are:
My server side GUI doesn't appear at all!I don't understand
why. Should I use thread?
Also, the server only stores the file in a fixed place with a fixed
name. Is there any way I can specify the location in the server side
and get the original file name from client side?
Edit:Now #1 is solved but the signal emitted by the thread doesn't seem to be caught at all, the browser of the server isn't updated at all.
The #2 is still not solved.
Thanks for any help!

Your program is stuck in an infinite loop
while 1:
self.receiveFile()
The form.show() is never reached.
You should probably do everything in a different thread and send signal back to main thread which run the GUI.
For the second problem, you can send the filename first before sending the data. When the server receive the filename, the worker thread will emit a signal. This signal will trigger the main thread to pop up a QFileDialog for you to select a folder. After the folder is selected, the main thread will send a signal with the folder path to the worker thread and the worker thread can save the file.

Related

create multiple thread for read and write with PyQt5

I write a code with PyQt5 for send and receive data via serial port. when a button pressed, data sends without any problem. in receive, data packet length is different in every time and time between any send is random. I create a thread for read serial port buffer in while loop and if data was received, then put that in a global queue. in other thread , queue will be checked and if it is not empty, some process will be done on data.
but when I test program and send data to application , the bellow error display and application crash.
the error:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTextDocument(0x1d1166f7620), parent's thread is QThread(0x1d116712ff0), current thread is
QThread(0x1d1166f7560)
here is the main part of code:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
import errordialog as D1
import serial
import serial.tools.list_ports
import threading
import queue
class Ui_Form(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def setupUi(self, Form):
self.q = queue.Queue()
.
.
.
def open_port(self):
if self.comboBoxPORT.count()==0:
dialog.exec_()
else:
self.ser.port = self.comboBoxPORT.currentText()
b=int(self.lineEditBaudrate.text())
if b==0:
self.ser.baudrate = 9600
else:
self.ser.baudrate = int(self.lineEditBaudrate.text())
try:
self.ser.open()
self.pushButtonClose.setEnabled(True)
self.pushButtonOpen.setEnabled(False)
self.pushButtonOpen.setStyleSheet("background-color: lime")
self.pushButtonSend.setEnabled(True)
self.comboBoxPORT.setEnabled(False)
self.lineEditBaudrate.setEnabled(False)
self.textEditReceived.setReadOnly(False)
g=threading.Thread(target=ui.read_data)
e=threading.Thread(target=ui.printData)
g.start()
e.start()
except:
dialog.exec_()
def read_data(self):
while True:
t = self.ser.read().decode()
if t:
self.q.put(t)
def printData(self):
while True:
while not self.q.empty():
print(self.q.get())
self.textEditReceived.setText(self.q.get())
def close_port(self):
try:
self.ser.close()
self.pushButtonClose.setEnabled(False)
self.pushButtonOpen.setEnabled(True)
self.pushButtonOpen.setStyleSheet("background-color: azure")
self.pushButtonSend.setEnabled(False)
self.comboBoxPORT.setEnabled(True)
self.lineEditBaudrate.setEnabled(True)
except:
dialog.exec_()
def send(self):
self.ser.write(str.encode(self.textEditSent.toPlainText()))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
##============= add error dialog
d1 = D1.Ui_DialogError()
dialog = QtWidgets.QDialog()
d1.setupUi(dialog)
##---======================----------
ui.pushButtonOpen.clicked.connect(lambda : ui.open_port())
d1.pushButtonCanceError.clicked.connect(lambda: dialog.close())
ui.pushButtonExit.clicked.connect(lambda: Form.close())
ui.pushButtonClose.clicked.connect(lambda: ui.close_port())
ui.pushButtonSend.clicked.connect(lambda: ui.send())
##=============-----------------
##----------====================
sys.exit(app.exec_())

How to keep PyQt5 UI responsive while waiting for serial feedback?

I'm developing a simple software where serial would be feeding back information and update on UI.
This software will be running in Raspbian Jessie, Python 3.4, PyQt5 and Pyserial.
This UI is drawn via Qt Designer and converted via pyuic.
The purpose of this software is to monitor 4 step motors that attached to my Pi, via MCU chip, and the serial information is from this MCU. I am not using Pi's GPIO as they has their other usage.
I wanted to get the text displayed on screen once the serial buffer is filled with information, for now.
I had tried the following code, but it's not good enough as I have to depend on timer to check on serial read. Is there another more efficient way to get the texts on screen once the serial port had received information?
import sys, datetime
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QWidget
#import UI drawn from QtDesigner
from QFrame.Main_btn6 import Ui_MainWindow
import serial
def setupserial(object):
com = serial.Serial(port = "/dev/ttyUSB0",
baudrate = 115200,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 3) #ms
return (com)
class Form_Operation(QtWidgets.QMainWindow):
def __init__(self, parent = None):
QWidget.__init__(self, parent)
self.timer = QtCore.QTimer(self)
self.ui = Ui_MainWindow()
self.serialcom = setupserial()
self.timer.setInterval(10)
self.timer.timeout.connect(self.hidden)
self.ui.setupUi(self)
self.initUI()
def initUI(self):
self.ui.MainDisplay.setText("Output from Serial comn.")
Exit = self.ui.Btn_Exit
Exit.clicked.connect(self.Exit_buttonClicked)
Clear = self.ui.Btn_Clear
Clear.clicked.connect(self.Clear_buttonClicked)
def hidden(self):
"""
Get texts from serial
"""
self.comread = self.com.readline().decode()
self.ui.MainDisplay.setText(self.comread)
def Exit_buttonClicked(self):
sys.exit()
def Clear_buttonClicked(self):
"""
Click to clear
"""
self.ui.MainDisplay.setText("")
def close(self):
self.timer.stop()
self.destroy()
def show(self):
self.timer.start()
self.showFullScreen()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
start = Form_Operation()
start.show()
sys.exit(app.exec_())

PyQt SimpleHTTPServer: GUI freezes on starting server

I am trying to create a simple desktop app using PyQt that runs a SimpleHTTPServer on clicking a start server button. I have tried using threads(both python threads and Qthread) and understand that this is not possible as it runs into issues with the GIL. Here's the code
def btn_startserver_clicked(self):
server_thread=threading.Thread(target=start_server())
server_thread.start()
def start_server():
#to get server's IP
host=([(s.connect(('8.8.8.8', 80)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1])
start=8000
end=56999
PORT = random.randint(start,end)
print host,":",PORT
httpd=ThreadedServer(("",PORT), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd.handle_request()`
I tried creating another process but the same thing happened. Also, if I create another process a new window pops up each time a request is served.
def btn_startserver_clicked(self):
if __name__=='__main__':
server_process=Process(target=start_server())
server_process.start()
Is there any way around this? I feel using multiprocessing is the right approach but I am new to this and can't figure out why it still freezes.
Thanks
The issue with your examples that lock the GUI is that rather than passing a reference to the function when creating the thread, you are actually running the function immediately and the thread is never created. For example, you should be doing:
server_thread=threading.Thread(target=start_server)
Note that I drop the brackets on start_server otherwise the code waits for start_server() to finish executing before creating the threading.Thread object, and uses the return value from start_server() as the value for the target attribute.
A final suggestion, you should really store the created thread as self.server_thread to prevent it from being garbage collected.
Not exactly sure what you're trying to do, but this might help you get started:
import sys
from urllib.request import urlopen
from http.server import HTTPServer, SimpleHTTPRequestHandler
from PyQt4 import QtCore, QtGui
HOST, PORT = '127.0.0.1', 12345
class HttpDaemon(QtCore.QThread):
def run(self):
self._server = HTTPServer((HOST, PORT), SimpleHTTPRequestHandler)
self._server.serve_forever()
def stop(self):
self._server.shutdown()
self._server.socket.close()
self.wait()
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.button = QtGui.QPushButton('Start', self)
self.button.clicked.connect(self.handleButton)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.button)
self.httpd = HttpDaemon(self)
def handleButton(self):
if self.button.text() == 'Start':
self.httpd.start()
self.button.setText('Test')
else:
urlopen('http://%s:%s/index.html' % (HOST, PORT))
def closeEvent(self, event):
self.httpd.stop()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

PyQt GUI control access from another thread

i'm trying to create an client server application in python. When the server closes i wish the gui of the client wich is on a separate thread to close, but the application crushes with Xlib error: bad implementation... I've searched and seems to be from accessing GUI interface from other thread. What should I do?python gui access from other thread
this might help you..
from PyQt4 import QtGui as gui
from PyQt4 import QtCore as core
import sys
import time
class ServerThread(core.QThread):
def __init__(self, parent=None):
core.QThread.__init__(self)
def start_server(self):
for i in range(1,6):
time.sleep(1)
self.emit(core.SIGNAL("dosomething(QString)"), str(i))
def run(self):
self.start_server()
class MainApp(gui.QWidget):
def __init__(self, parent=None):
super(MainApp,self).__init__(parent)
self.label = gui.QLabel("hello world!!")
layout = gui.QHBoxLayout(self)
layout.addWidget(self.label)
self.thread = ServerThread()
self.thread.start()
self.connect(self.thread, core.SIGNAL("dosomething(QString)"), self.doing)
def doing(self, i):
self.label.setText(i)
if i == "5":
self.destroy(self, destroyWindow =True, destroySubWindows = True)
sys.exit()
app = gui.QApplication(sys.argv)
form = MainApp()
form.show()
app.exec_()

How to access GUI elements from another thread in PyQt

I'm trying to create a client-server application, and when the server closes I wish that client GUI to close, which is running on another thread. I wish to access the GUI and close but I get X error:
Bad implementation(...).
How can I resolve this problem?
what you can do is emit a custom signal when the first thread goes down..
from PyQt4 import QtGui as gui
from PyQt4 import QtCore as core
import sys
import time
class ServerThread(core.QThread):
def __init__(self, parent=None):
core.QThread.__init__(self)
def start_server(self):
for i in range(1,6):
time.sleep(1)
self.emit(core.SIGNAL("dosomething(QString)"), str(i))
def run(self):
self.start_server()
class MainApp(gui.QWidget):
def __init__(self, parent=None):
super(MainApp,self).__init__(parent)
self.label = gui.QLabel("hello world!!")
layout = gui.QHBoxLayout(self)
layout.addWidget(self.label)
self.thread = ServerThread()
self.thread.start()
self.connect(self.thread, core.SIGNAL("dosomething(QString)"), self.doing)
def doing(self, i):
self.label.setText(i)
if i == "5":
self.destroy(self, destroyWindow =True, destroySubWindows = True)
sys.exit()
app = gui.QApplication(sys.argv)
form = MainApp()
form.show()
app.exec_()

Categories