ДК
Джон КофиНаурыз 4, 2020, 8:14 Т.Ж.

Передача сигнала в функцию

Qt, signals

Привет. Можно ли передать в метод сигнал, как параметр и потом сделать коннект на него? код ниже конечно не работает.

_model->waitingFor(SIGNAL(Model::somesignal())); // no matching function for call to..

...
class Model : public QObject
{
    Q_OBJECT
public:
    explicit Model(QObject *parent = nullptr);

    void foo();
    void waitingFor(const char *signal); - не работает
//    void waitingFor(std::function<void()> &signal); - тоже не работает

signals:
    void somesignal();
};
...
void Model::waitingFor(const char *signal)
{
    QEventLoop evloop;
    connect(this, signal, &evloop, &QEventLoop::quit); // не соберется
    connect(this, SIGNAL(signal()), &evloop, SLOT(quit())); // соберется, но QObject::connect: No such signal Model::signal()
    evloop.exec();
}

*так тоже не работает

void Test::waitingFor2(std::function<QMetaMethod> &signal)
{
    QEventLoop evloop;
    connect(this, signal, &evloop, &QEventLoop::quit);
    evloop.exec();
}
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

6
Evgenii Legotckoi
  • Наурыз 4, 2020, 8:51 Т.Ж.
  • (өңделген)
  • Жауап шешім ретінде белгіленді.

Добрый день.

Можно передать сигнал, но лучше в виде указателей это всё делать, МАКРОСЫ следует изживать из проекта.

Также здесь следует использовать шаблоны. Конкретно ваш случай можно разрулить так

#ifndef MODEL_H
#define MODEL_H

#include <QEventLoop>

class Model : public QObject
{
    Q_OBJECT
public:
    explicit Model(QObject *parent = nullptr) : QObject(parent) {}

    template<typename TSignal>
    void waitingFor(TSignal&& signal)
    {
        QEventLoop evloop;
        connect(this, signal, &evloop, &QEventLoop::quit);
        evloop.exec();
    }

signals:
    void someSignal();
};

#endif // MODEL_H

И вызов метода

model->waitingFor(&Model::someSignal);
    ДК
    • Наурыз 4, 2020, 9:05 Т.Ж.

    великолепно. я уж начал сомневаться, что делаю решаемую задачу.

      Evgenii Legotckoi
      • Наурыз 4, 2020, 9:10 Т.Ж.

      На макросах тоже можно, но лучше не надо. Кода больше получается, сам код в случае макросов требует применения SFINAE - в общем красивым код не назовёшь. Да и макросы менее надёжны.

        ДК
        • Наурыз 4, 2020, 1:54 Т.Қ.
        • (өңделген)

        на работе просто собрал, а протестил вот сейчас дома- не отрабатывает коннект.

        class Test : public QObject
        {
            Q_OBJECT
        public:
            explicit Test(QObject *parent = nullptr) : QObject(parent) {}
        
            void foo()
            {
                qDebug() << "foo";
                emit somesignal();
            }
        
            template<typename TSignal>
            void waitingFor(TSignal &&signal)
            {
                qDebug() << "waitingFor";
                connect(this, signal, [](){ qDebug() << "signal received"; });
            }
        
        signals:
            void somesignal();
        };
        ...
        _test->foo();
        _test->waitingFor(&Test::somesignal);
        

        именно qDebug() << "signal received";
        Может нельзя передавать в метод сигнал, а потом соединяться с ним?

          ДК
          • Наурыз 4, 2020, 2:20 Т.Қ.

          я вот думаю, что всё же правильней передавать const char *. Но всё равно тишина...

          class Test : public QObject
          {
              Q_OBJECT
          public:
              explicit Test(QObject *parent = nullptr) : QObject(parent) {}
          
              void foo()
              {
                  QTimer *timer = new QTimer;
                  timer->setSingleShot(true);
                  timer->start(5000);
                  connect(timer, &QTimer::timeout, timer, &QTimer::stop);
                  emit somesignal();
              }
          
              static void waitingFor(QObject *sender, const char *signalFromObj)
              {
                  qDebug() << "waitingFor";
                  QEventLoop loop;
                  connect(sender, signalFromObj, &loop, SLOT(quit()));
                  loop.exec();
              }
          
          signals:
              void somesignal();
          };
          ...
          _test->foo();
          Test::waitingFor(_test, SIGNAL(somesignal()));
          qDebug() << "mainwindow";
          

          qDebug() << "mainwindow"; не отработает.

            Evgenii Legotckoi
            • Наурыз 4, 2020, 2:38 Т.Қ.
            • (өңделген)

            я вот думаю, что всё же правильней передавать const char *. Но всё равно тишина...

            Вы неправильно думаете. При компиляции проектов на C/C++ макросы разворачиваются в полноценный код, а в случае Qt присутствует ещё и этап создания moc файлов, в которых эти макросы уже интерпретируются в сигнатуры функций и создаётся код коннектов. И только потом уже происходит компиляция всех созданных исходников. В Qt не создаются налёту подключения сигналов и слотов из указателей на const char *, потому что SIGNAL и SLOT - это не строки, это макросы. Весь процесс создания кода в случае SIGNAL и SLOT для сигналов и слотов происходит на этапе ПРЕДКОМПИЛЯЦИИ, а не в рантайме. А то, что вы пытаетесь передавать указатель на const char - это рантайм.

            Я вам дал полностью рабочий пример кода, который оттестировал и запустил.

            Вот модифицированный вариант, который тоже работает.

            #ifndef MODEL_H
            #define MODEL_H
            
            #include <QEventLoop>
            #include <QDebug>
            
            class Model : public QObject
            {
                Q_OBJECT
            public:
                explicit Model(QObject *parent = nullptr) : QObject(parent) {}
            
                template<typename TSignal>
                void waitingFor(TSignal&& signal)
                {
                    connect(this, signal, [](){ qDebug() << "Signal emitted"; });
                }
            
            signals:
                void someSignal();
            };
            
            #endif // MODEL_H
            
            

            Вот так его можно использовать

            widget.h

            #ifndef WIDGET_H
            #define WIDGET_H
            
            #include <QWidget>
            #include "model.h"
            
            QT_BEGIN_NAMESPACE
            namespace Ui { class Widget; }
            QT_END_NAMESPACE
            
            class Widget : public QWidget
            {
                Q_OBJECT
            
            public:
                Widget(QWidget *parent = nullptr);
                ~Widget();
            
            private slots:
                void on_pushButton_clicked();
            
                void on_sendSignalButton_clicked();
            
            private:
                Ui::Widget *ui;
            
                Model m_model;
            };
            #endif // WIDGET_H
            
            

            widget.cpp

            #include "widget.h"
            #include "ui_widget.h"
            
            Widget::Widget(QWidget *parent)
                : QWidget(parent)
                , ui(new Ui::Widget)
            {
                ui->setupUi(this);
            }
            
            Widget::~Widget()
            {
                delete ui;
            }
            
            void Widget::on_pushButton_clicked()
            {
                m_model.waitingFor(&Model::someSignal);
            }
            
            void Widget::on_sendSignalButton_clicked()
            {
                emit m_model.someSignal();
            }
            
            

            Вот тестовый проект

            CheckSignals.zip CheckSignals.zip

              Пікірлер

              Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
              Кіріңіз немесе Тіркеліңіз
              Г

              C++ - Тест 001. Первая программа и типы данных

              • Нәтиже:66ұпай,
              • Бағалау ұпайлары-1
              t

              C++ - Тест 001. Первая программа и типы данных

              • Нәтиже:33ұпай,
              • Бағалау ұпайлары-10
              t

              Qt - Тест 001. Сигналы и слоты

              • Нәтиже:52ұпай,
              • Бағалау ұпайлары-4
              Соңғы пікірлер
              G
              GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
              Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
              d
              dblas5Шілде 5, 2024, 11:02 Т.Ж.
              QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
              k
              kmssrАқп. 8, 2024, 6:43 Т.Қ.
              Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
              АК
              Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
              Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
              Енді форумда талқылаңыз
              Evgenii Legotckoi
              Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
              добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
              F
              FynjyШілде 22, 2024, 4:15 Т.Ж.
              при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
              BlinCT
              BlinCTМаусым 25, 2024, 1 Т.Ж.
              Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
              BlinCT
              BlinCTМамыр 5, 2024, 5:46 Т.Ж.
              Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
              Evgenii Legotckoi
              Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
              Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

              Бізді әлеуметтік желілерде бақылаңыз