简体   繁体   English

如何在单独的线程中创建带有进度条的MFC对话框?

[英]How to create a MFC dialog with a progress bar in a separate thread?

My application may take a while to connect to a database. 我的应用程序可能需要一段时间才能连接到数据库。 This connection is made with a single library function call, ie I cannot put progress updates in there and make callbacks or something similar. 这个连接使用单个库函数调用,即我不能在其中放入进度更新并进行回调或类似的操作。

My idea was to create a dialog with a progress bar in a separate thread before connecting to the DB. 我的想法是在连接到数据库之前在单独的线程中创建一个带有进度条的对话框。 This dialog will continually change the progress status with CProgressCtrl::StepIt() so the user sees something happening. 此对话框将使用CProgressCtrl::StepIt()不断更改进度状态,以便用户看到发生的事情。
After that dialog is set up and doing its thing I want to call the DB connection function from the main thread. 在设置完对话框并执行其操作之后,我想从主线程调用数据库连接函数。 After the connection function completed, I want to stop the progress bar thread. 连接功能完成后,我想停止进度条线程。

Let me paint a picture: 让我画一幅画:

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

Is that possible? 那可能吗? If yes, how? 如果有,怎么样?

Maybe the whole thing would work using timers, too. 也许整个事情也可以使用计时器。 Would probably be much simpler but I couldn't get that to work either. 可能会简单得多,但我也无法做到这一点。

  1. I am aware of CProgressCtrl::SetMarquee() which might do exactly what I need but I can't use it because the application does not have Unicode support. 我知道CProgressCtrl::SetMarquee()可能正是我需要的,但我不能使用它因为应用程序没有Unicode支持。
  2. I could move the db connection call into a separate thread but that way it looks like a lot of changes to the code and extra handling of connection errors. 我可以将数据库连接调用移动到一个单独的线程中,但这样看起来像代码的大量更改和连接错误的额外处理。

Update 2 更新2
I got it working the way AlexEzh and Javier De Pedro suggested: Put the DB stuf into its own thread. 我按照AlexEzh和Javier De Pedro建议的方式工作:将DB stuf放入自己的线程中。
initially I had concerns about how error handling could be done but it's actually quite similar to how it was before. 最初我担心如何处理错误,但它实际上与之前的情况非常相似。

  1. In the main thread I create a struct with connection parameters, result flag and thread-running-flag. 在主线程中,我创建了一个带有连接参数的结构,结果标志和thread-running-flag。 The latter is initially set to true . 后者最初设置为true
  2. I create a thread and pass that struct as parameter. 我创建一个线程并将该结构作为参数传递。
  3. I create a dialog that displays a progress bar in the main thread. 我创建了一个在主线程中显示进度条的对话框。
  4. Also in the main thread there is a loop that runs while the thread-running-flag is set. 同样在主线程中,有一个循环在设置thread-running-flag时运行。 It calls CMyDialog::Animate() which calls CProgressCtrl::StepIt() and then Sleep() sa bit. 它调用CMyDialog::Animate()调用CProgressCtrl::StepIt()然后调用Sleep()
  5. The thread executes the db-connection code and sets the running-flag to false when done. 该线程执行db-connection代码并在完成false running-flag设置为false
  6. When the main thread exits the loop it can handle errors exactly as it did before. 当主线程退出循环时,它可以完全像以前一样处理错误。

Disadvantage: Moving the mouse over the window doesn't work. 缺点:将鼠标移到窗口上不起作用。 It's invisible. 它是看不见的。 Thus no cancel-button or other interactive dialog elements can be used. 因此,不能使用取消按钮或其他交互式对话元素。 I can live with that, however. 但是,我可以忍受这一点。

Since you liked the diagram, here is how it now looks like: 既然您喜欢这个图表,现​​在的样子如下:

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

I hope this article about creating own-thread splash screen with progress bar could be helpful. 我希望文章有关与进度条创建自己的线程启动画面可能会有所帮助。 I wrote it while solving the problem with thread locking at MFC message queue level. 我在解决MFC消息队列级别的线程锁定问题时编写了它。

  1. Create worker thread using AfxBeginThread . 使用AfxBeginThread创建工作线程。
  2. In that thread Create a CProgressCtrl and call Create , pass the dialog as the parent of the CProgressCtrl, use the marquee style for the progress control. 在该线程中创建一个CProgressCtrl并调用Create ,将对话框作为CProgressCtrl的父级传递,使用选取框样式进行控制。
  3. In the Thread create a message waiting loop: 在Thread中创建一个消息等待循环:

    MSG msg; MSG消息;
    while(GetMessage(&Msg, NULL, 0, 0)) while(GetMessage(&Msg,NULL,0,0))
    { {
    TranslateMessage(&msg); 的TranslateMessage(MSG);
    DispatchMessage(&msg); DispatchMessage函数(MSG);
    } }

  4. The message loop need to check a global flag to see if to exit the loop. 消息循环需要检查全局标志以查看是否退出循环。

It would still be safer to move the DB connection logic to the separate thread. 将DB连接逻辑移动到单独的线程仍然更安全。 With DB on the dialog thread, you will be able to repaint the progress bar but not other controls in the dialog. 使用对话框线程上的DB,您将能够重新绘制进度条,但不能重新绘制对话框中的其他控件。

Have you tried to use SendMessage with PBM_SETMARQUEE instead of SetMarquee . 您是否尝试将SendMessagePBM_SETMARQUEE而不是SetMarquee一起使用。 I've never tried myself but it should work. 我从来没有尝试过,但它应该有效。

In my opinion the easiest way to achive what you want to do is making both the ProgressBar and DB connection in the ui thread and using OnTimer to call StepIt in the progress bar. 在我看来,实现你想要做的最简单的方法是在ui线程中同时创建ProgressBar和DB连接,并使用OnTimer在进度条中调用StepIt You can also create the progress bar in the ui thread and use a custom message for the working thread to modify the progress status. 您还可以在ui线程中创建进度条,并使用自定义消息为工作线程修改进度状态。

Anyway, I agree with AlexEzh that the best way to do it is making the whole non-UI work in the working thread. 无论如何,我同意AlexEzh的说法,最好的办法就是让整个非UI工作在工作线程中。

Create a member variable as 创建一个成员变量as

CProgressCtrl m_progress;

add the m_progress in DDX_Control in DoDataExcchange with the progress bar ID 使用进度条ID在DoDataExcchange中的DDX_Control中添加m_progress

add the following code under Button click function. 在按钮单击功能下添加以下代码。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM