Qt Connect - wyłapywanie sygnałów

Qt Connect - wyłapywanie sygnałów
B3
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 79
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:

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

W konstruktorze klasy manageWordList mam funkcję connect:

Kopiuj
  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.

several
  • Rejestracja: dni
  • Ostatnio: dni
0

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

B3
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 79
0

Wrzuciłem w

Kopiuj
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.

several
  • Rejestracja: dni
  • Ostatnio: dni
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):

Kopiuj
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ś.

B3
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 79
0

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

Kopiuj
signals:
    void added();

następnie tam gdzie chcę go wyrzucić:

Kopiuj
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().

several
  • Rejestracja: dni
  • Ostatnio: dni
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.

B3
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 79
0

Tak, slot jest pod 0.

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

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

several
  • Rejestracja: dni
  • Ostatnio: dni
1

W implementacji QMetaObject::activate jest taki warunek:

Kopiuj
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:

Kopiuj
if (!c->receiver)
            continue;

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

Kopiuj
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ć.

B3
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 79
0

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

Kopiuj
 newWord = new addNew(this, words);

wrzuciłem do konstruktora przed connect.

W pliku moc_addnew.cpp zmieniłem na:

Kopiuj
 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:

Kopiuj
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?

several
  • Rejestracja: dni
  • Ostatnio: dni
0

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

B3
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 79
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.
several
  • Rejestracja: dni
  • Ostatnio: dni
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.

B3
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 79
0

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

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

w konstruktorze addNew

Kopiuj
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:

Kopiuj
 // 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?

MarekR22
  • Rejestracja: dni
  • Ostatnio: dni
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:

Kopiuj
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.

B3
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 79
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).

Kopiuj
 qobject_cast<manageWordList *>(parent())->printTree();
gośćabc
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Szczecin
  • Postów: 500
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

MarekR22
  • Rejestracja: dni
  • Ostatnio: dni
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.

B3
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 79
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 :)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.