【问题标题】:Application with multiple windows as instances of a class, C++具有多个窗口作为类实例的应用程序,C++
【发布时间】:2013-05-15 11:16:10
【问题描述】:

我写了一个应用程序。有一个名为 APP 的类,有窗口句柄,里面有消息循环,以及所有这些东西。

它旨在“运行”这个类的一些对象,每个对象都有自己的窗口,基于标准窗口所需的一组变量。

消息循环允许公共使用,它由 RunMessageLoop 方法运行。 int nCmdShow - 当然,它是用来告诉如何显示一个窗口的。

现在,当我创建一些像这样的对象时:

vector <APP *> App;
for (int i=0; i<3; i++)
{
    App.push_back(&APP(nCmdShow))
    App[i]->RunMessageLoop();
}

程序在开始另一个消息循环之前等待每个消息循环结束。

我想办法做到这一点:

vector <APP *> App;
for (int i=0; i<3; i++)
{
    App.push_back(&APP(nCmdShow))
}
for (int i=0; i<3; i++)
{
    App[i]->RunMessageLoop();
}

当我知道我想在启动时运行多少个窗口时,似乎没问题。

但我不知道如何动态创建新窗口,完全独立于其他窗口。它应该调用消息循环并立即返回 WinMain() 而不结束消息循环。

我想到了多线程应用程序,每个线程对应一个 APP 类的一个实例。但是不知道如何构建多线程应用程序。

对可能的解决方案有什么想法吗?

【问题讨论】:

  • 您的代码有未定义的行为。当您这样做时:App.push_back(&amp;APP(nCmdShow)) 您正在存储指向立即销毁的临时对象的指针。
  • 嗯,在我看来它没有被破坏,因为我可以看到窗口,并且它正在响应消息。如果编码不正确,请给我一些建议,如果可以的话。
  • @bercik “未定义的行为”可能似乎在起作用,并在以后由于某种原因暴露其未定义性时困扰您数周。我很惊讶&amp;APP(nCmdShow) 甚至可以编译。你应该在那里使用new,而不是&amp;
  • 我只知道指针使用的基础;我不熟悉operator new。它在代码中看起来如何?
  • 当你创建一个对象而不使用new,你在堆栈上创建它。因此,一旦您在其中创建 APP 的函数返回,APP 将被销毁,从而使存储在向量中的指向 APP 的指针无效。使用App.push_back(new APP(nCmdShow))APP 将存储在动态内存中,防止其被破坏,然后指针将有效。顺便说一句,无论您是否对它们进行了无效指针,这些窗口仍然会出现。

标签: c++ visual-studio object instance


【解决方案1】:

我知道您现在正在尝试做什么,我已经在我的名为 Lucid 的应用程序框架中实现了这一点(它仍在进行中)。为了得到答案,您的窗口类将被称为Window 而不是APP

这是通过将全局过程传递给您创建的每个窗口来完成的。所有窗口共享相同的过程。每次任何窗口收到消息时,该消息都会发送到全局过程,全局过程会检查 HWND 是否属于您创建的 Window,如果是,则将消息发送到该 Windows ' 程序。以下是其工作原理的概述。

class Window
{
public:
    // The contents of this function can vary from window to window
    // provided that you make a subclass and override this method.
    virtual LRESULT procedure(HWND wnd, UINT msg, WPARAM wp, LPARAM lp);

    // When you create a Window object, add a pointer to it in this map.
    // Eg. if (this->hwnd != NULL) createdWindows[this->hwnd] = this;
    static map<HWND, Window*> createdWindows;

    // When you create a window, make this its procedure.
    static LRESULT CALLBACK routeMessage(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
    {
        if (createdWindows.find(wnd) != createdWindows.end()) {
            // Message belongs to one of our 'Window' objects.
            // Pass the message to that window and return the result.
            return createdWindows[wnd]->procedure(wnd, msg, wp, lp);
        } else {
            // It seems you made 'routeMessage' the procedure
            // of a window that doesn't belong in the map. Go ahead
            // and process the message in the default manner.
            return DefWindowProc(wnd, msg, wp, lp);
        }
    }
};

现在您只需要一个消息循环和一个线程。我有一个使用 Lucid 的测试项目,它在单个线程上使用不同的过程创建 2 个窗口,并带有单个消息循环:

#include "Lucid.h"
using namespace Lucid;

void sayBye(MessageEventArgs& e)
{
    MessageBox(NULL, "Goodbye!", "Form 2", MB_OK);
    e.handled = true;
}    

void Program::onStart()
{
    Form* myForm1 = new Form("Hello World!");
    myForm1->show();

    Form* myForm2 = new Form("Hello World!");
    myForm2->addMessageHandler(WM_CLOSE, sayBye);
    myForm2->show();

    // This Program::onStart() function is called
    // immediately before the single message loop is entered.
}

【讨论】:

  • 谢谢。这也很有趣。我会尝试并发表我的想法。
【解决方案2】:

创建线程,_beginthreadex 等于您需要运行的窗口数。然后,在线程过程中运行消息循环并等待直到所有线程都以WaitForMultipleObjects 终止。

【讨论】:

  • 感谢您的回复。我会尝试实施它并查看结果,然后我会给你反馈。
猜你喜欢
  • 1970-01-01
  • 2013-06-20
  • 1970-01-01
  • 1970-01-01
  • 2023-01-29
  • 1970-01-01
  • 2018-09-09
  • 2014-12-21
  • 2012-07-16
相关资源
最近更新 更多