简体   繁体   English

使用 wxWidgets 关闭时 SFML 崩溃

[英]SFML crashes when closing with wxWidgets

I am using an SFML view integrated inside a wxWidgets frame.我正在使用集成在 wxWidgets 框架内的 SFML 视图。 I used the code sample on the SFML website (which is quite old but I got it to work making a few tweaks) to do this.我使用了 SFML 网站上的代码示例(它很旧,但我做了一些调整)来做到这一点。 And then started fleshing out my project from that base class.然后开始从基础 class 充实我的项目。 However, I am at the stage now where I need to create and delete many SFML+wxWidgets windows based on user actions, however SFML crashes whenever I close its parent wxWidgets window.但是,我现在处于需要根据用户操作创建和删除许多 SFML+wxWidgets windows 的阶段,但是每当我关闭其父 wxWidgets window 时 SFML 就会崩溃。 I get the following error:我收到以下错误:

Cannot close SFML area when SFML is integrated in a NSView.

All the SFML+wxWidgets examples on the web I found face this error when I run it after closing. web 上的所有 SFML+wxWidgets 示例我发现在关闭后运行它时都会遇到此错误。 This error should not be an issue if the user only needs to close the window once, but I am managing many windows over the user session, so if it crashes once, it brings down the whole app with it.如果用户只需要关闭 window 一次,则此错误不应该成为问题,但我正在管理用户 session 上的许多 windows,所以如果它崩溃一次,它会导致整个应用程序崩溃

Here is the section of the header file code for the base class combining wxWidgets and sfml, everything else is specific to my app, and not to the error:这是 header 文件代码的部分,用于结合 wxWidgets 和 sfml 的基本 class,其他所有内容都特定于我的应用程序,而不是错误:

class ChessWidgetBase : public wxControl, public sf::RenderWindow {
  public:
    ChessWidgetBase(wxWindow* parent, wxSize size); 
    virtual ~ChessWidgetBase() {};
  private:
    DECLARE_EVENT_TABLE()
    virtual void HandleLeftDown(wxMouseEvent&) {}
    virtual void HandleLeftUp(wxMouseEvent&) {}
    virtual void OnUpdate() {};
    void OnIdle(wxIdleEvent&);
    void OnPaint(wxPaintEvent&);
    void OnEraseBackground(wxEraseEvent&);
};

This code is based off this minimum reproducable example I used from the internet to make the above class:此代码基于我从互联网上用于制作上述 class 的最小可重现示例:

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

#ifdef __WXGTK__
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#endif

using namespace std;

static const int kDefaultWindowWidth = 1280;
static const int kDefaultWindowHeight = 720;
static const int kCanvasMargin = 50;

struct wxSfmlCanvas : public wxControl, public sf::RenderWindow
{
  wxSfmlCanvas(
    wxWindow *parent = nullptr,
    wxWindowID windowId = -1,
    const wxPoint &position = wxDefaultPosition,
    const wxSize &size = wxDefaultSize,
    long style = 0) :
  wxControl(parent, windowId, position, size, style)
  {
    createRenderWindow();
  }

  virtual void onUpdate(){};

  void onIdle(wxIdleEvent& event)
  {
    // Send a paint message when control is idle, to ensure max framerate
    Refresh();
  }

  void onPaint(wxPaintEvent& event)
  {
    wxPaintDC dc(this);     // Prepare control to be repainted
    onUpdate();             // Tick update
    display();              // Draw
  }

  // Explicitly overriding prevents wxWidgets from drawing, which could result in flicker
  void onEraseBackground(wxEraseEvent& event){}

  void createRenderWindow()
  {
#ifdef __WXGTK__
    gtk_widget_realize(m_wxwindow);
    gtk_widget_set_double_buffered(m_wxwindow, false);

    GdkWindow *gdkWindow = gtk_widget_get_window((GtkWidget*)GetHandle());
    XFlush(GDK_WINDOW_XDISPLAY(gdkWindow));

    sf::RenderWindow::create(GDK_WINDOW_XWINDOW(gdkWindow));
#else
    sf::RenderWindow::create(GetHandle());
#endif
  }

  void setwxWindowSize(const wxSize& size)
  {
    this->SetSize(size);
  }

  void setRenderWindowSize(const sf::Vector2u& size)
  {
    this->setSize(size);
  }

  virtual ~wxSfmlCanvas(){};

wxDECLARE_EVENT_TABLE();
};

struct Canvas : public wxSfmlCanvas
{
  Canvas(
    wxWindow* parent,
    wxWindowID id,
    wxPoint position,
    wxSize size,
    long style = 0) :
  wxSfmlCanvas(parent, id, position, size, style)
  {
  }

  virtual void onUpdate()
  {
    clear(sf::Color::Yellow);

    // TODO: Do some sprite drawing or whatever
  }

  void onResize(wxSizeEvent& event)
  {
    auto size = event.GetSize();

    auto newCanvasWidth = size.x - (2 * kCanvasMargin);
    auto newCanvasHeight = size.y - (2 * kCanvasMargin);

    // Resize Canvas window
    this->setwxWindowSize({newCanvasWidth, newCanvasHeight});
    this->setRenderWindowSize({(unsigned int)newCanvasWidth, (unsigned int)newCanvasHeight});
  }
};

struct AppFrame : public wxFrame
{
  AppFrame(const wxString& title, const wxPoint& pos, const wxSize& size) :
    wxFrame(NULL, wxID_ANY, title, pos, size),
    _panel(new wxPanel(this)),
    _canvas(new Canvas(
      _panel.get(),
      wxID_ANY,
      wxPoint(kCanvasMargin, kCanvasMargin),
      wxSize(kDefaultWindowWidth - (2 * kCanvasMargin), kDefaultWindowHeight - (2 * kCanvasMargin))
    ))
  {
    _panel->SetBackgroundColour(*wxCYAN);

    ////////////////////////////////////////////////////////////////////////////////
    // Probably due to some RTTI, IDE is getting confused by this dynamic call
    // and doesn't understand the correct Bind overload. Causes non sequitur errors
    // to display in the inspector. Suppress.
    //
    // Dynamic binding is cleanest here, since we don't want to hook up our resize
    // handler until our dependencies (Canvas namely) have finished their initialization
    ////////////////////////////////////////////////////////////////////////////////
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wint-conversion"
    Bind(wxEVT_SIZE, &AppFrame::onResize, this);
    #pragma clang diagnostic pop
    ////////////////////////////////////////////////////////////////////////////////

  }

  void onResize(wxSizeEvent& event)
  {
    _canvas->onResize(event);
    event.Skip();
  }

  unique_ptr<wxPanel> _panel;
  unique_ptr<Canvas> _canvas;
};

struct App : public wxApp
{
  virtual bool OnInit()
  {
    auto frame = new AppFrame("SFML Canvas Demo", wxPoint(100, 100),
                              wxSize(kDefaultWindowWidth, kDefaultWindowHeight));
    frame->Show(true);
    return true;
  }
};

wxBEGIN_EVENT_TABLE(wxSfmlCanvas, wxControl)
  EVT_IDLE(wxSfmlCanvas::onIdle)
  EVT_PAINT(wxSfmlCanvas::onPaint)
  EVT_ERASE_BACKGROUND(wxSfmlCanvas::onEraseBackground)
wxEND_EVENT_TABLE()

wxIMPLEMENT_APP(App);

(if you want to run it you might have to install sfml+wxwidgets) Any ways to handle closing a window that prevents a crash with wxWidgets+SFML? (如果你想运行它,你可能必须安装 sfml+wxwidgets) 任何方法来处理关闭一个防止 wxWidgets+SFML 崩溃的 window? Just need some ideas and a couple lines of code to show them, no need for complete examples...只需要一些想法和几行代码来展示它们,不需要完整的例子......

To fix this error upgrade SFML to version >= 2.6.0.要修复此错误,请将 SFML 升级到版本 >= 2.6.0。 You cannot find this in the downloads site for SFML as it hasn't been released yet, so you must install from the Github directly over here: https://github.com/SFML/SFML/tree/2.6.x .您无法在 SFML 的下载站点中找到它,因为它尚未发布,因此您必须直接从 Github 安装: https://github.com/SFML/SFML/tree/2.6.x

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM