Qt Connect - wyłapywanie sygnałów

0

Witam, mam kolejny problem z moim programem. Mianowicie: wyskakuje mi okienko z listą słów w postaci drzewa (manageWordList), na dole okienka jest przycisk Dodaj, po naciśnięciu wyskakuje kolejne okienko (addNewWord), tam wypełniam formularz, klikam OK i wysyłam sygnał added().
Funkcja uruchamiająca okno addNew:

void manageWordList::on_pushButton_released()
{
    newWord = new addNew(this, words);
    newWord->exec();
} 

W konstruktorze klasy manageWordList mam funkcję connect:

  connect(newWord, SIGNAL(added()), this, SLOT(printTree()));

gdzie printTree() to funkcja odpowiedzialna za generowanie drzewa w oknie manageWordList (czyli najzwyczajniej w świecie po dodaniu słowa chcę od nowa narysować drzewo - teraz z dodanym słowem).

Problem polega na tym, że pomimo emitowania sygnału added w addNew nie zostaje wywołana funkcja paintTree() w manageWordList. Dodam, że sprawdzałem i sygnał jest emitowany poprawnie.

0

W jaki sposób sprawdzałeś czy sygnał jest emitowany poprawnie?

0

Wrzuciłem w

void addNew::added()
{
    QMetaObject::activate(this, &staticMetaObject, 0, 0);

} 

qDebug() i został wyświetlony tekst więc na tej podstawie stwierdziłem, że sygnał został wyemitowany poprawnie :D Szczerze mówiąc nie wiem czy świadczy to o poprawności emisji tego sygnału.

0

A skąd tak cudacznie nauczyłeś się definiować sygnały? Pytam bez szydery, poważnie chciałbym wiedzieć. QMetaObject::activate jest metodą używaną w generowanym przez moc kodzie, nie wiem dlaczego miałbyś wołać tą metodę ręcznie. Klasa w której definiujesz sygnał powinna wyglądać mniej więcej tak (pisane bez IDE):

class MyClass : public QObject
{
        Q_OBJECT
     public:
        MyClass();
        virtual ~MyClass();

    signals:
        void added();
}

Sygnał added() nie ma implementacji! Wtedy uruchamiasz ręcznie qmake, bo czasami draństwo się nie załącza dlatego ja uruchamiam qmake zawsze jak dodam klasę która musi być dotknięta przez moc. A potem właczasz budowanie.

EDIT
By the way, nie widziałem jeszcze żeby ktoś wywoływał connect na obiekcie który nie jest jeszcze zainicjalizowany, przynajmniej tak wynika ze skrawka kodu który wkleiłeś.

0

Już tłumaczę, w nagłówku klasy dodałem:

signals:
    void added();

następnie tam gdzie chcę go wyrzucić:

emit added();

Skąd się wziął kod z poprzedniego posta? Otóż po kliknięciu na nazwę added z przetrzymanym ctrl przerzuciło mnie do pliku moc, w który znajdował się ten kawałek kodu ;) Tam dodałem qDebug().

0

To teraz wszystko jasne ;) emit added() to nic innego jak wywołanie tej implementacji z pliku wygenerowanym przez moc. Przedostatni argument to indeks slotu który ma być wywołany. W tym samym pliku jest metoda MyClass::qt_static_metacall , zobacz czy pod indeksem 0 kryje się Twój slot.

0

Tak, slot jest pod 0.

case 0: _t->added(); break; 

EDIT:
Wcześniej sprawdziłem sygnał, slot jest pod 1 (plik moc_managewordlist.cpp)

1

W implementacji QMetaObject::activate jest taki warunek:

if (!sender->d_func()->isSignalConnected(signal_index))
        return;

Co mniej więcej oznacza, że nic nie zrobimy jeśli nic nie jest podłączone. Inną możliwością przeskoczenia slotu w pętli jest sprawdzenie czy odbiorca przypadkiem nie jest nullem:

if (!c->receiver)
            continue;

Obydwa te przypadki wskazywałyby, że ta inicjalizacja:

newWord = new addNew(this, words);

musiałaby zostać przeniesiona przed wywołaniem connect (zwróciłem już na to uwagę wcześniej). W tej chwili nie widzę innej możliwości dlaczego slot miałby się nie wykonać.

0

Też o tym myślałem, jeszcze wcześniej

 newWord = new addNew(this, words);

wrzuciłem do konstruktora przed connect.

W pliku moc_addnew.cpp zmieniłem na:

 void addNew::added()
{
    QMetaObject::activate(this, &staticMetaObject, 1, 0);
}

i nadal nie działa :/ Tylko teraz jest taka różnica, że jak ustawię na 0 to program przestaje działać :)

EDIT:
W konstruktorze dodałem:

if(newWord)
    {
        qDebug()<<"Tutaj - sprawdzam newWord";
        connect(newWord, SIGNAL(added()), this, SLOT(paintTree())); //przerysowanie drzewa po dodaniu słowa
    } else {
        qDebug()<<"Tutaj - sprawdzam newWord - nie ma nic!";
    } 

i pojawia się tylko jeden komunikat z tego warunku. Po wysłaniu sygnału added() powinien pojawić się któryś z nich. Wychodzi na to, że tylko przy tworzeniu obiektu jest łapany sygnał - własność konstruktora. W takim razie gdzie wrzucić connect żeby sygnał był łapany cały czas?

0

Nie zmieniaj nic w plikach moc! Wrzuć inicjalizację przed connect --> qmake --> budowanie. Nic więcej.

0

Jeżeli dobrze zrozumiałem:

  1. odpaliłem qmake -o makefile slowka.pro
  2. zbudowałem projekt w kreatorze (Budowanie -> Zbuduj projekt)
  3. uruchomiłem
    Niestety dalej to samo.
0

Hm, użyj klasy QSignalSpy do przetestowania co się dzieje z Twoim sygnałem. Z tego co pokazałeś nie widzę co mogłoby być nie tak.

0

Wrzuciłem kod zliczania sygnałów i przez qDebug() wyświetlam tą ilość.
Kod zaraz po emisji sygnału (addNew):

qDebug()<<spy->count();

w konstruktorze addNew

spy = new QSignalSpy(this, SIGNAL(added()));

Nie wiem też dlaczego cały czas, przy każdym budowaniu projektu w pliku moc_addnew.cpp w funkcji:

 // SIGNAL 0
void addNew::added()
{
    QMetaObject::activate(this, &staticMetaObject, 0, 0);
}

slot jest ustawiany na 0, a nie na 1.

A może macie jakieś inne pomysły w jaki sposób wywoływać funkcje klasy rodzica w klasie potomka?

1

Zamiast szukać niestworzonych rzeczy w pliku moc pokaż, większy kawałek kodu.

Poza tym jest debuger. Wstaw breakpoint w miejsce emita i już będziesz wiedział, czy sygnał jest emitowany czy nie.
Drugą rzeczy jest zweryfikowanie czy sygnał i slot zostały połączone prawidłowo. Po pierwsze popatrz w logi (jeśli connect nie może wykonać połączania to w logach pojawia się odpowiednia informacja), a najlepiej popraw kod następująco:

bool connectOk;
connectOk = connect(newWord, SIGNAL(added()), this, SLOT(printTree()));
Q_ASSERT(connectOk);

Innych możliwości nie ma. Zwalanie winy na kod moc jest bezproduktywne.

0

Dziękuję wszystkim za pomoc, niestety nie doszedłem do tego dlaczego ten sygnał nie działa. Problem rozwiązałem poprzez wywołanie funkcji na rzecz obiektu rodzica (przekazywany do konstruktora).

 qobject_cast<manageWordList *>(parent())->printTree();
0

Dodałeś macro Q_OBJECT w obu klasach obsługujących signal/sloty? Zakładam, że obie dziedziczą po QObject bo by Ci rzuciło compile error na funckji connect

also jeżeli te signal sloty posiadają argumenty musisz zarejestrować typy

0

Próbowałeś moich rad? Popatrzyłeś w logi? Sprawdziłeś czy connect kończy się sukcesem?
Może pokaż swój kod w całości. Link do githuba albo zipa.

0
MarekR22 napisał(a):

Próbowałeś moich rad? Popatrzyłeś w logi? Sprawdziłeś czy connect kończy się sukcesem?

Właśnie wkleiłem Twój kod i wszystko ładnie działa. Co więcej, jeżeli wrzucę kod, który pokazywałem wcześniej również działa. Sprawdzałem kilka razy, oczywiście wcześniej wyłączyłem wywołanie funkcji printTree() za pomocą obiektu rodzica.

Dziękuję za pomoc :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1