ptosiek Temat założony przez niniejszego użytkownika |
[C++ wxWidgets] Brak odpowiedzi programu po wywołaniu funkcji » 2016-06-23 14:45:15 Witam Mam problem z „kawałkiem” programu. Jest to aplikacja okienkowa (wxWidgets). W oknie znajduje się przycisk, który wywołuję download, który jest prostym klientem ftp wykorzystującym biblioteki curl. Zadanie owego okienka to po wciśnięciu przycisku klient ftp ma pobrać z serwera 10 plików bmp i po każdym pobraniu pliku ma być wyświetlane jakiś info dla użytkownika. void Start::Onbutton_1( wxCommandEvent & WXUNUSED( event ) ) { for( int i = 0; i < 10; i++ ) { download( i ); int wynik = download( i ); if( wynik = 0 ) { if( i == 0 ) { } . . . if( i == 9 ) { } } } }
Problem polega na tym, że jak wywołuję download okno „zamarza” (w górnym pasku komunikat „brak odpowiedzi”). Aby rozwiać problem download dałem do osobnego wątku. Niestety w przypadku: #include "mingw.thread.h" thread dw( download, i ); dw.detach();
jak i: #include <process.h> HANDLE hThread =( HANDLE ) _beginthread( download, i, NULL );
nie jest w stanie uzyskać zamierzonego celu, czyli wywołanie download bez „zamrażania” okna programu. Czy ma ktoś pomysł na rozwiązanie problemu? Moje środowisko: Code::Blocks/MinGW, okienka: wxWidgets |
|
mateczek |
» 2016-06-23 17:53:25 ja nie pisze w wxWidget. Ale przez analogię do QT, który ma qThread. Poszukał bym wxThread :) |
|
j23 |
» 2016-06-23 19:38:24 Aby rozwiać problem download dałem do osobnego wątku. |
Przenieś całą pętle do oddzielnego wątku ( wxThread). O postępach w ściąganiu plików możesz informować wątek główny/okno za pomocą wxEvtHandler::QueueEvent i klasy wxThreadEvent. for( int i = 0; i < 10; i++ ) { download( i ); int wynik = download( i ); ...
|
Dwa razy to samo ściągasz? |
|
ptosiek Temat założony przez niniejszego użytkownika |
» 2016-07-05 13:36:06 Dziękuje za pomoc. Skorzystałem z przykładu wxThread i zadziałało. Jednak mam problem jak wywołać MyFrame::OnStartThread przy akcji przycisku MyFrame::m_button_job? #include "thread.h" #include "tdownload.h" #include "wx/wxprec.h" #ifndef WX_PRECOMP #include "wx/wx.h" #endif #if !wxUSE_THREADS #error "This sample requires thread support!" #endif #include "wx/thread.h" #include "wx/dynarray.h" #include "wx/time.h" #include "wx/numdlg.h" #include "wx/progdlg.h" #define USE_EXECUTE #ifdef USE_EXECUTE #define EXEC(cmd) wxExecute((cmd), wxEXEC_SYNC) #else #define EXEC(cmd) system(cmd) #endif using namespace std; IMPLEMENT_APP( MyApp ) enum { THREAD_QUIT = 1, THREAD_CLEAR, THREAD_START_THREAD = 201, WORKER_EVENT }; MyThread::MyThread( MyFrame * frame ) : wxThread() { m_count = 0; m_frame = frame; } void MyThread::OnExit() { wxCriticalSectionLocker locker( wxGetApp().m_critsect ); wxArrayThread & threads = wxGetApp().m_threads; threads.Remove( this ); if( threads.IsEmpty() ) { if( wxGetApp().m_waitingUntilAllDone ) { wxGetApp().m_waitingUntilAllDone = FALSE; wxMutexLocker lock( wxGetApp().m_mutexAllDone ); wxGetApp().m_condAllDone.Signal(); } } } void * MyThread::Entry() { cout << "Start" << endl; for( int i = 0; i < 2; i++ ) { download( i ); } cout << "Stop" << endl; return NULL; } MyWorkerThread::MyWorkerThread( MyFrame * frame ) : wxThread() { m_frame = frame; m_count = 0; } void MyWorkerThread::OnExit() { } void * MyWorkerThread::Entry() { for( m_count = 0; !m_frame->Cancelled() &&( m_count < 100 ); m_count++ ) { if( TestDestroy() ) break; wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT ); event.SetInt( m_count ); wxPostEvent( m_frame, event ); wxThread::Sleep( 200 ); } wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT ); event.SetInt( - 1 ); wxPostEvent( m_frame, event ); return NULL; } BEGIN_EVENT_TABLE( MyFrame, wxFrame ) EVT_MENU( THREAD_QUIT, MyFrame::OnQuit ) EVT_MENU( THREAD_START_THREAD, MyFrame::OnStartThread ) EVT_MENU( WORKER_EVENT, MyFrame::OnWorkerEvent ) EVT_IDLE( MyFrame::OnIdle ) END_EVENT_TABLE() MyApp::MyApp() : m_condAllDone( m_mutexAllDone ) { m_mutexAllDone.Lock(); m_waitingUntilAllDone = FALSE; } MyApp::~MyApp() { m_mutexAllDone.Unlock(); } bool MyApp::OnInit() { MyFrame * frame = new MyFrame(( wxFrame * ) NULL, _T( "Watki" ), 770, 400 ); wxMenuBar * menuBar = new wxMenuBar; wxMenu * menuThread = new wxMenu; menuThread->Append( THREAD_START_THREAD, _T( "&Pobierz dane\tCtrl-N" ) ); menuBar->Append( menuThread, _T( "&Zadanie" ) ); frame->SetMenuBar( menuBar ); frame->Show( TRUE ); return TRUE; } MyFrame::MyFrame( wxFrame * frame, const wxString & title, int w, int h ) : wxFrame( NULL, wxID_ANY, title, wxDefaultPosition, wxSize( w, h ) ) { SetMinSize( GetSize() ); SetMaxSize( GetSize() ); Centre(); m_nRunning = m_nCount = 0; m_dlgProgress =( wxProgressDialog * ) NULL; wxPanel * m_panel = new wxPanel( this, wxID_ANY ); m_panel->SetBackgroundColour( wxColor( 201, 202, 204 ) ); wxButton * m_button = new wxButton( m_panel, wxID_ANY, _T( "Download" ), wxPoint( 50, 50 ), wxSize( 100, 50 ) ); m_button->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MyFrame::m_button_job ), NULL, this ); }
void MyFrame::m_button_job( wxCommandEvent & WXUNUSED( event ) ) { ??? } MyThread * MyFrame::CreateThread() { MyThread * thread = new MyThread( this ); if( thread->Create() != wxTHREAD_NO_ERROR ) { cout << "Problem ze stworzeniem nowego watku" << endl; } cout << "Watek stworzony \n" << endl; wxCriticalSectionLocker enter( wxGetApp().m_critsect ); wxGetApp().m_threads.Add( thread ); return thread; } void MyFrame::OnStartThread( wxCommandEvent & WXUNUSED( event ) ) { MyThread * thread = CreateThread(); if( thread->Run() != wxTHREAD_NO_ERROR ) { cout << "Problem z wystartowaniem nowego watku" << endl; } cout << "Nowy watek wystartowal" << "\n" << endl; } void MyFrame::OnIdle( wxIdleEvent & event ) { wxCriticalSectionLocker enter( wxGetApp().m_critsect ); size_t nRunning = 0, nCount = wxGetApp().m_threads.Count(); for( size_t n = 0; n < nCount; n++ ) { if( wxGetApp().m_threads[ n ]->IsRunning() ) nRunning++; } if( nCount != m_nCount || nRunning != m_nRunning ) { m_nRunning = nRunning; m_nCount = nCount; } } void MyFrame::OnQuit( wxCommandEvent & WXUNUSED( event ) ) { { wxGetApp().m_critsect.Enter(); const wxArrayThread & threads = wxGetApp().m_threads; size_t count = threads.GetCount(); if( count ) { for( size_t n = 0; n < count; n++ ) { threads[ n ]->Delete(); } wxGetApp().m_waitingUntilAllDone = TRUE; } wxGetApp().m_critsect.Leave(); if( count ) { wxMutexGuiLeave(); wxGetApp().m_condAllDone.Wait(); wxMutexGuiEnter(); } } Close( TRUE ); } void MyFrame::OnWorkerEvent( wxCommandEvent & event ) { #if 0 cout << ":)" << endl; #else int n = event.GetInt(); if( n == - 1 ) { m_dlgProgress->Destroy(); m_dlgProgress =( wxProgressDialog * ) NULL; wxWakeUpIdle(); } else { if( !m_dlgProgress->Update( n ) ) { wxCriticalSectionLocker lock( m_critsectWork ); m_cancelled = TRUE; } } #endif } bool MyFrame::Cancelled() { wxCriticalSectionLocker lock( m_critsectWork ); return m_cancelled; }
Jeśli chodzi o
for( int i = 0; i < 10; i++ ) { download( i ); int wynik = download( i );
|
to omyłka pisarska ;) |
|
j23 |
» 2016-07-05 18:45:47 Nie rozumiem pytania. O to Ci chodzi? void MyFrame::m_button_job( wxCommandEvent & event ) { OnStartThread( event ); } Jeśli tak, to trochę to bez sensu, bo od razu możesz podpiąć metodę OnStartThread do m_button. PS, void MyFrame::OnIdle( wxIdleEvent & event ) { wxCriticalSectionLocker enter( wxGetApp().m_critsect ); size_t nRunning = 0, nCount = wxGetApp().m_threads.Count(); for( size_t n = 0; n < nCount; n++ ) { if( wxGetApp().m_threads[ n ]->IsRunning() ) nRunning++; } if( nCount != m_nCount || nRunning != m_nRunning ) { m_nRunning = nRunning; m_nCount = nCount; } } to twój kod? |
|
ptosiek Temat założony przez niniejszego użytkownika |
» 2016-07-06 12:13:30 Jak pisałem Skorzystałem z przykładu wxThread i zadziałało.
|
Jednak to rozwiązanie jest zbyt „rozbudowane”, dodatkowo jest tworzony nowy obiekt aplikacji co mi komplikuje sprawę. Chciałem szybko, ale nie tym razem ;) |
|
j23 |
» 2016-07-06 13:00:46 No właśnie, też mi się wydawało, że za dużo tu tego, jeśli patrzeć na twój problem. |
|
« 1 » |