如何显示非模式对话框并立即在其中显示信息?

发布于 2024-07-11 06:46:52 字数 278 浏览 8 评论 0原文

我想在屏幕上显示一个无模式对话框并在其中显示一些信息。

但是,如果我按照以下方式使用它,则会出现一些问题:

function()
{
showdialog(XXX).
//heavy work.
update the dialog..
//heavy work.
update the dialog...
}

似乎显示了对话框,但它没有在其中绘制任何信息。 它仅在函数结束时绘制所有信息。

如何修改非模式对话框以便它立即显示信息?

I want to show a modeless dialog on the screen and display some information in it.

However if I use it the following way, it has some problems:

function()
{
showdialog(XXX).
//heavy work.
update the dialog..
//heavy work.
update the dialog...
}

It seems the dialog displayed, but it does not draw any information in it. It only draw all information when the function is over.

How can I modify the modeless dialog so it will display the information immediately?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

九公里浅绿 2024-07-18 06:46:52

您可以做一些事情。

(1) 您可以从 CDialog::OnInitDialog 方法内部发布消息给对话框,然后在消息处理程序中处理长函数那个发布的消息。 这样,对话框将首先显示,然后长函数将运行。

(2) 第二个选项是确保消息循环获得一些处理时间。 因此,如果您的长函数是某种循环,只需偶尔添加对 ProcessMessages 的调用,以确保消息队列保持为空:

void ProcessMessages()
{
    MSG msg;
    CWinApp* pApp = AfxGetApp();
    while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
    {
        pApp->PumpMessage();
    }
}

编辑: 当然可以使用线程就是这样的情况,但是这样做并不总是没有风险和复杂性。

使用带有 GUI 的线程意味着必须处理多个消息队列,这意味着使用 PostThreadMessage 等 API,并且引入了一系列需要警惕的新问题。

有关此类问题的示例,请参阅以下链接:

http: //msdn.microsoft.com/en-us/library/ms644946(VS.85).aspx

其中说:

PostThreadMessage发送的消息是
不与窗口关联。 作为一个
一般规则,不属于的消息
不能与窗口关联
由 DispatchMessage 调度
功能。 因此,如果收件人
线程处于模态循环中(如
消息框或对话框),
消息将会丢失。 拦截
在模态中线程消息
循环,使用线程特定的钩子。

我在 Zeus IDE 中使用进程消息方法,它可以很好地确保 GUI 保持对用户的响应。 它还具有非常容易实现的优点。

There are a few things you can do.

(1) You could post the dialog a message from inside the CDialog::OnInitDialog method and then handle the long function in the message handler of that posted message. That way the dialog will first be displayed and then later the long function will get run.

(2) The second option is to make sure the message loop gets some processing time. So if your long function is some sort of loop just add the occasional call to the ProcessMessages to make sure the message queue is kept empty:

void ProcessMessages()
{
    MSG msg;
    CWinApp* pApp = AfxGetApp();
    while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
    {
        pApp->PumpMessage();
    }
}

Edit: It certainly is possible to use threads is such a situation, but doing so is not always without risk and complexity.

Using threads with a GUI means having to deal with multiple message queues which then means using API's like PostThreadMessage and that introduces a new set of issues to be wary of.

For an example of one such issue refer to this link:

http://msdn.microsoft.com/en-us/library/ms644946(VS.85).aspx

where is says:

Messages sent by PostThreadMessage are
not associated with a window. As a
general rule, messages that are not
associated with a window cannot be
dispatched by the DispatchMessage
function. Therefore, if the recipient
thread is in a modal loop (as used by
MessageBox or DialogBox), the
messages will be lost. To intercept
thread messages while in a modal
loop, use a thread-specific hook.

I use the process message approach in the Zeus IDE and it works very well at making sure the GUI remains responsive to the user. It is also has the advantage of being very easy to implement.

谁把谁当真 2024-07-18 06:46:52

在 OnInitDialog 中,启动工作线程来执行计算。 从工作线程发布用户消息以更新对话框。

这优于 ProcessMessages 实现,原因如下:

  • 用于执行计算的代码可以从它不属于的 UI 代码中分离出来。

  • 在执行实际计算时,UI 保持响应。 ProcessMessages 允许在单个计算函数期间进行多次 UI 更新,但在实际计算过程中 UI 仍会被阻塞。

对话框代码:

#define WM_NEW_COUNT (WM_USER + 0x101)

BEGIN_MESSAGE_MAP()
    ON_MESSAGE(WM_NEW_COUNT, OnNewCount)
END_MESSAGE_MAP()

BOOL CMyDialog::OnInitDialog()
{
    CWinThread* pThread = AfxBeginThread(MyCountFunc, this->GetSafeHwnd());
    return TRUE;
}

LRESULT CMyDialog::OnNewCount(WPARAM wParam, LPARAM)
{
    int newCount = (int)wParam;

    // m_count is DDX member, e.g. for label
    m_count = newCount;

    UpdateData(FALSE);

    return 0;
}

工作线程:

UINT MyCountFunc(LPVOID lParam)
{
    HWND hDialogWnd = (HWND)lParam;

    for (int i=0; i < 100; ++i)
    {
        PostMessage(hDialogWnd, WM_NEW_COUNT, i, NULL);
    }
}

In OnInitDialog, start a worker thread to perform the computations. Post a user message from the worker thread to update the dialog.

This is superior to the ProcessMessages implementation for several reasons:

  • The code for doing the calculations can be separated out of the UI code, where it does not belong.

  • The UI remains responsive while the actual calculations are being performed. ProcessMessages allows multiple UI updates during the single calculation function, but the UI will still be blocked during the actual calculations.

Dialog code:

#define WM_NEW_COUNT (WM_USER + 0x101)

BEGIN_MESSAGE_MAP()
    ON_MESSAGE(WM_NEW_COUNT, OnNewCount)
END_MESSAGE_MAP()

BOOL CMyDialog::OnInitDialog()
{
    CWinThread* pThread = AfxBeginThread(MyCountFunc, this->GetSafeHwnd());
    return TRUE;
}

LRESULT CMyDialog::OnNewCount(WPARAM wParam, LPARAM)
{
    int newCount = (int)wParam;

    // m_count is DDX member, e.g. for label
    m_count = newCount;

    UpdateData(FALSE);

    return 0;
}

The worker thread:

UINT MyCountFunc(LPVOID lParam)
{
    HWND hDialogWnd = (HWND)lParam;

    for (int i=0; i < 100; ++i)
    {
        PostMessage(hDialogWnd, WM_NEW_COUNT, i, NULL);
    }
}
乱了心跳 2024-07-18 06:46:52

根据经验,繁重的计算不应该放在 GUI 线程中。 由于它是一个无模式对话框,因此该对话框不会拥有消息循环。 ProcessMessage() 解决方案可以工作,但 IMO 不是正确的方法。 我的建议是:
1)在OnInitDialog()中生成一个新线程
2)当发生有趣的事情时,让单独的线程向对话框发布消息。 这些有趣的事情之一是工作已经完成。

但请注意,这意味着您需要执行正确的同步。

As a rule of thumb, heavy computations should never be placed in the GUI thread. Since it is a modeless dialog, the dialog will not own the message loop. The ProcessMessage() solution will work, but is IMO not the right way. My suggestion is:
1) Spawn a new thread in OnInitDialog()
2) Have the separate thread post messages to the dialog when something interesting happens. One of these interesting things is that the work is done.

Note, however, that this will mean that you need to perform proper synchronization.

乖乖 2024-07-18 06:46:52

不要试图一次完成所有繁重的工作。 让对话框在 OnInitDialog 的 WM_APP 范围内向自己发送一条消息。 WM_APP 处理程序可以完成部分繁重的工作,然后执行另一个 PostMessage 并返回。 通过这种方式,您允许消息泵在处理块之间处理窗口消息。

Don't try to do your heavy work all at once. Have the dialog post itself a message in the WM_APP range in OnInitDialog. The WM_APP handler can do part of the heavy work, then do another PostMessage and return. In this way, you allow the message pump to process window messages in between your chunks of processing.

浮世清欢 2024-07-18 06:46:52

在 SDI 和 MDI 应用程序中,提供的 ProcessMessages() 函数不会导致为状态栏生成 ON_UPDATE_UI 消息。 状态栏通常用于报告有关“鼠标所在位置”的信息,因为它与正在查看或编辑的文档有关。 虽然 WM_MOUSEMOVE 消息将成功路由,但状态栏不会更新。 需要的是对状态栏的 OnUpdateCmdUI() 方法的显式调用 - 在泵送消息循环之后将是调用它的合理位置。
例如,在您的 CMainFrame 中添加:,

void CMainFrame::ForceStatusBarUpdate()
{
    m_wndStatusBar.OnUpdateCmdUI(this,FALSE);
}

然后在 ProcessMessages 中调用它:

...
static_cast<CMainFrame*>( AfxGetApp()->m_pMainWnd )->ForceStatusBarUpdate();

In SDI and MDI applications, the ProcessMessages() function provided will not cause ON_UPDATE_UI messages to be generated for the status bar. The status bar is often used to report information about "where the mouse is", as it pertains to the document being viewed or edited. While WM_MOUSEMOVE messages will be routed successfully, the status bar updates won't. What's needed is an explicit call to the status bar's OnUpdateCmdUI() method - after pumping the message loop would be a reasonable place to call it.
e.g.in your CMainFrame, add:

void CMainFrame::ForceStatusBarUpdate()
{
    m_wndStatusBar.OnUpdateCmdUI(this,FALSE);
}

and then call it in ProcessMessages:

...
static_cast<CMainFrame*>( AfxGetApp()->m_pMainWnd )->ForceStatusBarUpdate();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文