Przenoszenie czasochłonnych operacji do osobnego wątku

0

W sumie nie wiem czy dobrze określiłem problem w temacie. Mam okno pomiarowe, które w trakcie pracy prezentuje się mniej więcej tak:
http://i56.tinypic.com/24uwdch.jpg
W trakcie pomiaru, czyli wypełniania QTableWidget nie mogę kliknąć żadnego buttona, nawet counter u góry nie startuje mimo że rozpoczęcie jego pracy jest wywoływane przed pomiarem. Gdy próbuję kliknąć buttona okno wygląda tak:
http://i55.tinypic.com/2m5i45v.jpg
Nie dostaję jakiegoś krytyka, po prostu okno się blokuje na dobre i dostaję do niego dostęp gdy pomiar się skończy, wtedy też wyświetlane są wszystkie wartości pomiaru. Pętla pomiarowa wygląda tak:

    counter->Start();
    ui->measEndButton->setEnabled(true);
    int row=0;

    for(int i=1;i<=10;i++)
    {
        
        if(!device->PrepareRequest(i,500)){
            break;
        }
        device->SendRequest();
        QString text=device->GetData();
        table->InsertValue(row,0,text);
        ++row;
        if(measBreak){
            break;
        }
        this->repaint();
    }
    ui->measEndButton->setEnabled(false); 

Gdzie 'table' jest typu dziedziczącego z QTableWidget. Dane z 'device' przychodzą z opóźnieniem i na początku poszczególne komórki nie chciały się wyświetlić, dopiero po wyjściu z pętli pojawiały się wartości. Dodanie repaint() pomogło ale podejrzewam że ta metoda coś tu jednak psuje. 'counter' też zacznie odliczać dopiero gdy program wyjdzie z pętli.

0

Bracie several co to jest to device?QIODevice?
co do repainta,to on jest czymś w rodzaju 'brute force' odświeżania.Spróbuj update'a,ten powinien przemalować tylko te indeksy co potrzeba

0

Gdy używam update() to mam taki sam efekt jakbym nie używał żadnego odświeżania, czyli wszystkie wartości w tabeli są wyświetlane po wyjściu z pętli. A 'device' to mój interfejs do obsługi mojego urządzenia z którym komunikuje się po RS232. Zawarłem w nim szczątkowe elementy Qt, nie ma nawet sygnałów i slotów, większość to WinApi. Mnie najbardziej dziwi że counter (odświeżany przez QTime) zastyga gdy program wchodzi do pętli pomiaru. Myślałem żeby wrzucić tą pętlę do innego wątku (QTConcurrent::run) ale nie mogę modyfikować obiektów stworzonych w innym wątku :/

1

Counter zastyga chyba potemu,że pętla komunikatów jest zajęta twoim device->getData,ponadto tłumaczyłoby to czemu nie masz reakcji od przycisków etc...Cóż,chyba jednak bez QThreada się nie obędzie :/
Co do modyfikacji,to bez problemu możesz używać mechanizmu sygnał/slot pomiędzy wątkami,jednak w nowych wątkach nie możesz tworzyć widgetów.

Ewentualnie jeszcze możesz zamrozić program wyświetlając QProgressDialog,jednak to pewnie nie pomoże na zawieszony licznik

0
MasterBLB napisał(a)

Co do modyfikacji,to bez problemu możesz używać mechanizmu sygnał/slot pomiędzy wątkami,jednak w nowych wątkach nie możesz tworzyć widgetów.

Hmm, wywołując table->InsertValue() wypełniam komórki tabeli dodając elementy typu QTreeWidgetItem*. Mogę tak to zostawić czy inaczej muszę kombinować?

MasterBLB napisał(a)

Ewentualnie jeszcze możesz zamrozić program wyświetlając QProgressDialog,jednak to pewnie nie pomoże na zawieszony licznik

Chciałbym mieć możliwość przerywania pętli (pomiaru) w trakcie jej trwania poprzez kliknięcie buttona, czyli nie za bardzo mogę zamrozić program.

1

To insertValue musi być Twoim wynalazkiem,bo w assistancie nie widzę tego.Anyway,rozpatrując problem całościowo:
1.Tworzysz QThread z wszelakimi regułami sztuki ( Assistant reading :P ) z sygnałem wymienionym niżej.Podłączasz ów sygnał do swojego slotu.
2.W tym 2 wątku masz tą swoją pętlę czytającą wynik-tam wrzucasz konstrukcję emit signalConnectedToaSlotInYaMainThread(device->getData());
3.W slocie robisz te swoje czarymary z insertValue

oczywiście,będzie jeszcze trzeba obsłużyć wspomnianą sytuację przerywania pomiaru,ale to wrócimy do zagadnienia jak powyższe będzie już hulało jak Bracie potrzebujesz ;)

EDIT:
Szybki rzut oka w dokumentację QProgressDialogu pokazuje,że nim też powinno się dać-piszą o możliwości przerwania operacji.

0

Hell yeah, miałeś rację, to sam pomiar blokował formę. Wrzuciłem do osobnego wątku, zrobiłem sygnał jak napisałeś i działa (wyniki pomiaru na razie w konsoli):
http://i54.tinypic.com/2lasjo4.jpg

No i teraz...pewnie żeby przerwać pomiar muszę zrobić sygnał w druga stronę? Aa i co zrobić by mieć pewność, że wątek pomiaru został NA PEWNO zamknięty?

edit
Kurcze, chyba powinienem zmienić nazwę tematu.

1

E nie,sygnały nie są konieczne.Po prostu,jak gdzieś stworzyłeś sobie obiekt YaThread to po pomiarze wywołujesz YaThread->quit() (ew. terminate()) i tyle.Możesz i załatwić sprawę sygnałem,jako że te 2 funkcje QThreada są zarazem slotami.

0

quit() wymaga event loop, do jego zainicjowania potrzebuję wywołać exec() w run(). Tylko że w run() mam pętlę która w skrajnych przypadkach może wykonywać się 3 minuty z groszem (ilość mierzonych ogniw * ustawiany czas na pomiar każdego ogniwa), exec() wywołany gdziekolwiek poza ostatnim wierszem ciała run() spowoduje nie wykonanie się pętli w całości. Pozostaje mi terminate() ale czytam w assistancie że ta metoda jest be. Z resztą po jej wywołaniu nie mogę wznowić pomiaru. Hmm...najwyżej tak to zostawię, ale pokombinuje jeszcze z wait(). Dziękuję panowie.

ps. Muszę wymyślić adekwatniejszy tytuł dla tematu.

0

Ja bym Bracie several kończenie wątku kombinował w tym slocie co to odbiera dane-ot np w YaThread za ciałem pętli pobierającej dane wyślesz ten sam sygnał ze stringiem "measurementFinished",a slocie wpisującym do tabelki badasz czy na dzień dobry:

if(sentString!="measurementFinished")
{
     insertValue(sentString);//czy jak to tam u Ciebie idzie
}
else YaThread->quit();

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