如何在 SFML 中使用 wxWidgets?

How to use wxWidgets with SFML?

我正在做一系列关于物理模拟的应用程序,直到现在我已经完成了其中一些纯粹使用方便的 SFML 库。现在我想给它们添加一些 GUI 元素。我对 wxWidgets 框架和 wxFrames 只是有点熟悉,但不知道 wxDc 是如何工作的,这似乎是 SFML-wxWidgets 集成的核心。我会一一列出我的疑问。

  1. 我对 SFML dev webpage 提供的旧教程的拍摄:纠正了一些小错误后的最终代码如下所示:
#include <SFML/Graphics.hpp>
#include <wx/wx.h>

class wxSFMLCanvas : public wxControl, public sf::RenderWindow
{
public:
    wxSFMLCanvas(wxWindow* Parent = NULL, wxWindowID Id = -1, const wxPoint& Position = wxDefaultPosition,
        const wxSize& Size = wxDefaultSize, long Style = 0);
    virtual ~wxSFMLCanvas();

private:
    DECLARE_EVENT_TABLE()
    virtual void OnUpdate();
    void OnIdle(wxIdleEvent&);
    void OnPaint(wxPaintEvent&);
    void OnEraseBackground(wxEraseEvent&);
    void OnSize(wxSizeEvent&);
};

void wxSFMLCanvas::OnUpdate()
{
}

void wxSFMLCanvas::OnIdle(wxIdleEvent&)
{
    // Send a paint message when the control is idle, to ensure maximum framerate
    Refresh();
}

void wxSFMLCanvas::OnPaint(wxPaintEvent&)
{
    // Prepare the control to be repainted
    wxPaintDC Dc(this);
    // Let the derived class do its specific stuff
    OnUpdate();
    // Display on screen
    display();
}

void wxSFMLCanvas::OnEraseBackground(wxEraseEvent&)
{
}

void wxSFMLCanvas::OnSize(wxSizeEvent&)
{
}

wxSFMLCanvas::wxSFMLCanvas(wxWindow* Parent, wxWindowID Id, const wxPoint& Position, const wxSize& Size, long Style) :
    wxControl(Parent, Id, Position, Size, Style) {
    sf::RenderWindow::create(GetHandle());
}

wxSFMLCanvas::~wxSFMLCanvas()
{
}

class MyCanvas : public wxSFMLCanvas
{
    sf::CircleShape circ;
public:
    MyCanvas(wxWindow* Parent, wxWindowID Id, wxPoint& Position, wxSize& Size, long Style = 0) : wxSFMLCanvas(Parent, Id, Position, Size, Style) {
        // specify circle
        circ.setRadius(50.0f);
        circ.setOrigin(50.0f,50.0f);
        circ.setFillColor(sf::Color::Blue);
        circ.setPosition(100.0f, 100.0f);
    }
private:
    virtual void OnUpdate() {
        // Clear the view
        clear(sf::Color(0, 128, 128));

        // Display the circle in the view
        draw(circ);
    }
};

class MyFrame : public wxFrame
{
public:
    MyFrame() : wxFrame(NULL, wxID_ANY, "SFML wxWidgets", wxDefaultPosition, wxSize(800, 600)) {
        wxPoint tmp1 = wxPoint(50, 50);
        wxSize tmp2 = wxSize(700, 500);
        new MyCanvas(this, wxID_ANY, tmp1, tmp2);
    }
};

class MyApplication : public wxApp
{
private:

    virtual bool OnInit()
    {
        // Create the main window
        MyFrame* MainFrame = new MyFrame;
        MainFrame->Show();

        return true;
    }
};

IMPLEMENT_APP(MyApplication);

这会抛出一堆未解决的外部问题:

Error   LNK2001 unresolved external symbol "protected: virtual struct wxEventTable const * __cdecl wxSFMLCanvas::GetEventTable(void)const " (?GetEventTable@wxSFMLCanvas@@MEBAPEBUwxEventTable@@XZ) test1   C:\Users\rajat\source\repos\test1\test1.obj 1   
Error   LNK2001 unresolved external symbol "protected: virtual class wxEventHashTable & __cdecl wxSFMLCanvas::GetEventHashTable(void)const " (?GetEventHashTable@wxSFMLCanvas@@MEBAAEAVwxEventHashTable@@XZ)    test1   C:\Users\rajat\source\repos\test1\test1.obj 1   
Error   LNK2019 unresolved external symbol main referenced in function "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)    test1   C:\Users\rajat\source\repos\test1\MSVCRTD.lib(exe_main.obj) 1   

此外,我不太明白在这个例子中wxWidgets 应该如何绘制sf::RenderWindow 的内容。如果有人可以纠正此准系统代码以使其正常工作,那将非常有帮助。也希望解释它是如何工作的。

  1. 是否有可以与 SFML 一起使用的 wxWidgets 的替代品,或者是否有用于快速简单的图形库的便捷工具?唯一的要求是我应该能够在 MSVS 上为 x64 框架编译它并静态 link 到我的应用程序。我考虑过Qt,但我不能让它自己编译,或者即使我编译,它也只是32位共享库配置。

  2. 代码应该如何工作? sf::RenderWindow 是使用 sf::RenderWindow::create(GetHandle()) 创建的。它应该自己绘制所有内容吗?还是我必须自己复制 SFML window 的位图并在 wxControl 上绘制?如果有人能阐明它应该如何工作,那将非常有帮助。

您的错误是由于使用 DECLARE_EVENT_TABLE 但未使用任何 wxBEGIN_EVENT_TABLE/wxEND_EVENT_TABLE,即您从未定义事件 table 也未连接任何事件处理程序。

我对 SFML 一无所知,所以我无法真正帮助您完成其余的工作,但显然绘图应该由您的 wxEVT_PAINT 处理程序完成——一旦您连接了它——只需调用 sf::RenderWindow::Display().

我终于让他们一起工作了。这是在单击按钮时显示圆圈的最小代码:

#include <SFML/Graphics.hpp>
#include <wx/wx.h>

class wxSFMLCanvas : public wxControl, public sf::RenderWindow
{
public:
    wxSFMLCanvas(wxWindow* Parent = NULL, wxWindowID Id = -1, const wxPoint& Position = wxDefaultPosition,
        const wxSize& Size = wxDefaultSize, long Style = 0);
    virtual ~wxSFMLCanvas();
};

wxSFMLCanvas::wxSFMLCanvas(wxWindow* Parent, wxWindowID Id, const wxPoint& Position, const wxSize& Size, long Style) :
    wxControl(Parent, Id, Position, Size, Style) {
    sf::RenderWindow::create(GetHandle());
}

wxSFMLCanvas::~wxSFMLCanvas() {
}

class cMain : public wxFrame
{
    wxButton* m_btn1 = nullptr;
    wxSFMLCanvas* mycanv = nullptr;
    wxDECLARE_EVENT_TABLE();
public:
    cMain();
    void onBtnClicked(wxCommandEvent &evt);
};


wxBEGIN_EVENT_TABLE(cMain,wxFrame)
    EVT_BUTTON(10001, onBtnClicked)
wxEND_EVENT_TABLE()


cMain::cMain() : wxFrame(nullptr, wxID_ANY, "Window", wxPoint(30, 30), wxSize(800, 600)) {
    mycanv = new wxSFMLCanvas(this, wxID_ANY, wxPoint(50, 50), wxSize(700, 500));
    m_btn1 = new wxButton(this, 10001, "button1", wxPoint(10, 10), wxSize(100, 50));
}

void cMain::onBtnClicked(wxCommandEvent& evt) {
    sf::CircleShape circ(50.0f);
    circ.setOrigin(50.0f, 50.0f);
    circ.setFillColor(sf::Color::Blue);
    circ.setPosition(350, 250);
    mycanv->draw(circ);
    mycanv->display();
}

class myApp : public wxApp
{
    cMain* m_Frame1 = nullptr;
public:
    myApp();
    virtual bool OnInit();
};
wxIMPLEMENT_APP(myApp);

myApp::myApp() {

}

bool myApp::OnInit() {
    // Create the main window
    m_Frame1 = new cMain;
    m_Frame1->Show();
    return true;
}

此代码的可执行文件(所有静态链接)约为 10MB(调试模式)~4MB(发布模式)。我将这段代码留在这里以防其他人发现它有用。