Qt Connect - wyłapywanie sygnałów

Qt Connect - wyłapywanie sygnałów
B3
  • Rejestracja:ponad 11 lat
  • Ostatnio:9 miesięcy
  • 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:prawie 16 lat
  • Ostatnio:dzień
0

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


B3
  • Rejestracja:ponad 11 lat
  • Ostatnio:9 miesięcy
  • 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:prawie 16 lat
  • Ostatnio:dzień
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ś.


edytowany 1x, ostatnio: several
B3
  • Rejestracja:ponad 11 lat
  • Ostatnio:9 miesięcy
  • 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:prawie 16 lat
  • Ostatnio:dzień
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:ponad 11 lat
  • Ostatnio:9 miesięcy
  • 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)

edytowany 2x, ostatnio: bryla33
several
  • Rejestracja:prawie 16 lat
  • Ostatnio:dzień
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:ponad 11 lat
  • Ostatnio:9 miesięcy
  • 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?

edytowany 1x, ostatnio: bryla33
several
  • Rejestracja:prawie 16 lat
  • Ostatnio:dzień
0

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


B3
  • Rejestracja:ponad 11 lat
  • Ostatnio:9 miesięcy
  • 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:prawie 16 lat
  • Ostatnio:dzień
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:ponad 11 lat
  • Ostatnio:9 miesięcy
  • 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?

edytowany 1x, ostatnio: bryla33
MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:7 minut
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.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
B3
  • Rejestracja:ponad 11 lat
  • Ostatnio:9 miesięcy
  • 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:około 11 lat
  • Ostatnio:ponad 3 lata
  • 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

edytowany 1x, ostatnio: gośćabc
MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:7 minut
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.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
B3
  • Rejestracja:ponad 11 lat
  • Ostatnio:9 miesięcy
  • 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 :)

several
Dodałeś asercje i zaczęło działać? No ciekawe, ciekawe :)
MarekR22
musiały się skopać zależności plików i w momencie kiedy zmodyfikowałeś plik zawierający connect to zależności musiały się naprawić. Niestety takie rzeczy się zdarzają (zwłaszcza jak się manipuluje kontrolą wersji).
B3
several no jasne, że dodanie asercji nie zdziałało cudów ;) źle się wypowiedziałem MarekR22 wcześniej nie spotkałem się z tym problemem, dziękuję za pomoc :)
MarekR22
w narzędziu make jest coś skopane (domyślny build manager dla qt) i czasami nie przebudowuje niektórych plików, kiedy jest to potrzebne. Zdarza się to niezwykle rzadko, ale jednak (widziałem to na Windowsie i na Linux-ie). Wyczyszczenie projektu i budowa od początku zwykle pomaga (bolesne jeśli projekt jest naprawdę duży).

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.