簡體   English   中英

使用 wxWidgets 關閉時 SFML 崩潰

[英]SFML crashes when closing with wxWidgets

我正在使用集成在 wxWidgets 框架內的 SFML 視圖。 我使用了 SFML 網站上的代碼示例(它很舊,但我做了一些調整)來做到這一點。 然后開始從基礎 class 充實我的項目。 但是,我現在處於需要根據用戶操作創建和刪除許多 SFML+wxWidgets windows 的階段,但是每當我關閉其父 wxWidgets window 時 SFML 就會崩潰。 我收到以下錯誤:

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

web 上的所有 SFML+wxWidgets 示例我發現在關閉后運行它時都會遇到此錯誤。 如果用戶只需要關閉 window 一次,則此錯誤不應該成為問題,但我正在管理用戶 session 上的許多 windows,所以如果它崩潰一次,它會導致整個應用程序崩潰

這是 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&);
};

此代碼基於我從互聯網上用於制作上述 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);

(如果你想運行它,你可能必須安裝 sfml+wxwidgets) 任何方法來處理關閉一個防止 wxWidgets+SFML 崩潰的 window? 只需要一些想法和幾行代碼來展示它們,不需要完整的例子......

要修復此錯誤,請將 SFML 升級到版本 >= 2.6.0。 您無法在 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