Сигналдар мен слоттар Qt-дағы объектілер арасындағы байланыс үшін пайдаланылады. Сигнал және слот механизмі Qt-тің орталық ерекшелігі болып табылады және Qt-ны функционалдық жағынан басқа құрылымдардан ерекшелендіретін нәрсе болуы мүмкін. Сигналдар мен слоттар Qt. meta-object system арқылы мүмкін болады.
Кіріспе
GUI бағдарламалауда виджеттердің бірі өзгерген кезде, біз басқа виджеттердің хабарландыруын жиі қалаймыз. Жалпы, біз объектілердің бір-бірімен әрекеттесе алатынын қалаймыз. Мысалы, егер пайдаланушы Жабу түймесін басқан болса, біз window нысанының close(). функциясын шақырғанын қалар едік.
Басқа әзірлеу құралдары кері шақыру арқылы ұқсас функционалдылықты қамтамасыз етеді. кері шақыру функцияның көрсеткіші болып табылады және сізге қандай да бір оқиға туралы хабарлайтын функцияны орындағыңыз келсе, онда сіз көрсеткішті басқа функцияға, яғни кері шақыру. Іске қосу функциясы кері шақыруды* шақырады. * содан кейін, қажет болғанда. кері шақыру функцияларын сәтті пайдаланатын фреймворктар бар болғанымен, кері шақыру** қайтарылған аргументтерді тексеру кезінде қиындықтар тудыруы мүмкін интуитивті емес әдіс.
Сигналдар мен слоттар
Qt балама техниканы пайдаланады, яғни слоттар мен сигналдарды пайдаланады. Белгілі бір оқиға болған кезде сигнал орындалады. Qt виджеттерінің алдын ала анықталған сигналдары көп, бірақ біз әрқашан виджеттен мұра алып, олар үшін өз сигналдарымызды анықтай аламыз. Слот - бұл белгілі бір сигналға жауап ретінде шақырылатын функция. Qt виджеттерінің де алдын ала анықталған слоттары көп, бірақ виджеттерден мұра алу және өз ұяларыңызды қосу әдеттегі тәжірибе, сондықтан сізді қызықтыратын сигналдарды өңдеуге болады.
]
Qt жүйесіндегі сигналдар мен ұялар Сигналдар мен слоттар типті қауіпсіз механизм болып табылады. Сигналдың қолтаңбасы қабылдау ұясының қолтаңбасына сәйкес болуы керек (Шын мәнінде, ұяшықта сигналдан қысқа қолтаңба болуы мүмкін, бірақ ұяшық сигналды қабылдайды, себебі ол қосымша аргументтерді елемейді). Қолтаңбалар үйлесімді болғандықтан, компилятор көрсеткішке негізделген синтаксисті пайдалану кезінде сәйкессіздіктерді анықтауға көмектеседі. Ал, SIGNAL және SLOT макростарына негізделген синтаксиспен түр сәйкессіздігін тек орындау уақыты процесінде анықтауға болады. Сигналдар мен слоттар еркін байланысқан: сигналды шақыратын класс сигналды қабылдайтын ұяшықты ғана біледі. Qt жүйесіндегі сигнал және ұяшық механизмі сигналды қажетті уақытта сигнал параметрлерімен шақырылатын ұяға қоссаңыз қамтамасыз етіледі. Сигналдар мен ұяшықтардың бірнеше аргументтері мен түрлері болуы мүмкін. Және олар түрге мүлдем қауіпсіз.
QObject немесе оның ішкі сыныптарынан (мысалы, QWidget) алынған барлық сыныптар -5/qwidget.html) сигналдар мен слоттарды қамтуы мүмкін. Сигналдарды басқа объектілерді қызықтыруы мүмкін күйін өзгертетін объектілер шақырады. Байланыс үшін нысанның барлығы осы. Ал нысан ол шығаратын сигналдарды кім қабылдайтыны маңызды емес. Бұл ақпараттың әділ инкапсуляциясы және объектіні бағдарламалық құрал құрамдас бөлігі ретінде пайдалану мүмкіндігін қамтамасыз етеді.
Слоттарды сигналдарды қабылдау үшін пайдалануға болады, бірақ олар да қалыпты функциялар болып табылады. Нысан өз сигналын не қабылдағанын білмейтіні сияқты, ұяшық оған қандай сигнал қосылғанын білмейді. Бұл Qt көмегімен жасауға болатын құрамдастардың нақты тәуелсіздігін қамтамасыз етеді.
Бірнеше сигналды бір ұяға қосуға болады немесе сигналды бірнеше ұяшықтарға қосуға болады. Және тіпті сигналды басқа сигналға тікелей қосуға болады. (Бұл бірінші сигнал шақырылған кезде екінші сигналды қосады)
Сигналдар мен слоттар бірге құрамдас бағдарламалаудың қуатты механизмін жасайды.
Сигналдар
Сигналдарды объектінің ішкі күйі басқа объектілерді қызықтыруы мүмкін белгілі бір бағытта өзгерген кезде шығарады. Сигналдар жалпыға ортақ функциялар болып табылады және оларды кез келген жерде шақыруға болады, бірақ оларды тек анықталған сыныпта және оның ішкі сыныптарында шақыру ұсынылады.
Сигнал шақырылғанда, оған қосылған ұяшық әдетте қалыпты функция сияқты бірден орындалады. Бұл мүмкін, себебі сигнал және слот механизмі GUI-дегі кез келген циклдардан тәуелсіз. Кодты орындау барлық слоттарды шақыратын emit директивасы арқылы шақырылуы керек. Қосылым кезегі пайдаланылған жағдайларда код сигнал береді және слоттар сәл кейінірек орындалады.
Егер бір сигналға бірнеше слоттар қосылса, онда ұялар сигнал шақырылған кезде қосылу ретімен бірінен соң бірі шақырылады.
Сигналдар moc ішінде автоматты түрде жасалады және оларды .cpp файлында анықтаудың қажеті жоқ және олар ешқашан нәтижені қайтармайды.
Ескертпе: Біздің тәжірибемізге сәйкес, сигналдар мен слоттар, егер олар арнайы түрлерде пайдаланылмаса, тиімдірек болады. Егер QScrollBar::valueChanged () гипотетикалық QScrollBar::Range сияқты арнайы түрі болса, ол тек келесіге қосыла алады. QScrollBar үшін арнайы жасалған ұяшық. Әртүрлі виджеттерді біріктіру мүмкін болмауы мүмкін.
Слоттар
Слот оған қосылған сигнал шақырылған кезде шақырылады. Слоттар қалыпты C++ функциясы болып табылады және оларды шақыруға болады; олар сигналдардың оларға қосылуында ғана ерекше.
Сондай-ақ, слоттарды қарапайым функциялар сияқты орындауға болады, олар тікелей шақырылған кезде әдеттегі C++ ережелеріне бағынады. Дегенмен, слоттар сияқты, олар қол жеткізу деңгейіне қарамастан, сигнал-слот қосылымы арқылы басқа компоненттермен шақырылуы мүмкін. Бұл сигнал сыныптардың бірінен шығарылатынын және сол байланыссыз сыныптан шақырылатын жеке ұяшыққа берілуі мүмкін екенін білдіреді.
Сондай-ақ, слоттарды виртуалды деп анықтауға болады, біз оны іс жүзінде өте пайдалы деп санаймыз.
кері қоңыраумен салыстырғанда сигналдар мен ұяшықтар қамтамасыз ететін икемділікке байланысты сәл баяуырақ, дегенмен нақты қолданбадағы айырмашылықтар шамалы. Негізінде, бірнеше ұяшықтарға қосылатын сигналды шақыру виртуалды емес функцияны шақырудан шамамен он есе баяу. Бұл үстеме шығындар, осыған байланысты ұя функциясын қауіпсіз шақыру үшін барлық слоттар мен сигналдарды қайталау және қолтаңбаларды салыстыру арқылы қосылым нысанын табу қажет. Ал он виртуалды емес функциялар бірнеше жаңа және жою операцияларына қарағанда аз қосымша шығындармен шақырылады. Жаңа және жою әрекеттерін қажет ететін сахна артында жол, вектор немесе тізім әрекетін орындағаннан кейін, сигналдар мен ұяшықтардың үстеме шығындары функция шақыруының жалпы құнымен салыстырғанда өте аз болады. Бұл ұяшыққа жүйелік қоңырау шалғанда немесе оннан астам функцияларды жанама шақырғанда дұрыс. Сигнал мен слот механизмінің қарапайымдылығы мен икемділігі - бұл сіздің пайдаланушыларыңыз байқамайтын шамалы.
Басқа кітапханалар сигналдар мен ұялар деп аталатын айнымалы мәндерді анықтайтынын және Qt негізіндегі қолданба құрастырылған кезде қателер мен ескертулерді тудыруы мүмкін екенін ескеріңіз. Бұл мәселелердің шешімі препроцессор үшін #undef директивасын пайдалану болып табылады.
Сигналды ұяға қосыңыз
Qt бесінші нұсқасына дейін сигналды ұяға қосу макростар арқылы жазылса, бесінші нұсқада көрсеткіштерге негізделген белгілер қолданыла бастады.
Макростармен жазу:
connect(button, SIGNAL(clicked()), this, SLOT(slotButton()));
Көрсеткіш негізіндегі жазба:
connect(button, &QPushButton::clicked, this, &MainWindow::slotButton);
Екінші нұсқаның артықшылығы мынада: қолтаңбаның сәйкессіздігі мен дұрыс емес ұяшық немесе сигнал атауын қолданбаны тестілеу процесінде емес, жобаны құрастыру сатысында анықтауға болады.
Сигналдарды және ұяшықтарды пайдалану мысалы
Сигналдарды және ұяшықтарды пайдалану мысалы үшін негізгі терезеде үш түймесі бар жоба жасалды, олардың әрқайсысында ұяшық қосылған және бұл слоттар басылған түйменің нөмірімен сигналды бір ұяшыққа жібереді.
Жоба құрылымы
Жоба құрылымы Сабақты оқытудың қалыптасқан дәстүріне сәйкес, мен мүлдем тривиальды және ұятқа қалдыратын жоба құрылымын қосамын, мен оған енгізілген сыныптар мен файлдарды сипаттамаймын.
mainwindow.h
Сонымен, әрекет келесідей: үш түйме - үш ұяшық, барлық үш түйме үшін бір сигнал, ол түйме ұяшықтарына беріледі және түйме нөмірін бір жалпы ұяшыққа жібереді, ол түйме нөмірі бар хабарлама береді.
#ifndef MAINWINDOW\_H #define MAINWINDOW\_H #include <QMainWindow> #include <QPushButton> #include <QMessageBox> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q\_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); signals: void signalFromButton(int buttonID); // Сигнал для передачи номер нажатой кнопки private: Ui::MainWindow *ui; private slots: void slotButton1(); // Слоты-обработчики нажатий кнопок void slotButton2(); void slotButton3(); // Слоты вызывающий сообщение с номеро нажатой кнопки void slotMessage(int buttonID); }; #endif // MAINWINDOW\_H
mainwindow.cpp
Және бұл файлда алдыңғы параграфтарда сипатталған логика конфигурацияланған. Бағдарламаның кодын қараңыз және бейнені қарауға кірісіңіз, бүкіл процесс егжей-тегжейлі көрсетіледі, қолданба көрсетіледі, сонымен қатар код әртүрлі қателермен жазылса не болатыны көрсетіледі.
#include "mainwindow.h" #include "ui\_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); /* Объявляем и инициализируем кнопки * */ QPushButton *but\_1 = new QPushButton(this); QPushButton *but\_2 = new QPushButton(this); QPushButton *but\_3 = new QPushButton(this); /* Устанавливаем номера кнопок * */ but\_1->setText("1"); but\_2->setText("2"); but\_3->setText("3"); /* Добавляем кнопки на слой с вертикальной ориентацией * */ ui->verticalLayout->addWidget(but\_1); ui->verticalLayout->addWidget(but\_2); ui->verticalLayout->addWidget(but\_3); /* Подключаем к кнопкам индивидуальные слоты * */ connect(but\_1, SIGNAL(clicked()), this, SLOT(slotButton1())); connect(but\_2, SIGNAL(clicked()), this, SLOT(slotButton2())); connect(but\_3, SIGNAL(clicked()), this, SLOT(slotButton3())); /* Подключаем сигнал с передачей номера кнопки к слоту вывода сообщения * */ connect(this, &MainWindow::signalFromButton, this, &MainWindow::slotMessage); } MainWindow::~MainWindow() { delete ui; } /* Слоты для обработки нажатия кнопок * */ void MainWindow::slotButton1() { emit signalFromButton(1); } void MainWindow::slotButton2() { emit signalFromButton(2); } void MainWindow::slotButton3() { emit signalFromButton(3); } /* Слоты вывода сообщения * */ void MainWindow::slotMessage(int buttonID) { QMessageBox::information(this, "Уведомление о нажатой кнопке", "Нажата кнопка под номером " + QString::number(buttonID)); }
Простите , а если я например хочу сделать по кнопке клик не левой кнопкой ,а правой или вообще засекать перемещение мыши на кнопке, то как будет выглядить строка
Я так понял что сиглалы виджетов заранее предопределены в библиотеке и в данном случае &QPushButton::clicked это событие из стандартной библиотеки Qt. В справке сказано, что всего есть четыре сигнала clicked, pressed, released,toggled. Может я не ту справку читаю, от того и странные вопросы.
Правильно всё читаете. Так и есть.
Если хотите отслеживать правую кнопку мыши, то вам следует наследоваться от QPushButton и переопределять методы
И переопределять поведение кнопки в случае правой, или левой кнопки мыши.
Извините, последний вопрос.
Написал маленький "проект", хочу стобы сцена ловила события мыши. Особенно когда мышь "отпустили". По сути это нужно для манипулирования с картинками на сцене.
Согласно справке за события на сцене отвечает QGraphicsSceneMouseEvent, однако попытка подружить слот и сигнал со сценой провалились, вот такой код привязки
не работает, компилятор ругается на объект scene, если поставить this то все конечно компилируется, но это же и не должно работать как надо
Вот весь код проекта.
mainwindow.h
mainwindow.cpp
Как можно привязать слот к сцене или либому другому виджету ? Может быть у вас есть видеоурок на этой теме? Особенно интересует обработка событий при столкновении двух пиксельных рисунков на сцене.
какая жуть.... если вам нужно, чтобы сцена что-то делала при кликах мыши, то методы нужно переопределять в наследованном классе сцены, а не запихивать методы из графической сцены в класс окна приложения.
Да я уже нашел ваш проект, с рисованием мышью и понял что это действительно жуть.
Думаю надо отдохнуть, уже 12 учусь.
Возник такой вопрос.
Разбираюсь с одной библиотекой. В ней применен паттерн Pimpl. И в коде есть вызовы метода connect(), но с помощью макросов:
Q_Q(QAmqpClient); - это, как понял, получение q-указателя на основной класс.
В нем сигнал таймера, который находится в приватном классе коннектится к слоту, который находится в основном классе.
Как этот коннект записать без макросов?
В основном классе _q_heartbeat() объявлен как Q_PRIVATE_SLOT(d_func(), void _q_heartbeat()). Т.е., на сколько понял, вызывается приватный метод _q_heartbeat приватного класса. Причем он находится в секции public, а не public slots.
Попытки написать что-то типа
приводят к ошибке компиляции.
ошибка: '_q_heartbeat' is not a member of 'QAmqpClient'
или
ошибка: expected primary-expression before '/' token
Без макросов никак. Приватные методы через указатели не коннектятся извне, что правильно, а вот макросы болт кладут на private и protected модификаторы.