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 *
,
Надеюсь, это поможет.