Использование QLineEdit.setText () останавливает окно, но фоновые задачи работают нормально - PullRequest
0 голосов
/ 18 мая 2018

Я пытаюсь создать программу для чата как обычный проект, чтобы лучше понять PyQt5 и многопоточность, но я столкнулся с довольно странной проблемой.Внутри класса sWindow , в функции createserver () , setText () на дисплееВиджет в блоке try останавливает экран, но фоновые процессы работают нормально.Функция setText в блоке , за исключением , работает нормально.Если я попытаюсь напечатать операторы в cmd, он будет работать отлично.

Вот фрагмент кода, в котором я столкнулся с проблемой:

def createServer(self):
    try:
        self.display.setText("Creating server") #doesn't display text, whole screen freezes
        print("Creating Server") #works fine
        self.s.bind((self.host, self.port))
        self.s.listen(10)
        print("Server Created") #works fine
        self.display.append("Server Created.") #doesn't print anything
        self.display.append("Started listening to clients")
        self.Listen() #goes into the listen function as well without display widget printing anything
    except Exception as e:
        print(e)
        self.display.setText("Error occured")

Вот весь код:

class sWindow(QMainWindow):
def __init__(self, title = "File Sharing", l = 0, t = 0, r = 800, b = 600):
    super().__init__()
    self.left = l
    self.right = r
    self.top = t
    self.bottom = b
    self.title = title
    self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    self.host = ""
    self.port = 15478
    self.ip_add = socket.gethostbyname(socket.getfqdn())
    self.initUi()
    self.shutting = False
    self.mode = 0
    self.address = {}
    self.clientaddr = {}
    self.buffsize = 2048
    self.encoding = 'utf8'




def closeEvent(self, event):
    reply = QMessageBox.question(self, "Message Box", "Are you sure?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
    if reply == QMessageBox.Yes:
        self.shutting = True
        self.s.close()
        event.accept()
    else:
        event.ignore()


def createServer(self):
    try:
        self.display.setText("Creating server")
        print("Creating Server")
        self.s.bind((self.host, self.port))
        self.s.listen(10)
        print("Server Created")
        self.display.append("Server Created.")
        self.display.append("Started listening to clients")
        self.Listen()
    except Exception as e:
        print(e)
        self.display.setText("Error occured")


def Listen(self):
    try:
        print("started listenting")
        while self.shutting == False:
            client, addr = self.s.accept()
            self.address[client] = addr
            message = "Enter your name: "
            client.send(message.encode(encoding))
            threading.Thread(target = handleclient, args = (client,)).start()
    except Exception as e:
        print('Error occured while creating server. ',e)



def handleclient(self, client):
    try: 
        name = client.recv(buffsize).decode(encoding)
        self.display.append(name + " connected from address ", addr)
        self.clientaddr[client] = name
        message = "Welcome " + name + "!! You have entered the chatroom."
        client.send(message.encode(encoding))
        message = name + "has entered the chatroom. "
        self.broadcast(message, client)
        while self.shutting == False:
            data = client.recv(buffsize).decode(encoding)
            self.display.append(name + ': ' + data)
            self.broadcast(data, client)


    except Exception as e:
        del self.address[client]
        del self.clientaddr[client]
        self.display.append('Error occured while connecting to client. ',e)
        message = name + " entered the chatroom."
        self.broadcast(message.encode(encoding), False)
        return


def broadcast(self, mesage, client):
    try:
        for sock in self.address.keys():
            if sock != client:
                sock.send(message)
    except Exception as e:
        self.display.append("Error occured while broadcasting the message to clients. ", e)
        print(e)
        return




def centr(self):
    qr = self.frameGeometry()
    cr = QDesktopWidget().availableGeometry().center()
    qr.moveCenter(cr)
    self.move(qr.topLeft())

def initUi(self):
    ## For window

    self.setGeometry(self.left, self.top, self.right, self.bottom)
    self.centr()
    self.setWindowTitle(self.title)
    self.setWindowIcon(QIcon("fSharing.jpg"))

    ## For layout

    self.setCentralWidget(QWidget(self))
    self.grid = QGridLayout()
    self.grid.setSpacing(10)
    self.centralWidget().setLayout(self.grid)

#def createServer(self):


def mainWindow(self):
    ## buttons
    global ip
    self.connect = QPushButton("Connect")
    self.connect.setToolTip("Connect to the server")
    self.connect.resize(self.connect.sizeHint())

    self.create = QPushButton("Create Server")
    self.create.setToolTip("Create server for others to connect")
    self.create.resize(self.create.sizeHint())
    self.create.clicked.connect(self.createServer)

    self.chooseFile = QPushButton("Choose File")
    self.chooseFile.setToolTip("Choose the file you want to send.")
    self.chooseFile.setEnabled(False)
    self.chooseFile.resize(self.chooseFile.sizeHint())

    self.send = QPushButton("Send")
    self.send.setEnabled(False)
    self.send.resize(self.send.sizeHint())

    self.sendFile = QPushButton("Send File")
    self.sendFile.setToolTip("Send the selected file")
    self.sendFile.setEnabled(False)
    self.sendFile.resize(self.sendFile.sizeHint())


    ## text Fields

    self.ip = QLineEdit()
    self.ip.setPlaceholderText("Ex: 192.168.0.1")

    self.display = QTextEdit()
    self.display.setReadOnly(True)

    self.sendText = QTextEdit()

    ## Label

    self.lbl = QLabel()
    self.lbl.setText(" Or ")

    self.grid.addWidget(self.create, 0,3 )
    self.grid.addWidget(self.lbl, 0,5)
    self.grid.addWidget(self.ip, 0,7)
    self.grid.addWidget(self.connect,0,9)
    self.grid.addWidget(self.display, 1, 1, 8, 7)
    self.grid.addWidget(self.chooseFile, 2, 9)
    self.grid.addWidget(self.sendFile, 4, 9)
    self.grid.addWidget(self.sendText, 9, 1, 2, 7)
    self.grid.addWidget(self.send, 9,9)
    self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = sWindow()
    win.mainWindow()
    sys.exit(app.exec())

1 Ответ

0 голосов
/ 18 мая 2018

Qt, чтобы иметь возможность обрабатывать события и задачи, которые необходимо выполнить, создать цикл событий, в простом описании цикл событий представляет собой некоторое время True, внутри которого он просматривает различные события, такие как мышь, клавиатура, событиясозданный пользователем и т. д. И вы создаете свой сервер, создавая цикл, который блокирует цикл обработки событий, и, следовательно, означает, что графический интерфейс не может обрабатывать эти задачи и останавливается при подаче сигнала.

Как вы создаетепотоки, так что связь с клиентами не блокирует сервер, то же самое должно быть сделано с сервером в отношении GUI, но это приносит с собой неудобство: GUI не может быть обновлен из другого потока (в вашем случае self.display.setText() илиself.display.append() перерисовывает текст GUI), Qt рекомендует использовать сигналы, и для этого лучше отделить, в этом случае я создал класс Manager, который наследуется от QObject, чтобы он мог создавать сигналы и администрироватьсервер:

import sys
import socket
import threading

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class Manager(QObject):
    logSignal = pyqtSignal(str)
    def __init__(self, parent=None):
        QObject.__init__(self, parent)
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.address = {}
        self.clientaddr = {}
        self.shutting = False
        self.encoding = 'utf8'
        self.buffsize = 2048

    def create_server(self, host, port):
        try:
            self.logSignal.emit("Creating server")
            print("Creating Server")
            self.s.bind((host, port))
            self.s.listen(10)
            print("Server Created")
            self.logSignal.emit("Server Created.")
            self.logSignal.emit("Started listening to clients")
            self.listen()
        except Exception as e:
            print(e)
            self.logSignal.emit("Error occured")

    def listen(self):
        try:
            print("started listenting")
            while self.shutting == False:
                client, addr = self.s.accept()
                self.address[client] = addr
                message = "Enter your name: "
                client.send(message.encode(self.encoding))
                threading.Thread(target =self.handleclient, args = (client,), daemon=True).start()
        except Exception as e:
            print('Error occured while creating server. ',e)

    def handleclient(self, client):
        try: 
            name = client.recv(self.buffsize).decode(self.encoding)
            self.logSignal.emit(name + " connected from address " + str(self.address[client]))
            self.clientaddr[client] = name
            message = "Welcome " + name + "!! You have entered the chatroom."
            client.send(message.encode(self.encoding))
            message = name + "has entered the chatroom. "
            self.broadcast(message, client)
            while self.shutting == False:
                data = client.recv(self.buffsize).decode(self.encoding)
                self.logSignal.emit(name + ': ' + data)
                self.broadcast(data, client)

        except Exception as e:
            del self.address[client]
            del self.clientaddr[client]
            self.logSignal.emit('Error occured while connecting to client. ' + str(e))
            message = name + " entered the chatroom."
            self.broadcast(message.encode(self.encoding), False)

    def broadcast(self, mesage, client):
        try:
            for sock in self.address.keys():
                if sock != client:
                    sock.send(message)
        except Exception as e:
            self.logSignal.emit("Error occured while broadcasting the message to clients. ", e)
            print(e)

    def stop(self):
        self.shutting = True
        self.s.close()

class sWindow(QMainWindow):
    def __init__(self, title = "File Sharing"):
        super().__init__()
        self.initUi()

        self.port = 15478
        self.manager = Manager()
        self.manager.logSignal.connect(self.display.append)

    def initUi(self):
        self.resize(800, 600)
        self.setWindowTitle("File Sharing")
        self.setWindowIcon(QIcon("fSharing.jpg"))
        self.setCentralWidget(QWidget(self))
        self.grid = QGridLayout(self.centralWidget())
        self.grid.setSpacing(10)
        self.setup()

    def setup(self):
        self.connect = QPushButton("Connect")
        self.connect.setToolTip("Connect to the server")
        self.connect.resize(self.connect.sizeHint())

        self.create = QPushButton("Create Server")
        self.create.setToolTip("Create server for others to connect")
        self.create.resize(self.create.sizeHint())
        self.chooseFile = QPushButton("Choose File")
        self.chooseFile.setToolTip("Choose the file you want to send.")
        self.chooseFile.setEnabled(False)
        self.chooseFile.resize(self.chooseFile.sizeHint())

        self.send = QPushButton("Send")
        self.send.setEnabled(False)
        self.send.resize(self.send.sizeHint())

        self.sendFile = QPushButton("Send File")
        self.sendFile.setToolTip("Send the selected file")
        self.sendFile.setEnabled(False)

        self.ip = QLineEdit()
        self.ip.setPlaceholderText("Ex: 192.168.0.1")

        self.display = QTextEdit()
        self.display.setReadOnly(True)

        self.sendText = QTextEdit()

        self.lbl = QLabel()
        self.lbl.setText(" Or ")

        self.grid.addWidget(self.create, 0,3 )
        self.grid.addWidget(self.lbl, 0,5)
        self.grid.addWidget(self.ip, 0,7)
        self.grid.addWidget(self.connect,0,9)
        self.grid.addWidget(self.display, 1, 1, 8, 7)
        self.grid.addWidget(self.chooseFile, 2, 9)
        self.grid.addWidget(self.sendFile, 4, 9)
        self.grid.addWidget(self.sendText, 9, 1, 2, 7)
        self.grid.addWidget(self.send, 9,9)
        self.centr()

        self.create.clicked.connect(self.on_create)

    def on_create(self):
        threading.Thread(target = self.manager.create_server, daemon=True, args = (self.ip.text(), self.port)).start()

    def closeEvent(self, event):
        reply = QMessageBox.question(self, "Message Box", "Are you sure?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.manager.stop()
            event.accept()
        else:
            event.ignore()

    def centr(self):
        qr = self.frameGeometry()
        cr = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cr)
        self.move(qr.topLeft())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = sWindow()
    win.show()
    sys.exit(app.exec())

Примечание: с другой стороны, если вы делаетене желая иметь дело с потоками, Qt предлагает классы, такие как QTcpServer и QTcpSocket, для обработки соединений без блокировки цикла событий дружественным Qt способом.Вы можете найти пример чата с этими классами: http://doc.qt.io/qt-5/qtnetwork-network-chat-connection-cpp.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...