Гузариш ба мундариҷа
Мавзӯи 3 аз 6

Сигналҳо, слотҳо ва сигналҳои худӣ

Сигналҳо ва слотҳо барои чӣ лозиманд

Майдони вуруд намедонад, ки баъди таҳрир ҳисобкунакро нав кардан, қиматро аз нав ҳисоб кардан ё сабтро иҷозат додан лозим аст. Инҳо қоидаҳои барномаанд. Сигналҳо ба виджет имкон медиҳанд аз тағйирот хабар диҳад ва слотҳо посухи заруриро иҷро мекунанд. Ҳамин тавр интерфейс аз қисмҳои хурде иборат мешавад, ки онҳоро ба тарзҳои гуногун пайвастан мумкин аст.

Дар ин мавзӯъ фарқ кардани амали корбар ва тағйирот аз код муҳим аст. Масалан, бор кардани матн ба муҳаррир низ метавонад сигнал барорад. Агар онро таҳрири нав шуморем, барнома ҳисобҳои зиёдатӣ мекунад ё тасодуфан додаҳоро аз нав менависад.

1. Слот кадом додаҳоро мегирад

Сигнал огоҳӣ бо маҷмӯи муайяни аргументҳост. QSpinBox.valueChanged адади бутуни нав ва QCheckBox.toggled ҳолати мантиқиро медиҳад. Функсияи ба connect додашуда ин қиматҳоро ҳангоми ҳар тағйироти воқеӣ мегирад.

from PySide6.QtWidgets import QApplication, QSpinBox, QCheckBox

app = QApplication.instance() or QApplication([])
spin = QSpinBox()
spin.setRange(0, 10)
spin.valueChanged.connect(lambda value: print("value", value))
spin.setValue(4)
box = QCheckBox()
box.toggled.connect(lambda checked: print("checked", checked))
box.setChecked(True)

Натиҷа:

value 4
checked True

setRange ададҳои иҷозашударо маҳдуд мекунад. setValue(4) қиматро иваз карда, коркардкунандаро даъват мекунад; setChecked(True) барои аломати интихоб ҳамин корро мекунад. Слоте, ки ба додаҳо ниёз надорад, метавонад аргументҳои сигналро қабул накунад. Агар аргумент лозим бошад, маънояшро аз рӯи сигнали мушаххас санҷед, на аз рӯи номи виджет тахмин кунед.

2. Тағйири матн ва таҳрири корбар

Сигнали textChanged(str)-и QLineEdit новобаста аз манбаи тағйирот аз матни нав хабар медиҳад. textEdited(str) барои таҳрири корбар аст. Гузоштани матни нав бо setText() сигнали аввалро мебарорад, вале дуюмро не. Боз гузоштани ҳамон матн тағйироти нав эҷод намекунад.

from PySide6.QtWidgets import QApplication, QLineEdit

app = QApplication.instance() or QApplication([])
edit = QLineEdit()
events = []
edit.textChanged.connect(lambda text: events.append(("changed", text)))
edit.textEdited.connect(lambda text: events.append(("edited", text)))
edit.setText("Qt")
edit.setText("Qt")
print(events)

Натиҷа:

[('changed', 'Qt')]

Дар рӯйхати рӯйдодҳо як сабти changed ҳаст, гарчанде setText ду бор даъват шуд. Сабти edited нест: вуруди клавиатура набуд. returnPressed сигнали дигари алоҳидаи майдон аст, ки ҳангоми Enter пайдо мешавад; онро барои тасдиқи вуруд истифода бурдан мумкин аст.

3. Додани аргументи худ

lambda функсияи хурдест, ки онро ба ҷойи методи алоҳида пайвастан қулай аст. Ҳангоми сохтани тугмаҳо дар давра қимати такрори ҷориро нигоҳ доштан лозим аст. Параметри пешфарзи k=key инро дар лаҳзаи сохтани функсия мекунад. Параметри якуми checked аргументи мантиқии сигнали clicked-ро мегирад.

from PySide6.QtWidgets import QApplication, QPushButton

app = QApplication.instance() or QApplication([])
buttons = []
for key in ("A", "B"):
    button = QPushButton(key)
    button.clicked.connect(lambda checked=False, k=key: print(k))
    buttons.append(button)
for button in buttons:
    button.click()

Натиҷа:

A
B

Тугмаҳо ҳарфҳои гуногунро чоп мекунанд, зеро ҳар функсия қимати пешфарзи худро дорад. Бе k=key ифодаи дохили lambda тағйирёбандаи key-ро баъдтар, ҳангоми пахш мехонд; баъди давра дар он аллакай B аст. Бе параметри аввал қимати checked метавонист аргументи шуморо иваз кунад.

4. Навкунии ором ва QSignalBlocker

Агар ду коркардкунанда майдонҳои ба ҳам вобастаро иваз кунанд, огоҳиҳои такрорӣ ба осонӣ пайдо мешаванд. Ҳатто агар давр дар қимати яксон қатъ шавад, гирдкунӣ ё шаклдиҳӣ метавонад вуруди аслиро иваз кунад. Бастани сигналҳо имкон медиҳад ҳолати виджетро бе огоҳ кардани қабулкунандагон тағйир диҳед.

QSignalBlocker сигналҳои объекти муайяншударо муваққатан мебандад. Блоки with муҳлати бастанро маҳдуд карда, ҳангоми баромадан, аз ҷумла баъди истисно, ҳолати пешинаро барқарор мекунад. Сигналҳои замони бастан барои фиристодани баъдӣ ҷамъ намешаванд.

from PySide6.QtCore import QSignalBlocker
from PySide6.QtWidgets import QApplication, QLineEdit

app = QApplication.instance() or QApplication([])
edit = QLineEdit()
events = []
edit.textChanged.connect(events.append)
with QSignalBlocker(edit):
    edit.setText("Сиёҳнавис")
print(edit.text(), events)
edit.setText("Покнавис")
print(events)

Натиҷа:

Сиёҳнавис []
['Покнавис']

Матни «Сиёҳнавис» воқеан гузошта шуд, вале коркардкунанда огоҳӣ нагирифт. Тағйироти навбатӣ берун аз with аллакай ба events меравад. Объектеро бандед, ки сигнали нолозимро мебарорад, на виджети ҳамсояи тасодуфиро.

5. Сигнали худӣ

Танҳо виджетҳои тайёр аз тағйирот хабар намедиҳанд. Зерсинфи QObject дар низоми сигналҳои Qt иштирок мекунад. Signal(int) дар тани синф эълон мешавад ва emit(value) аз объекти мушаххас огоҳӣ мефиристад. super().__init__() қисми QObject-ро оғоз мекунад.

from PySide6.QtCore import QObject, Signal

class Meter(QObject):
    reading = Signal(int)

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

meter = Meter()
meter.reading.connect(lambda value: print(value * 2))
meter.reading.emit(7)

Натиҷа:

14

Объекти meter адади 7-ро фиристод ва қабулкунанда қимати дучанди онро чоп кард. Худи фиристанда намедонад, ки қабулкунанда ададро чӣ гуна истифода мебарад. Ба як сигнал чанд қабулкунандаи гуногунро пайвастан мумкин аст; ҳар кадом кори худро иҷро мекунад.

Дар дохил чӣ рӯй медиҳад

connect пайвастро сабт мекунад, вале слотро фавран даъват намекунад. Ҳангоми баромадани сигнал Qt аргументҳоро ба функсияҳои пайвастшуда медиҳад. Дар мисолҳо ҳамаи объектҳо дар як риштаанд: пайвастҳои одӣ коркардкунандаҳоро ҳамзамон, пеш аз бозгашти setText() ё emit(), даъват мекунанд. Аз ҳамин сабаб натиҷа бе app.exec() намоён аст. Пайвастҳои байни риштаҳо метавонанд аз навбати рӯйдодҳо истифода баранд; дар ин ҷо онҳо истифода намешаванд.

Хатоҳои маъмул ва ислоҳи онҳо

  1. lambda: print(key) дар давра: ҳамаи тугмаҳо қимати охиринро мегиранд. Онро бо параметри пешфарз нигоҳ доред ва аргументи clicked-ро алоҳида қабул кунед.
  2. self.changed = Signal(int) дар __init__: сигнали дурусти вобастаи Qt ҳосил намешавад. changed = Signal(int)-ро дар сатҳи зерсинфи QObject эълон кунед.
  3. edit.blockSignals(True) бе барқароркунӣ: майдон иваз мешавад, вале интерфейс дигар посух намедиҳад. Бастанро бо with QSignalBlocker(edit): маҳдуд кунед.
  4. Интизор шудан, ки setText() сигнали textEdited диҳад: коркардкунанда иҷро намешавад. Барои тағйироти код ва корбар textChanged истифода баред.
  5. plain.textChanged.connect(lambda text: ...): QPlainTextEdit ин аргументро намедиҳад ва коркардкунанда TypeError медиҳад. plain.toPlainText()-ро дар функсияи бепараметр хонед.

Ёддошти кӯтоҳ

Ҳолат Восита
Ҳар тағйири матни QLineEdit textChanged(str)
Таҳрири корбар дар QLineEdit textEdited(str)
Адад / аломати интихоб valueChanged(int) / toggled(bool)
Қимати такрори ҷорӣ параметри пешфарзи lambda
Навкунӣ бе огоҳӣ with QSignalBlocker(widget):
Сигнали худӣ Signal(...) дар синфи QObject
Фиристодани огоҳӣ object.signal.emit(...)