БлогNot. Приватные и публичные слоты в QT

Приватные и публичные слоты в QT

В доке сказано только следующее:

Слоты - это обычные функции-члены, они следуют обычным правилам C ++ при непосредственном вызове.

Однако как слоты они могут быть вызваны любым компонентом, независимо от его уровня доступа, через соединение "сигнал-слот".

Это означает, что сигнал, отправляемый экземпляром некоторого класса, может выполнить вызов приватного слота в экземпляре другого класса.

Иными словами из другого класса вы не можете вызывать приватный слот как функцию, но если вы отправляете сигнал методом emit, подключённый к этому приватному слоту, вы можете вызывать его.

Возьмём примерно тот же самый код, что в этой заметке, создадим виджет как здесь, разместим на форме однострочное текстовое поле QLineEdit и флажок-переключатель QCheckBox, а также добавим в проект пустой класс MyObject, унаследованный от Object. Будем "танцевать" в разработке от объекта, который ещё упростим.

Файл object.h
#ifndef OBJECT_H
#define OBJECT_H
#include <QObject>
#include <QtWidgets>
class MyObject : public QObject {
Q_OBJECT
 //Класс д.б. наследником QObject, чтобы использовать сигналы и слоты
public:
 explicit MyObject(QObject * parent = 0);
signals:
 void send_to_gui(bool value); //Сигнал, отправляемый объектом в GUI
private slots:
 void get_from_gui(bool value); //Слот для приёма сигналов от GUI
 void gets_from_gui(QString value);
  //Ещё один слот для приёма информации о том, что изменилось текстового поля
//При этом объект не знает о виджете,
//он просто предоставляет слот для получения внешней информации
private:
 bool state; //Собственно данные класса
};
#endif // OBJECT_H
Файл object.cpp
#include "object.h"

MyObject::MyObject(QObject *parent) : QObject (parent) {  }

void MyObject::get_from_gui(bool value) { //Слот 1
 state = value; //У объекта есть состояние, он его как-то поменял
 emit send_to_gui(state); //и послал сигнал в GUI
}

void MyObject::gets_from_gui(QString value) { //Слот 2
 QMessageBox msgBox; 
 msgBox.setText(value); 
 msgBox.exec();
}
Файл widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "object.h"

namespace Ui {class Widget;}

class Widget : public QWidget {
 Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
signals:
    void send_to_object(bool value); //Сигнал для отправки из GUI в объект
private slots:
    void get_from_object(bool value);
    void on_checkBox_clicked();
private:
    Ui::Widget *ui;
    MyObject Object; //Экземпляр объекта
};
#endif // WIDGET_H
Файл widget.cpp

Тут будет самое интересное. Если мы соединим сигналы со слотами в конструкторе виджета "классческим" кодом, пришедшим ещё из QT4, то всё работает как надо.

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
 ui->setupUi(this);
 //Виджет может использовать интефейс сигналов-слотов других виджетов,
 //не вникая в детали их реализации, очередность обработки сигналов и т.п.
 connect(&Object,SIGNAL(send_to_gui(bool)),this,SLOT(get_from_object(bool)));
  //Это сигнал от объекта в виджет
 connect(this,SIGNAL(send_to_object(bool)),&Object,SLOT(get_from_gui(bool)));
  //Это сигнал от виджета в слот объекта
 connect(ui->lineEdit,SIGNAL(textChanged(QString)),&Object,SLOT(gets_from_gui(QString)));
  //Это сигнал от дочернего виджета lineEdit в слот объекта
}

Widget::~Widget(){    delete ui; }

void Widget::get_from_object(bool value) { //Слот 1 виджета
 ui->lineEdit->setText(value?"true":"false");
}

void Widget::on_checkBox_clicked() { //Слот 2 виджета
 emit send_to_object(ui->checkBox->isChecked());
}

Теперь изменения в текстовом поле также обрабатываются слотом. Причём, это сработает при любом изменении текста в поле, в том числе, вызванном активностью слота get_from_object, который записал туда текст.

Но если мы изменим соединения на "стиль QT5" на основе указателей (показано только изменённое тело конструктора виджета)

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
 ui->setupUi(this);
 connect (&Object,&MyObject::send_to_gui,this,&Widget::get_from_object);
 connect (this,&Widget::send_to_object,&Object,&MyObject::get_from_gui);
 connect(ui->lineEdit,&QLineEdit::textChanged,&Object,&MyObject::gets_from_gui);
}

то возникнет ошибка вида "'get_from_gui' is a private member of 'MyObject'" и описания слотов в object.h придётся сделать публичными:

public slots:
 void get_from_gui(bool value);
 void gets_from_gui(QString value);

Думается, всё понятно из общих соображений - QT отказывается получать явно адрес функции-слота, объявленной приватной.

 Скачать этот проект QT 5.X в архиве .zip, папка уже создана внутри архива (3 Кб)


теги: программирование c++ qt

15.03.2020, 13:16; рейтинг: 157