PyQt倒计时器 - 通过套接字连接从另一个应用程序启动

时间:2018-01-18 12:47:07

标签: python pyqt pyqt5 python-3.6

我想在python中创建一个倒数计时器应用程序。 我在PyQt中创建了一个计时器,现在我不想通过发送信号和套接字连接来设置计时并从另一个应用程序启动此计时器。

这是我的代码。 Gui是在QtCreator中生成的

Server.py

import socket
import sys
import time
import datetime

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread

from serwer_gui import Ui_MainWindow


class MyForm(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        # Syglany i sloty
        self.ui.pushButtonKlientClose.clicked.connect(self.close_client)
        self.ui.pushButtonCzasStart.clicked.connect(self.start_count)

    def close_client(self):
        c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        c.connect(("127.0.0.1", 1234))
        c.send("zamknij;".encode())
        c.close()
        return

    def start_count(self):
        ilosc_minut = self.ui.spinBoxTime.value()
        print(ilosc_minut)
        c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        c.connect(("127.0.0.1", 1234))
        c.send(("czas_set;10").encode())
        c.close()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    myapp = MyForm()
    myapp.show()
    sys.exit(app.exec_())

和Client.py

import socket
import sys
import time

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread

from klient_gui import Ui_MainWindow


class MyForm(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        # Pelen ekran
        # self.showFullScreen()
        self.showMaximized()
        self.timer = QtCore.QTimer(self)
        self.polaczenie = Polaczenie(self)
        self.polaczenie.start()
        #self.start_linczik(20)

    def updateLCD(self):
        # Update the lcd
        self.start_time -= 1
        if self.start_time >= 0:
            self.ui.lcdNumber.display("%d:%02d" % (self.start_time / 60, self.start_time % 60))
        else:
            self.timer.stop()

    def start_linczik(self, b):
        self.start_time = b
        self.ui.lcdNumber.display("%d:%02d" % (self.start_time / 60, self.start_time % 60))
        self.timer.start(1000)
        self.timer.timeout.connect(self.updateLCD)

class Polaczenie(QtCore.QThread):
    sig = QtCore.pyqtSignal(str,str)
    def __init__(self, parent):
        super(Polaczenie, self).__init__(parent)
        self.ui = parent.ui
        self.parent = parent
        self.sig.connect(self.event_dispatcher)

    def run(self):
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        ip = "127.0.0.1"
        port = 1234
        adress = (ip, port)
        server.bind(adress)
        server.listen(1)

        while True:
            print("Start listenint on ", ip, " on ", port)
            (client, addr) = server.accept()
            print("Got connection from ", addr[0], ":", addr[1])
            data = client.recv(1024)
            data = data.decode()
            print("Recived ", data, " from the client")
            print("Processin data")
            indeks_srednik = data.index(";")
            instrukcja = data[:indeks_srednik]
            try:
                string = data[indeks_srednik+1:]
            except Exception as e:
                print(e)
            try:
                print(instrukcja)
                print(string)
                if instrukcja == "zamknij":
                    # Zamykanie aplikacji przy pomocy serwera
                    server.close()
                    sys.exit(0)
                elif instrukcja == "czas_set":
                    self.sig.emit("czas_set", string)
            except Exception as e:
                print(e)

    def event_dispatcher(self, a, b):
        # funkcja dispatchujaca eventy
        if a == "czas_set":
            print("licznik start")
            print(a)
            print(b)
            b=int(b)
            MyForm().start_linczik(b)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    myapp = MyForm()
    myapp.show()
    sys.exit(app.exec_())

我想要实现的是当我从server.py通过套接字(例如czas_set; 60)发送到klient.py消息时,然后klient.py设置倒计时时间,并开始倒计时。 现在,当我运行我的程序时,我可以发送消息,但计时器不会启动。只有应用程序冻结并失败。 当我从MyForm类启动计时器 init 时,计时器工作正常。只有当我想通过套接字从另一个thred运行它时它才会失败 我做错了什么?我该如何解决这个问题呢?

在Windows 7和python 3.6上测试

1 个答案:

答案 0 :(得分:0)

问题是由于运行MyForm().Start_linczik(b)正在创建另一个窗口而引起的,此窗口将创建一个具有相同端口的服务器,该端口会因端口忙而生成错误。

你应该做的是用现有对象调用函数start_linczik,为此我们可以使用信号,或者在这种情况下我会显示QMetaObject::invokeMethod()的使用但为此你必须使用插槽中的装饰器pyqtSlot(),这有利于减少内存消耗并使应用程序更快一些。

class MyForm(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        [...]

    @QtCore.pyqtSlot()
    def updateLCD(self):
        [...]

    @QtCore.pyqtSlot(int)
    def start_linczik(self, b):
        [...]

没有必要将parentparent.ui保存在变量中,因为您可以通过parent()方法访问父级。

class Polaczenie(QtCore.QThread):
    sig = QtCore.pyqtSignal(str,str)
    def __init__(self, parent):
        super(Polaczenie, self).__init__(parent)
        self.sig.connect(self.event_dispatcher)

    def run(self):
        [...]

    def event_dispatcher(self, a, b):
        # funkcja dispatchujaca eventy
        if a == "czas_set":
            print("licznik start")
            print(a)
            print(b)
            b=int(b)
            #MyForm().start_linczik(b)
            QtCore.QMetaObject.invokeMethod(self.parent(), "start_linczik", 
                QtCore.Qt.QueuedConnection, QtCore.Q_ARG(int, b))