2016-04-05 9 views
7

Czytam przez pewną dokumentację na PyQt5, aby wymyślić prosty mechanizm szczeliny sygnału. Zatrzymałem się z powodu rozważań projektowych.PyQt właściwe użycie emit() i pyqtSignal()

Rozważmy następujący kod:

import sys 
from PyQt5.QtCore import (Qt, pyqtSignal) 
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, 
    QVBoxLayout, QApplication) 


class Example(QWidget): 

    def __init__(self): 
     super().__init__() 

     self.initUI() 

    def printLabel(self, str): 
     print(str) 

    def logLabel(self, str): 
     '''log to a file''' 
     pass 

    def initUI(self): 

     lcd = QLCDNumber(self) 
     sld = QSlider(Qt.Horizontal, self) 

     vbox = QVBoxLayout() 
     vbox.addWidget(lcd) 
     vbox.addWidget(sld) 

     self.setLayout(vbox) 

     #redundant connections 
     sld.valueChanged.connect(lcd.display) 
     sld.valueChanged.connect(self.printLabel) 
     sld.valueChanged.connect(self.logLabel) 

     self.setGeometry(300, 300, 250, 150) 
     self.setWindowTitle('Signal & slot') 
     self.show() 


if __name__ == '__main__': 

    app = QApplication(sys.argv) 
    ex = Example() 
    sys.exit(app.exec_()) 

Aby śledzić zmiany dokonane na suwak, po prostu wydrukować i rejestrowania zmian. To, co mi się nie podoba w tym kodzie, to to, że muszę zadzwonić do automatu trzykrotnie po trzykrotne wysłanie tej samej informacji do 3 różnych automatów.

Czy mogę utworzyć własną pyqtSignal, która wysyła liczbę całkowitą do pojedynczego gniazda. A z kolei czy funkcja slotów emituje zmiany, które należy wprowadzić?

  • Może nie w pełni zrozumieć cel emit() ponieważ nie istnieją dobre przykłady to cel w PyQt Signal-Slot docs. Podajemy tylko przykład wdrożenia emit bez parametrów.

Chciałbym utworzyć funkcję, która obsługuje funkcję emitowania. Rozważ następujące:

import sys 
from PyQt5.QtCore import (Qt, pyqtSignal) 
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, 
    QVBoxLayout, QApplication) 


class Example(QWidget): 

    def __init__(self): 
     super().__init__() 

     #create signal 
     self.val_Changed = pyqtSignal(int, name='valChanged') 

     self.initUI() 

    def initUI(self): 

     lcd = QLCDNumber(self) 
     sld = QSlider(Qt.Horizontal, self) 

     vbox = QVBoxLayout() 
     vbox.addWidget(lcd) 
     vbox.addWidget(sld) 

     self.setLayout(vbox) 

     sld.val_Changed.connect(self.handle_LCD) 
     self.val_Changed.emit() 

     self.setGeometry(300, 300, 250, 150) 
     self.setWindowTitle('Signal & slot') 
     self.show() 

    def handle_LCD(self, text): 
     '''log''' 
     print(text) 
     '''connect val_Changed to lcd.display''' 

if __name__ == '__main__': 

    app = QApplication(sys.argv) 
    ex = Example() 
    sys.exit(app.exec_()) 

Istnieją oczywiście poważne wady projektu. Nie mogę owijać głowy wokół kolejności wywołań funkcji. I nie implementuję poprawnie pyqtSignal. Sądzę jednak, że prawidłowe podanie poniższych 3 punktów pomoże mi stworzyć odpowiednią aplikację:

  1. Dla wstępnie zdefiniowanego sygnału: wyślij sygnał do funkcji automatu. Slot można ponownie wdrożyć, aby użyć wartości sygnału.
  2. Wyprodukuj obiekt pyqtSignal z niektórymi parametrami. Nie jest jeszcze jasne, jaki jest cel tych parametrów i jak różnią się one od parametrów "emitowania".
  3. emit może zostać ponownie zaimplementowany w celu wysłania określonych wartości sygnału do funkcji gniazda. Nie jest jeszcze jasne, dlaczego musiałbym wysyłać różne wartości z dotychczasowych metod sygnalizacji.

Możesz całkowicie zmienić kod tego, co próbuję zrobić, bo jeszcze nie zorientowałem się, czy jest to w dobrym stylu.

Odpowiedz

11

Możesz zdefiniować swój własny slot (dowolnie wywoływany python) i podłączyć go do sygnału, a następnie wywołać inne gniazda z tego jednego gniazda.

class Example(QWidget): 

    def __init__(self): 
     super().__init__() 
     self.initUI() 

    def printLabel(self, str): 
     print(str) 

    def logLabel(self, str): 
     '''log to a file''' 
     pass 

    @QtCore.pyqtSlot(int) 
    def on_sld_valueChanged(self, value): 
     self.lcd.display(value) 
     self.printLabel(value) 
     self.logLabel(value) 

    def initUI(self): 

     self.lcd = QLCDNumber(self) 
     self.sld = QSlider(Qt.Horizontal, self) 

     vbox = QVBoxLayout() 
     vbox.addWidget(self.lcd) 
     vbox.addWidget(self.sld) 

     self.setLayout(vbox) 
     self.sld.valueChanged.connect(self.on_sld_valueChanged) 


     self.setGeometry(300, 300, 250, 150) 
     self.setWindowTitle('Signal & slot') 

Ponadto, jeśli chcesz zdefiniować własne sygnały, muszą być zdefiniowane jako zmienne klasy

class Example(QWidget): 
    my_signal = pyqtSignal(int) 

argumentów do pyqtSignal określić typy obiektów, które będą emit byłyby na tym sygnał, więc w tym przypadku można zrobić

self.my_signal.emit(1) 

emitować może być przepisany do wysyłania sygnału konkretnych va lues do funkcji gniazda .Nie jest jeszcze jasne, dlaczego musiałbym wysyłać różne wartości z wcześniej istniejących metod sygnału.

Generalnie nie powinno się emitować sygnałów wbudowanych. Powinieneś tylko emitować zdefiniowane sygnały. Podczas definiowania sygnału można zdefiniować różne sygnatury z różnymi typami, a gniazda mogą wybrać sygnaturę, z którą chcą się połączyć. Na przykład, można zrobić to

my_signal = pyqtSignal([int], [str]) 

ten definiuje sygnał z dwóch różnych podpisów, a szczelina może połączyć się albo jeden

@pyqtSlot(int) 
def on_my_signal_int(self, value): 
    assert isinstance(value, int) 

@pyqtSlot(str) 
def on_my_signal_str(self, value): 
    assert isinstance(value, str) 

W praktyce rzadko przeciążać podpisów sygnałowych. Normalnie utworzyłbym dwa oddzielne sygnały z różnymi sygnaturami zamiast przeciążania tego samego sygnału. Ale istnieje i jest obsługiwany w PyQt, ponieważ Qt ma sygnały, które są przeciążone w ten sposób (np. QComboBox.currentIndexChanged)

+0

Wygląda na to, że komentowanie '@pyqtSlot (int)' nie wpływa na wynik. Dlaczego tak jest? – Max

+0

Wygląda na to, że prawdziwym celem dekoratora jest zbytnie umożliwienie przeładowania. – Max

+0

Nie służy tylko do przeciążania. Ta [odpowiedź] (http://stackoverflow.com/a/14431607/1547004) wyjaśnia to całkiem dobrze. Jeśli kiedykolwiek wysyłasz sygnały przez wątki, to wymaga to również dekoratora szczelin. –