Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++ wxWidgets] Brak odpowiedzi programu po wywołaniu funkcji

Ostatnio zmodyfikowano 2016-07-06 13:00
Autor Wiadomość
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.

C/C++
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 )
            {
                //informacja dla użytkownika;
            }
            .
            .
            .
            if( i == 9 )
            {
                //informacja dla użytkownika;
            }
        }
    }
}

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:
C/C++
#include "mingw.thread.h"
thread dw( download, i );
dw.detach();
jak i:
C/C++
#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
P-149412
mateczek
» 2016-06-23 17:53:25
ja nie pisze w wxWidget. Ale przez analogię do QT, który ma qThread. Poszukał bym wxThread :)
P-149417
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.


C/C++
for( int i = 0; i < 10; i++ )
{
    download( i ); // <--- wtf?!
   
    int wynik = download( i );
    ...
Dwa razy to samo ściągasz?
P-149419
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?
C/C++
#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 ); // that's all
    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

C/C++
for( int i = 0; i < 10; i++ )
{
    download( i ); // <--- wtf?!
   
    int wynik = download( i );
 
to omyłka pisarska  ;)
P-149691
j23
» 2016-07-05 18:45:47
Nie rozumiem pytania. O to Ci chodzi?
C/C++
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,
C/C++
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?
P-149706
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 ;)
P-149720
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.
P-149725
« 1 »
  Strona 1 z 1