2009-11-03 21 views
9

Mi aplicación puede tardar un tiempo en conectarse a una base de datos. Esta conexión se realiza con una sola llamada de función de biblioteca, es decir, no puedo poner actualizaciones de progreso allí y hacer devoluciones de llamada o algo similar.¿Cómo crear un cuadro de diálogo MFC con una barra de progreso en un hilo separado?

Mi idea era crear un diálogo con una barra de progreso en un hilo separado antes de conectar con la base de datos. Este diálogo cambiará continuamente el estado del progreso con CProgressCtrl::StepIt() para que el usuario vea que algo está sucediendo.
Después de que el cuadro de diálogo esté configurado y haciendo lo suyo, quiero llamar a la función de conexión de DB desde el hilo principal. Después de completar la función de conexión, quiero detener el hilo de la barra de progreso.

me deja pintar un cuadro:

CMyApp::  ProgressThread 
InitInstance()  . 
    |    . 
    |    . 
    +-Create Dialog-+ 
    |    | 
    |    Animate 
Connect   Progress 
    to    Bar 
    DB    | 
    |    | 
    +-Destroy Dlg---+ 
    |    . 
    |    . 

¿Es posible? Si es así, ¿cómo?

Tal vez todo funcione con temporizadores, también. Probablemente sería mucho más simple, pero tampoco pude lograr que funcionara.

  1. Soy consciente de CProgressCtrl::SetMarquee() que podría hacer exactamente lo que necesito, pero no puedo usarlo porque la aplicación no tiene soporte para Unicode.
  2. Podría mover la llamada a la conexión db a un hilo separado, pero de esa manera parece que hay muchos cambios en el código y un manejo adicional de los errores de conexión.

Actualización 2
lo tengo trabajando de la manera AlexEzh y Javier De Pedro sugirieron: Poner el stuf DB en su propio hilo.
inicialmente me preocupaba cómo se podía manejar el error, pero en realidad es bastante similar a cómo era antes.

  1. En el hilo principal, creo una estructura con parámetros de conexión, indicador de resultado y indicador de ejecución de hilo. El último se establece inicialmente en true.
  2. Creo un hilo y paso esa estructura como parámetro.
  3. Creo un cuadro de diálogo que muestra una barra de progreso en el hilo principal.
  4. También en el hilo principal hay un bucle que se ejecuta mientras se establece thread-running-flag. Llama al CMyDialog::Animate() que llama a CProgressCtrl::StepIt() y luego a Sleep() s un poco.
  5. El subproceso ejecuta el código de conexión db y establece el indicador de ejecución en false cuando finaliza.
  6. Cuando el hilo principal sale del lazo puede manejar errores exactamente como lo hacía antes.

Desventaja: Mover el mouse sobre la ventana no funciona. Es invisible. Por lo tanto, no se puede usar ningún botón de cancelar u otros elementos de diálogo interactivos. Sin embargo, puedo vivir con eso.

Dado que te gustó el diagrama, aquí es la forma en que ahora se ve así:

CMyApp::  WorkerThread 
InitInstance()  . 
    |    . 
    |    . 
Create Dialog  . 
    |    . 
    +-Start Thread--+ 
    |    | 
    |    Connect 
Animate   to 
Progress   DB 
    Bar    | 
    |    | 
    +-Thread Ends---+ 
    |    . 
Destroy Dlg  . 
    |    . 
+3

+1 para el diagrama –

+0

Puede llamar SetMarquee() en una aplicación ANSI, pero no va a ayudar ya que el contador de tiempo que anima a la barra de progreso se llama en el hilo principal también –

+0

En mi afxcmn.h se ve así: ** if (_WIN32_WINNT> = 0x0501) && defined (UNICODE) \ n BOOL SetMarquee (_In_ BOOL fMarqueeMode, _In_ int nInterval); \ n #endif \t // _WIN32_WINNT> = 0x0501 && defined (UNICODE) \ n ** Y es por eso que no puedo llamarlo. – foraidt

Respuesta

2

Todavía sería más seguro mover la lógica de conexión DB a la secuencia separada. Con DB en el hilo de diálogo, podrá volver a pintar la barra de progreso pero no otros controles en el cuadro de diálogo.

+0

Puedo repintar todo el cuadro de diálogo llamando a RedrawWindow(). Si no hago eso, solo la barra de progreso está animada. – foraidt

7

espero this artículo sobre la creación de la pantalla de bienvenida propia de rosca con la barra de progreso puedan ser de utilidad. Lo escribí mientras resolvía el problema con el bloqueo de subprocesos en el nivel de cola de mensajes de MFC.

2
  1. Crear hilo de trabajo usando AfxBeginThread.
  2. En ese hilo Crea un CProgressCtrl y llama al Create, pasa el diálogo como padre del CProgressCtrl, utiliza el estilo de marquesina para el control de progreso.
  3. En el subproceso crea un bucle de espera de mensaje:

    MSG msg;
    mientras (GetMessage (& Msg, NULL, 0, 0))
    {
    TranslateMessage (& msg);
    DispatchMessage (& msg);
    }

  4. El bucle de mensaje necesita comprobar una bandera global para ver si sale del bucle.

+0

Eso no funcionará. Lee mi respuesta –

+1

@Kirill Esto funciona para mí, en mi proyecto, ¿qué es exactamente lo que no funciona? –

+0

El hilo MFC podría estar bloqueado en la función Crear. Para evitar eso, debe usar subprocesos que no sean MFC. –

1

Ha intentado utilizar SendMessage con PBM_SETMARQUEE en lugar de SetMarquee. Nunca me he probado, pero debería funcionar.

En mi opinión, la manera más fácil de lograr lo que quiere hacer es hacer la conexión ProgressBar y DB en el hilo ui y usar OnTimer para llamar al StepIt en la barra de progreso. También puede crear la barra de progreso en el subproceso ui y usar un mensaje personalizado para el subproceso activo para modificar el estado del progreso.

De todos modos, estoy de acuerdo con AlexEzh en que la mejor manera de hacerlo es hacer que toda la interfaz no relacionada con la interfaz funcione en el hilo de trabajo.

+0

Enviar un mensaje no tuvo ningún efecto, cuando lo intenté. – foraidt

1

Crear una variable miembro como

CProgressCtrl m_progress; 

añadir el m_progress en DDX_Control en DoDataExcchange con el ID de barra de progreso

agregar el código siguiente en función de clic de botón.

m_progress.setRange(0,100); 
m_progress.SetPos(1); 
+0

Esta es solo información muy básica que no se solicitó ni soluciona el problema de subprocesos múltiples. – foraidt

Cuestiones relacionadas