Qt подключить сигнал к слоту

У меня есть класс главного окна, который содержит виджет QSplitter (среди других виджетов). Содержимое этого сплиттера заполняется виджетами, которые находятся в другом классе.

Внутри этого другого виджета у меня есть макет с добавленным QPushButton с именем test_btn. У меня также есть функция, определенная в заголовочном файле под public slots: называется test_function с соответствующим кодом в файле cpp:

cout << "Test!" << endl;

Я пытаюсь вызвать эту функцию, используя следующий код:

connect(test_btn, SIGNAL(clicked()), SLOT(test_function()));

Виджеты и кнопки отображаются в приложении, как и ожидалось, но когда я нажимаю, ничего не происходит.

Если я добавлю то же самое connect код для главного окна, в котором он работает (для вызова тестовой функции из главного окна), т.е.

connect(cc_point.test_btn, SIGNAL(clicked()), SLOT(main_win_test_function()));

Я не могу вызвать тестовую функцию из другого класса, если я не вызываю ее из main_win_test_function()

Я знаю, что мне не хватает "виджета-получателя" из оператора connect, хотя он работает без него в классе главного окна, и я не получаю никаких ошибок при компиляции.

Нужно ли определять родителя или что-то в other_class?

main_window.cpp:

main_window::main_window()
{
    add_splitter();

    QGridLayout *window_layout = new QGridLayout;

    window_layout->setSpacing(0);
    window_layout->setContentsMargins(0, 0, 0, 0);

    window_layout->addWidget(splitter1, 0, 0);

    set_layout(window_layout);
}

void main_window::add_splitter()
{
     other_class oc_point;

     splitter1 = new QSplitter(Qt::Horizontal);

     splitter1->addWidget(oc_point.oc_widget);
}

other_class.cpp:

other_class:other_class()
{
     oc_widget = new QWidget;

     QGridLayout *other_layout = new QGridLayout(oc_widget);

     test_btn = new QPushButton;
     test_btn->setText("Test Button");

     connect(test_btn, SIGNAL(clicked()), test_btn->parent(), SLOT(test_function());
     other_layout->addWidget(test_btn);
}

void other_class::test_function()
{
     cout << "Test output" << endl;
}

main.cpp:

int main(int argc, char *argv[]) {

QApplication app(argc, argv);

main_window window;

window.resize(1100, 700);
window.setWindowTitle("Qt Test");
window.setWindowIcon(QIcon (":/images/icon_1.png"));
window.setMinimumHeight(500);
window.show();

return app.exec();
}

Как я уже упоминал выше, все это прекрасно работает, когда создается окно и отображаются виджеты, но функция test_function не вызывается, когда я нажимаю кнопку. Дайте мне знать, если мне нужно также включить мои заголовочные файлы.

2 ответа

В main_window::add_splitter(), oc_point уничтожается, как только функция возвращается. Проблема не в связи, а в том, что ваш объект исчезает, прежде чем вы сможете что-то сделать с ним.

Ниже приведен автономный пример, который демонстрирует эту проблему как в Qt 4, так и в 5. Как только вы нажимаете "Удалить другие", кнопка "Тест" не работает.

//main.cpp
#include <QApplication>
#include <QGridLayout>
#include <QSplitter>
#include <QPushButton>
#include <QMessageBox>

class Other : public QObject
{
    Q_OBJECT
    QWidget *m_widget;
    Q_SLOT void testFunction() {
        QMessageBox::information(NULL, "Test", "Slot works.");
    }
public:
    QWidget *widget() const { return m_widget; }
    Other(QObject *parent = 0) : m_widget(new QWidget), QObject(parent) {
        QGridLayout *l = new QGridLayout(m_widget);
        QPushButton *btn = new QPushButton("Test Button");
        l->addWidget(btn);
        connect(btn, SIGNAL(clicked()), this, SLOT(testFunction()));
    }
    ~Other() { if (!m_widget->parent()) delete m_widget; }
};

class Main : public QWidget
{
public:
    Main(QWidget *parent = 0, Qt::WindowFlags f = 0) : QWidget(parent, f) {
        QGridLayout *l = new QGridLayout(this);
        QPushButton *btn = new QPushButton("Delete Other");
        Other *o = new Other(this);
        QSplitter *spl = new QSplitter;
        spl->addWidget(o->widget());
        l->addWidget(spl);
        l->addWidget(btn);
        connect(btn, SIGNAL(clicked()), o, SLOT(deleteLater()));
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Main w;
    w.show();
    return a.exec();
}

#include "main.moc"

После того, как ваши объекты инициализированы, вы должны соединить их друг с другом. Явное указание, чьи слоты - это чьи, а чьи сигналы - чьи, очень поможет.

Иногда я делаю вспомогательную функцию void Widget::connectTo__Class__(Class * class_ptr);

Затем в этом вызове функции я соединю слоты, которые пересекают границы класса / родителя / наследования.

Вот пример реализации:

void Widget::connectTo__Class__(Class * class_ptr)
{
    QObject::connect(this,      SIGNAL(myWidgetSignal()), 
                     class_ptr, SLOT(myClassSlot()));

    QObject::connect(class_ptr, SIGNAL(myClassSignal()), 
                     this,      SLOT(myWidgetSlot()));
}

Также имейте в виду, что среда выполнения будет жаловаться, когда вы делаете что-то не так, например, если class_ptr является null, или если myClassSignal не существует Вы можете увидеть эти ошибки в выходных данных приложения, когда вы запускаете его в режиме отладки.

И дать QDebug попытка когда-нибудь.

http://qt-project.org/doc/qt-4.8/debug.html

РЕДАКТИРОВАТЬ: Чтобы исправить любые проблемы рекурсивного определения класса заголовка, выполните следующие действия:

В вашем заголовочном файле для одного из классов только прототип класса, не включайте его:

в widget.h:

// #include "myclass.cpp" // Should be commented out!

class MyClass; // This prototype avoids the recursion

// ...

class Widget
{
    // ...

    public:
        void connectToMyClass(Class * class_ptr);

    // ...
}

Затем в файле cpp вы делаете включение.

#include "myclass.h"

void Widget::connectToMyClass(Class * class_ptr)
{
    // ...
}

Другим способом решения этой проблемы является использование QObject * вместо Class *,

Надеюсь, это поможет.

Другие вопросы по тегам