C++ 如何在单独的线程中创建带有进度条的 MFC 对话框?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1669017/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create a MFC dialog with a progress bar in a separate thread?
提问by foraidt
My application may take a while to connect to a database. This connection is made with a single library function call, i.e. 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.
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.
我的想法是在连接到数据库之前在单独的线程中创建一个带有进度条的对话框。此对话框将不断更改进度状态,CProgressCtrl::StepIt()
以便用户看到正在发生的事情。
在设置该对话框并执行其操作后,我想从主线程调用 DB 连接函数。连接功能完成后,我想停止进度条线程。
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.
也许整个事情也可以使用计时器。可能会简单得多,但我也无法让它工作。
- 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. - 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.
- 我知道
CProgressCtrl::SetMarquee()
哪些可能完全满足我的需要,但我无法使用它,因为该应用程序不支持 Unicode。 - 我可以将 db 连接调用移动到一个单独的线程中,但这样看起来对代码和连接错误的额外处理有很多变化。
Update 2
I got it working the way AlexEzh and Javier De Pedro suggested: Put the DB stuf into its own thread.
initially I had concerns about how error handling could be done but it's actually quite similar to how it was before.
更新 2
我让它按照 AlexEzh 和 Javier De Pedro 建议的方式工作:将 DB stuf 放入自己的线程中。
最初我担心如何进行错误处理,但它实际上与以前的方式非常相似。
- In the main thread I create a struct with connection parameters, result flag and thread-running-flag. The latter is initially set to
true
. - I create a thread and pass that struct as parameter.
- I create a dialog that displays a progress bar in the main thread.
- Also in the main thread there is a loop that runs while the thread-running-flag is set. It calls
CMyDialog::Animate()
which callsCProgressCtrl::StepIt()
and thenSleep()
s a bit. - The thread executes the db-connection code and sets the running-flag to
false
when done. - When the main thread exits the loop it can handle errors exactly as it did before.
- 在主线程中,我创建了一个带有连接参数、结果标志和线程运行标志的结构。后者最初设置为
true
。 - 我创建了一个线程并将该结构作为参数传递。
- 我创建了一个在主线程中显示进度条的对话框。
- 同样在主线程中,有一个循环在设置线程运行标志时运行。它调用
CMyDialog::Animate()
which 调用CProgressCtrl::StepIt()
然后Sleep()
有点。 - 该线程执行 db-connection 代码并将运行标志设置为
false
完成时。 - 当主线程退出循环时,它可以完全像以前一样处理错误。
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 .
| .
采纳答案by AlexEzh
It would still be safer to move the DB connection logic to the separate thread. With DB on the dialog thread, you will be able to repaint the progress bar but not other controls in the dialog.
将数据库连接逻辑移动到单独的线程仍然会更安全。使用对话框线程上的 DB,您将能够重新绘制进度条,但不能重新绘制对话框中的其他控件。
回答by Kirill V. Lyadvinsky
回答by Shay Erlichmen
- Create worker thread using
AfxBeginThread
. - In that thread Create a
CProgressCtrl
and callCreate
, pass the dialog as the parent of the CProgressCtrl, use the marquee style for the progress control. In the Thread create a message waiting loop:
MSG msg;
while(GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}The message loop need to check a global flag to see if to exit the loop.
- 使用
AfxBeginThread
. - 在该线程中创建一个
CProgressCtrl
并调用Create
,将对话框作为 CProgressCtrl 的父级传递,对进度控件使用选取框样式。 在 Thread 创建一个消息等待循环:
味精味精;
while(GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&msg);
调度消息(&msg);
}消息循环需要检查一个全局标志以查看是否退出循环。
回答by Javier De Pedro
Have you tried to use SendMessage
with PBM_SETMARQUEE
instead of SetMarquee
. I've never tried myself but it should work.
您是否尝试过使用SendMessage
withPBM_SETMARQUEE
而不是SetMarquee
. 我从来没有尝试过自己,但它应该工作。
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.
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 线程中同时建立 ProgressBar 和 DB 连接,并使用 OnTimer 调用StepIt
进度条。您也可以在 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 工作在工作线程中。
回答by Ravi
Create a member variable as
创建一个成员变量作为
CProgressCtrl m_progress;
add the m_progress
in DDX_Control
in DoDataExcchange
with the progress bar ID
加m_progress
中DDX_Control
在DoDataExcchange
进度条ID
add the following code under Button click function.
在按钮单击功能下添加以下代码。
m_progress.setRange(0,100);
m_progress.SetPos(1);