2009-11-03 67 views
9

我的应用程序可能需要一段时间才能连接到数据库。这个连接是通过一个库函数调用完成的,也就是说,我不能在那里放置进度更新并进行回调或类似的事情。如何在单独的线程中使用进度条创建MFC对话框?

我的想法是在连接到数据库之前,在单独的线程中创建一个带有进度条的对话框。此对话框将不断更改CProgressCtrl::StepIt()的进度状态,以便用户看到发生的事情。
之后,对话框设置和做它的事情我想从主线程调用数据库连接功能。 连接功能完成后,我想停止进度条线程。

让我画一幅画:

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

这可能吗?如果是,如何?

也许整个事情也会使用定时器。可能会简单得多,但我也无法让它工作。

  1. 我知道CProgressCtrl::SetMarquee()这可能正是我所需要的,但我不能使用它,因为应用程序没有Unicode支持。
  2. 我可以将db连接调用移动到一个单独的线程中,但这样看起来好像对代码进行了很多更改并且额外处理了连接错误。

更新2
我得到它的工作AlexEzh和哈维尔·佩德罗·德建议的方式:把DB塞入到它自己的线程。
最初我担心错误处理是如何完成的,但实际上它与以前的方式非常相似。

  1. 在主线程中,我使用连接参数,结果标志和线程运行标志创建了一个结构。后者最初设置为true
  2. 我创建一个线程并将该结构作为参数传递。
  3. 我创建一个对话框,在主线程中显示进度条。
  4. 另外在主线程中有一个循环,它在设置线程运行标志时运行。它调用CMyDialog::Animate(),它调用CProgressCtrl::StepIt(),然后Sleep()有点。
  5. 线程执行db连接代码并在完成时将运行标志设置为false
  6. 当主线程退出循环时,它可以像以前一样处理错误。

缺点:将鼠标移到窗口上不起作用。它是隐形的。因此不能使用取消按钮或其他交互式对话元素。不过,我可以忍受这一点。

既然你喜欢的图,这里是现在的样子:

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

+1为图 – 2009-11-03 19:52:12

+0

您可以在ANSI应用程序调用SetMarquee(),但它不会帮你,因为是动画进度条的计时器被称为主线程也 – 2009-11-03 19:55:25

+0

在我afxcmn上。h看起来像这样: ** if(_WIN32_WINNT> = 0x0501)&& defined(UNICODE)\ n BOOL SetMarquee(_In_ BOOL fMarqueeMode,_In_ int nInterval); \ n #endif \t // _WIN32_WINNT> = 0x0501 && defined(UNICODE)\ n ** 这就是为什么我不能调用它。 – foraidt 2009-11-04 08:46:08

回答

2

将DB连接逻辑移动到单独的线程仍然更安全。随着对话线程DB,你就能重绘对话框中的进度条而不是其他控件。

+0

我可以通过调用RedrawWindow()来重绘整个对话框。如果我不这样做,只有进度条是动画的。 – foraidt 2009-11-04 15:51:06

7

我希望this一篇关于用进度条创建自己的线程启动画面可能会有所帮助。我在解决MFC消息队列级别的线程锁定问题的同时写了它。

2
  1. 使用AfxBeginThread创建工作线程。
  2. 在该线程创建CProgressCtrl并调用Create,通过对话作为CProgressCtrl的父,使用选框风格的进度控制。
  3. 在线程中创建消息等待循环:

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

  4. 消息循环需要检查全局标志以查看是否退出循环。

+0

这是行不通的。阅读我的答案。 – 2009-11-03 20:17:52

+1

@Kirill这适用于我,在我的项目中,究竟是不是假设工作? – 2009-11-03 21:18:32

+0

MFC线程可能在创建函数中死锁。为了避免这种情况,你应该使用非MFC线程。 – 2009-11-04 09:45:21

1

您是否尝试过使用SendMessagePBM_SETMARQUEE,而不是SetMarquee。我从来没有尝试过自己,但它应该工作。

在我看来,实现你想要做的最简单的方法是在UI线程中同时进行ProgressBar和数据库连接,并使用OnTimer在进度条中调用StepIt。 您还可以创建在UI线程的进度条,并使用自定义消息的工作线程修改的进展状况。

反正我AlexEzh同意,要做到这一点的最好办法是使整个非UI工作的工作线程。

+0

当我尝试过时发送消息没有效果。 – foraidt 2009-11-04 10:14:22

1

创建一个成员变量如

CProgressCtrl m_progress; 

与进度条ID

添加在DDX_Controlm_progressDoDataExcchange添加下按钮点击功能下面的代码。

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

这只是非常基本的信息,它既没有被要求,也没有解决多线程问题。 – foraidt 2014-02-18 07:59:28

相关问题