2017-09-28 5 views
0

Je sais comment créer un ProgressBar fonctionnant avec le style PBS_MARQUEE, mais j'ai du mal à l'implémenter dans une situation où je veux l'animation de sélection tant que long_operation() fonctionne, sans avoir à appeler SendMessage(hPB, PBM_STEPIT, 0, 0); en continu de long_operation() pour avancer l'animation.Comment faire fonctionner ProgressBar avec le style PBS_MARQUEE?

Voici une de mes tentatives infructueuses:

INT_PTR CALLBACK ProgressDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { 
    switch(message) { 
     case WM_INITDIALOG: 
     { 
      HWND hProgressBar = GetDlgItem(hWnd, IDC_PROGRESS1);     
      LONG_PTR style_flags = GetWindowLongPtr(hProgressBar, GWL_STYLE); 
      SetWindowLongPtr(hProgressBar, GWL_STYLE, style_flags | PBS_MARQUEE); 

      SendMessage(hProgressBar, (UINT)PBM_SETMARQUEE, (WPARAM)1, (LPARAM)NULL); 

      break; 
     } 
    } 

    return FALSE; 
} 

void long_operation() { 
    for(int i = 0; i < 9; ++i) { 
     for(int j = 0; j < 99999999; ++j) 
     ; 
     Beep(5000, 100); 
    } 
} 

void do_operation() { 
    HWND hDlg = CreateDialog(Dll_globals::g_hInst, 
          MAKEINTRESOURCE(IDD_DIALOG4), // assume this contains a ProgressBar ctl 
          Dll_globals::g_hWndMain, ProgressDlgProc); 
    if(hDlg) { 
     ShowWindow(hDlg, SW_SHOW); 
     UpdateWindow(hDlg); 
    } 

    long_operation(); 
} 

Ce que je reçois avec le code ci-dessus est une barre de progression marquee sans animation tout continue à émettre des bips, puis un chapiteau d'animation normale quand il arrête. Pour autant que je sache, puisque long_operation() bloque le thread, les files d'attente de messages sont également bloquées et le message de mise à jour 30ms par défaut n'est pas envoyé/reçu par le contrôle ProgressBar. Je pense qu'il doit y avoir une manière intuitive de le faire, mais je ne peux pas le comprendre.

De quoi s'agit-il?

+0

Pas si sûr si std :: thread a déjà été accusé d'être intuitif. Mais c'est ce qu'il faut pour garder votre thread d'interface utilisateur capable de mettre à jour la barre. Un curseur sablier au lieu d'une barre de progression est assez intuitif. –

+2

Décharge 'long_operation' sur un thread de travail. Cela peut être fait de plusieurs façons, par ex. en utilisant 'std :: thread',' std :: async', ou l'implémentation native de Windows ('CreateThread' /' _beginthreadex'). Notez en particulier que l'appel 'SendMessage' de' long_operation' implémente uniquement une solution partielle. Il empêche toujours l'envoi d'autres messages, ce qui provoque l'affichage de la boîte de dialogue, lorsqu'un utilisateur tente d'interagir avec lui, par exemple. – IInspectable

+0

Qu'est-ce qui se passe, c'est que vous travaillez dans le thread UI, ce qui rend l'interface utilisateur ne répond pas. Résolvez ce problème en faisant le travail dans un thread d'arrière-plan. –

Répondre

0

Si vous préférez rester avec un thread, vous devez périodiquement pomper des messages pour que la fenêtre puisse être déplacée ou rafraîchie si elle n'est pas couverte.

// Process all queued messages. Handle keyboard dialog nawigation 
// for dialog_hwnd. For more then one modeless dialog modify code by 
// calling IsDialogMessage for each dialog. 
void PumpMesages(HWND dialog_hwnd) { 
    MSG msg; 
    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) { 
     // Handling modeless dialog nawigation. 
     if (dialog_hwnd && IsDialogMessage(dialog_hwnd)) 
      continue; 

     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
} 

void long_operation(HWND dialog_hwnd, HWND progress_hwnd) { 
    for(int i = 0; i < 9; ++i) { 
     for(int j = 0; j < 99999999; ++j) 
     ; 

     // I'm not shure if this is needed. 
     // I have always used propper progress bar (PBM_SETPOS). 
     SendMessage(progress_hwnd, PBM_STEPIT, 0, 0); 
     // Periodically process messages. 
     PumpMessages(dialog_hwnd); 

     Beep(5000, 100); 
    } 
} 

void do_operation() { 
    HWND hDlg = CreateDialog(Dll_globals::g_hInst, 
          MAKEINTRESOURCE(IDD_DIALOG4), // assume this contains a ProgressBar ctl 
          Dll_globals::g_hWndMain, ProgressDlgProc); 
    if(hDlg==0) 
     return; 

    ShowWindow(hDlg, SW_SHOW); 

    // Disable input processing in main window if there is possibility 
    // of recursion. For example, user select Open file, we begin 
    // loading and inside PumpMessages, user can again select Open 
    // file so we will end with two progress dialogs and nested 
    // message loops. 
    EnableWindow(Dll_globals::g_hWndMain,FALSE); 

     long_operation(hDlg, GetDlgItem(hDlg, progress_bar_id_here)); 

    // Remember to enable input processing in main window. 
    EnableWindow(Dll_globals::g_hWndMain,TRUE); 
} 

Ceci peut être amélioré en ajoutant le bouton Abandonner, la manipulation WM_COMMAND dans ProgressDlgProc, un certain réglage de drapeau (Dll_globals :: g_Abort?) Et partir tôt long_operation. Going multithread, Vous devez établir un protocole pour démarrer le travail (cela dépend de l'API que vous sélectionnez) et signaler l'achèvement (cela peut être fait par PostMessage avec un message personnalisé ou même WM_COMMAND avec un ID de contrôle adéquat). Même dans ce scénario, méfiez-vous des problèmes potentiels lorsque l'utilisateur recommence la même opération avant la fin de l'appel précédent.

+0

Cette solution proposée interrompt la navigation au clavier dans la boîte de dialogue. La navigation au clavier est implémentée par l'appel de l'API [IsDialogMessage] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms645498.aspx). – IInspectable

+0

Oui, vous avez raison, nous utilisons une boîte de dialogue non modale donc IsDialogMessage est nécessaire pour gérer la navigation en kayboard. Oublié à ce sujet. Code mis à jour –

+0

Un problème avec cette solution est qu'elle peut créer des retards lorsque l'utilisateur interagit avec l'interface utilisateur. 'long_operation' peut ne pas être capable d'appeler' PumpMessages() 'dans des intervallations assez courtes. Même si c'est le cas, si 'PumpMessages()' est appelé à partir d'une boucle interne, cela peut gêner les performances. – zett42