wxWidgets with AUI: OpenGL render loop method and wxPaintEve

wxWidgets with AUI: OpenGL render loop method and wxPaintEvent

本文关键字:loop method and wxPaintEve render OpenGL with AUI wxWidgets      更新时间:2023-10-16

我传统上使用wxWidgets绘制到OpenGL画布的方法是从当前的OpenGL画布触发30赫兹的定时刷新(),然后生成一个"wxEVT_PAINT",我可以将其传播到帧的其余部分。 我还绑定到wxEVT_PAINT并调用 refresh() 来捕获任何帧大小调整。

在我的程序中,不使用wxWidgets AUI,这种方法完美无缺。

但是,如果我尝试使用 AUI,则每次尝试绑定到 wxEVT_PAINT 时,我的绘制事件都不会触发。 有时绑定到 paint 事件甚至会阻止其他事件(如计时器)触发。

AUI是否有某种特殊的方式来对待事件,或者我在这里缺少wxEVT_PAINT? 绘制到 AUI 托管帧内的 OpenGL 窗口的最佳方法是什么? 任何人都可以提供提示或示例,因为关于 AUI 的这个主题的文档似乎不存在。

编辑:为了清楚起见,我在下面添加了我的源代码,供任何想要帮助追踪问题的人使用。 我已经删除了 OpenGL 部分,因为我实际上只是想让wxEVT_PAINT在调整窗口大小时触发框架中的绑定处理程序。

Generated Frame.h

#ifndef __GENERATEDFRAME_H__
#define __GENERATEDFRAME_H__
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/panel.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/string.h>
#include <wx/menu.h>
#include <wx/frame.h>
#include <wx/aui/aui.h>

class MainFrame : public wxFrame 
{
    private:
    protected:
        wxPanel* m_panelMainView;
        wxMenuBar* m_menubar2;
    public:
        MainFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("SimpleAui"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 646,516 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
        wxAuiManager m_mgr;
        ~MainFrame();
};
#endif //__GENERATEDFRAME_H__

生成的帧.cpp

#include "GeneratedFrame.h"
MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
{
    this->SetSizeHints( wxDefaultSize, wxDefaultSize );
    m_mgr.SetManagedWindow(this);
    m_mgr.SetFlags(wxAUI_MGR_LIVE_RESIZE);
    m_panelMainView = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
    m_panelMainView->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVECAPTION ) );
    m_panelMainView->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_INFOBK ) );
    m_mgr.AddPane( m_panelMainView, wxAuiPaneInfo() .Name( wxT("MainView") ).Center() .Caption( wxT("Main View") ).MinimizeButton( true ).PinButton( true ).Dock().Resizable().FloatingSize( wxDefaultSize ).Floatable( false ) );
    m_menubar2 = new wxMenuBar( 0 );
    this->SetMenuBar( m_menubar2 );

    m_mgr.Update();
    this->Centre( wxBOTH );
}
MainFrame::~MainFrame()
{
    m_mgr.UnInit();
}

AppFrame.h

#ifndef __AppFrame_h__
#define __AppFrame_h__
#include "GeneratedFrame.h"
#include "SimpleAuiApp.h"
class AppFrame : public MainFrame
{
public:
    // Constructor/Descructor
    AppFrame( wxWindow* parent, ApplicationData* pAppData );
    ~AppFrame( );
    // display update (called from main App on an update event)
    void UpdateDisplay( );
private:
    // pointer to the main data structure
    ApplicationData* m_pAppData;
    void OnPaint( wxPaintEvent& event );
};
#endif //__AppFrame_h__

应用框架.cpp

#include "AppFrame.h"
#include "SimpleAuiApp.h"
#include <iostream>
// Constructor for the frame
AppFrame::AppFrame( wxWindow* parent, ApplicationData* pAppData )
    : MainFrame( parent )
{
    // Pull in the app data pointer
    m_pAppData = pAppData;
    // Set the size of the inner drawing area of the frame
    SetClientSize( 500, 500 );
    // Show the frame
    Show();
    // Layout the frame
    Layout();
    // Bind to the wxEVT_PAINT event
    Bind( wxEVT_PAINT, &AppFrame::OnPaint, this );
}
// Destructor for the frame
AppFrame::~AppFrame( )
{
    // stop the update timer for the application, otherwise a timer update
    // event can be generated while data is being deleted
    if( m_pAppData->m_pTimer )
    {
        m_pAppData->m_pTimer->Stop( );
    }
}
void AppFrame::OnPaint( wxPaintEvent& event )
{
    std::cout << "Running AppFrame::OnPaintn";
    UpdateDisplay( );
}
// perform frame update for the display 
void AppFrame::UpdateDisplay( )
{
    std::cout << "Running AppFrame::UpdateDisplayn";
}

SimpleAuiApp.h

#ifndef __SimpleAuiApp_h__
#define __SimpleAuiApp_h__
#include <wx/wx.h>
#define DEFAULT_UPDATE_RATE (10)    // in Hz (set to 0 for OnIdle)
// Forward declarations
class AppFrame;
struct ApplicationData
{
    // constructor
    ApplicationData( )
    {
        m_pFrame = NULL;
        m_pTimer = NULL;
        m_nDisplayUpdateRate = DEFAULT_UPDATE_RATE;
    }
    // timer object for frame based updates
    wxTimer* m_pTimer;
    // rate of display update (in HZ) (0=update on idle)   
    int m_nDisplayUpdateRate;
    // pointer to the main frame instance
    AppFrame* m_pFrame;
};
// Main application class
// (derived from the wxWidget App class)
class SimpleAuiApp : public wxApp
{
public:
    SimpleAuiApp( );
    virtual ~SimpleAuiApp( );
    // the main application data structure
    ApplicationData m_AppData;
private:
    // called by wxApp when starting up, program setup should be done here
    bool OnInit( );
    // called by wxApp when shutting down, program cleanup should be done here
    int  OnExit( );
    // When running with "fixed" framerate, called for each timer event (frame)
    void OnTimer( wxTimerEvent& event );
};
DECLARE_APP( SimpleAuiApp )
#endif //__SimpleAuiApp_h__

简单奥伊应用.cpp

#include <wx/wx.h>
#include "SimpleAuiApp.h"
#include "AppFrame.h"
#include <iostream>
IMPLEMENT_APP( SimpleAuiApp )
SimpleAuiApp::SimpleAuiApp( )
{
}
SimpleAuiApp::~SimpleAuiApp( )
{
}
bool SimpleAuiApp::OnInit( )
{
    // Open a console window for errors and standard output
    AllocConsole( );
    freopen( "CONOUT$", "wb", stdout );
    freopen( "CONOUT$", "wb", stderr );
    std::cout << "Initialization started...n";
    // Create the main application frame
    m_AppData.m_pFrame = new AppFrame( (wxWindow*) NULL, &m_AppData );
    // Bring the frame to the front
    SetTopWindow( m_AppData.m_pFrame );
    // See if a fixed frame rate is specified
    if ( m_AppData.m_nDisplayUpdateRate > 0 )
    {
        // Start a timer to update the display at a fixed frame rate.
        // Note that rate is increased by 10% to make up for wxWidget's inaccurate timers.
        m_AppData.m_pTimer = new wxTimer( this );
        float fMilliSeconds = 1000.0 / ( m_AppData.m_nDisplayUpdateRate * 1.1f );
        m_AppData.m_pTimer->Start( fMilliSeconds );
        Bind( wxEVT_TIMER, &SimpleAuiApp::OnTimer, this );
    }
    else
    {
        // capture the "on idle" event when not running at a fixed frame rate
        Bind( wxEVT_IDLE, &SimpleAuiApp::OnIdle, this );
    }
    std::cout << "Initialization completed...n";
    return true;
}
// -------------------------------------------------------------
// Framerate - functions bound to framerate related events.
// Either OnTimer() or OnIdle() should be called here for each
// frame, but never both.  They are two different refresh
// methods.
// -------------------------------------------------------------
// Called by widget app code on timer event
void SimpleAuiApp::OnTimer( wxTimerEvent& event )
{
    std::cout << "Called SimpleAuiApp::OnTimer n";
    // update the frame's display
    m_AppData.m_pFrame->UpdateDisplay( );
}
// -------------------------------------------------------------
// OnExit - Called by widget app code on shutdown
// -------------------------------------------------------------
int SimpleAuiApp::OnExit( )
{
    // stop (and delete) the update timer if needed
    if ( m_AppData.m_pTimer )
    {
        m_AppData.m_pTimer->Stop( );
        delete m_AppData.m_pTimer;
        m_AppData.m_pTimer = NULL;
    }
    // close the console window if needed
    FreeConsole( );
    // exit successful
    return 0;
}

问题最终是,附加到主帧的 AUI 管理器在传播时确实会消耗 wxEVT_PAINT 事件,并且它永远不会到达帧的类。 但是,框架的子项确实会收到事件。

我不只是使用 Frame 类中的 Bind(),而是调用了 m_panelgl->Bind,其中m_panelgl是我的子容器,它保存了 OpenGL 画布。