How to remove trailing effect when drawing on a panel? Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to remove trailing effect when drawing on a panel?

Post by doublemax »

but when I click on a sample, it prints Cannot update waveform bitmap.
"Cannot update" actually means that the code "thinks" it's not needed to update the bitmap.

If the waveform changes, you must set a dirty flag or something to make sure that the bitmap gets updated. That's the "anyVisiblePropertyOfTheWaveformHasChanged" part i was talking about earlier.
Use the source, Luke!
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: How to remove trailing effect when drawing on a panel?

Post by apoorv569 »

doublemax wrote: Fri Jul 30, 2021 5:38 pm If you update your repo, i can try running in Windows If it doesn't work there either, i should be able to find the bug.
I updated the repository, created new branch experimental-draw-waveform, https://gitlab.com/samplehive/sample-hi ... w-waveform
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to remove trailing effect when drawing on a panel?

Post by doublemax »

apoorv569 wrote: Fri Jul 30, 2021 6:18 pm
doublemax wrote: Fri Jul 30, 2021 5:38 pm If you update your repo, i can try running in Windows If it doesn't work there either, i should be able to find the bug.
I updated the repository, created new branch experimental-draw-waveform, https://gitlab.com/samplehive/sample-hi ... w-waveform
Sorry, there are too many missing files are other compiler errors that i don't know where they're coming from. I don't think i can get this to compile under Windows in a reasonable amount of time.
Use the source, Luke!
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to remove trailing effect when drawing on a panel?

Post by doublemax »

I built this sample which pretty much does what you're trying to do.

I tested this under Windows and Linux (GTK3). Under Windows is flickers heavily, but that's intentional in this case for demonstration purposes.

It's a drop-in replacement for the "minimal" sample that comes with wxWidgets.

I hope this helps.

Code: Select all

/////////////////////////////////////////////////////////////////////////////
// Name:        minimal.cpp
// Purpose:     Minimal wxWidgets sample
// Author:      Julian Smart
// Modified by:
// Created:     04/01/98
// Copyright:   (c) Julian Smart
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ============================================================================
// declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"


// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

// ----------------------------------------------------------------------------
// resources
// ----------------------------------------------------------------------------

// the application icon (under Windows it is in resources and even
// though we could still include the XPM here it would be unused)
#ifndef wxHAS_IMAGES_IN_RESOURCES
    #include "../sample.xpm"
#endif

// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------

// Define a new application type, each program should derive a class from wxApp
class MyApp : public wxApp
{
public:
    // override base class virtuals
    // ----------------------------

    // this one is called on application startup and is a good place for the app
    // initialization (doing it here and not in the ctor allows to have an error
    // return: if OnInit() returns false, the application terminates)
    virtual bool OnInit() wxOVERRIDE;
};

// Define a new frame type: this is going to be our main frame
class MyFrame : public wxFrame
{
public:
    // ctor(s)
    MyFrame(const wxString& title);

    // event handlers (these functions should _not_ be virtual)
    void OnQuit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    void OnPaint(wxPaintEvent &event);
    void OnTimer(wxTimerEvent &event);

private:
    void UpdateBGBitmap();

    wxPanel *m_panel;
    wxTimer m_timer;
    wxBitmap m_bgcache;
    double m_progress;

    // any class wishing to process wxWidgets events must use this macro
    wxDECLARE_EVENT_TABLE();
};

// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------

// IDs for the controls and the menu commands
enum
{
    // menu items
    Minimal_Quit = wxID_EXIT,

    // it is important for the id corresponding to the "About" command to have
    // this standard value as otherwise it won't be handled properly under Mac
    // (where it is special and put into the "Apple" menu)
    Minimal_About = wxID_ABOUT
};

// ----------------------------------------------------------------------------
// event tables and other macros for wxWidgets
// ----------------------------------------------------------------------------

// the event tables connect the wxWidgets events with the functions (event
// handlers) which process them. It can be also done at run-time, but for the
// simple menu events like this the static method is much simpler.
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(Minimal_Quit,  MyFrame::OnQuit)
    EVT_MENU(Minimal_About, MyFrame::OnAbout)
wxEND_EVENT_TABLE()

// Create a new application object: this macro will allow wxWidgets to create
// the application object during program execution (it's better than using a
// static object for many reasons) and also implements the accessor function
// wxGetApp() which will return the reference of the right type (i.e. MyApp and
// not wxApp)
wxIMPLEMENT_APP(MyApp);

// ============================================================================
// implementation
// ============================================================================

// ----------------------------------------------------------------------------
// the application class
// ----------------------------------------------------------------------------

// 'Main program' equivalent: the program execution "starts" here
bool MyApp::OnInit()
{
    // call the base class initialization method, currently it only parses a
    // few common command-line options but it could be do more in the future
    if ( !wxApp::OnInit() )
        return false;

    // create the main application window
    MyFrame *frame = new MyFrame("Minimal wxWidgets App");

    // and show it (the frames, unlike simple controls, are not shown when
    // created initially)
    frame->Show(true);

    // success: wxApp::OnRun() will be called which will enter the main message
    // loop and the application will run. If we returned false here, the
    // application would exit immediately.
    return true;
}

// ----------------------------------------------------------------------------
// main frame
// ----------------------------------------------------------------------------

// frame constructor
MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
{
    // set the frame icon
    SetIcon(wxICON(sample));

#if wxUSE_MENUBAR
    // create a menu bar
    wxMenu *fileMenu = new wxMenu;

    // the "About" item should be in the help menu
    wxMenu *helpMenu = new wxMenu;
    helpMenu->Append(Minimal_About, "&About\tF1", "Show about dialog");

    fileMenu->Append(Minimal_Quit, "E&xit\tAlt-X", "Quit this program");

    // now append the freshly created menu to the menu bar...
    wxMenuBar *menuBar = new wxMenuBar();
    menuBar->Append(fileMenu, "&File");
    menuBar->Append(helpMenu, "&Help");

    // ... and attach this menu bar to the frame
    SetMenuBar(menuBar);
#else // !wxUSE_MENUBAR
    // If menus are not available add a button to access the about box
    wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    wxButton* aboutBtn = new wxButton(this, wxID_ANY, "About...");
    aboutBtn->Bind(wxEVT_BUTTON, &MyFrame::OnAbout, this);
    sizer->Add(aboutBtn, wxSizerFlags().Center());
    SetSizer(sizer);
#endif // wxUSE_MENUBAR/!wxUSE_MENUBAR

#if wxUSE_STATUSBAR
    // create a status bar just for fun (by default with 1 pane only)
    CreateStatusBar(2);
    SetStatusText("Welcome to wxWidgets!");
#endif // wxUSE_STATUSBAR

    wxPanel *panel = new wxPanel(this, wxID_ANY);
    wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);

    m_panel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE);
    m_panel->SetMinSize( wxSize(-1, 200) );
    m_panel->SetBackgroundColour(*wxRED);
    m_panel->Bind(wxEVT_PAINT, &MyFrame::OnPaint, this);

    mainSizer->Add(m_panel, 0, wxEXPAND, 0);
    panel->SetSizer(mainSizer);

    m_progress = 0;
    m_timer.SetOwner(this);
    m_timer.Start(15);
    Bind(wxEVT_TIMER, &MyFrame::OnTimer, this);
}


// event handlers
void MyFrame::OnPaint(wxPaintEvent &event)
{
    wxPaintDC dc(m_panel);

    const wxSize &size = m_panel->GetClientSize();
    if(!m_bgcache.IsOk() || m_bgcache.GetWidth() != size.x || m_bgcache.GetHeight() != size.y)
    {
      wxLogDebug("creating new bitmap");
#if 0
      m_bgcache = wxBitmap( wxImage(size.x, size.y), 24);
#else
      m_bgcache.Create(size.x, size.y, 24);
#endif
      UpdateBGBitmap();
    }

    dc.DrawBitmap(m_bgcache, 0, 0, false);

    // draw progress indicator
    int progress_x = (int)(m_progress * size.x);
    dc.SetPen(*wxRED);
    dc.DrawLine(progress_x, 0, progress_x, size.y - 1);
}

void MyFrame::OnTimer(wxTimerEvent &event)
{
  m_progress += 0.003;
  if(m_progress > 1.0 )
    m_progress -= 1.0;

  // wxLogDebug("timer %.2f", m_progress);
  m_panel->Refresh();
}

void MyFrame::UpdateBGBitmap()
{
    wxMemoryDC mdc(m_bgcache);

    // clear background
    mdc.SetBrush(*wxWHITE);
    mdc.Clear();

    mdc.SetPen(*wxBLUE);

    int yBase = m_bgcache.GetHeight() / 2;
    double x_scale = 0.1;

    for(int x = 0; x < m_bgcache.GetWidth(); x++)
    {
        int y = (int)(sin(x_scale * x) * yBase);
        mdc.DrawLine(x, yBase, x, yBase + y);
    }
}


void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    // true is to force the frame to close
    Close(true);
}

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
    wxMessageBox(wxString::Format
                 (
                    "Welcome to %s!\n"
                    "\n"
                    "This is the minimal wxWidgets sample\n"
                    "running under %s.",
                    wxVERSION_STRING,
                    wxGetOsDescription()
                 ),
                 "About wxWidgets minimal sample",
                 wxOK | wxICON_INFORMATION,
                 this);
}
Use the source, Luke!
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: How to remove trailing effect when drawing on a panel?

Post by apoorv569 »

doublemax wrote: Fri Jul 30, 2021 10:22 pm I built this sample which pretty much does what you're trying to do.

I tested this under Windows and Linux (GTK3). Under Windows is flickers heavily, but that's intentional in this case for demonstration purposes.

It's a drop-in replacement for the "minimal" sample that comes with wxWidgets.

I hope this helps.

Code: Select all

/////////////////////////////////////////////////////////////////////////////
// Name:        minimal.cpp
// Purpose:     Minimal wxWidgets sample
// Author:      Julian Smart
// Modified by:
// Created:     04/01/98
// Copyright:   (c) Julian Smart
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ============================================================================
// declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"


// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

// ----------------------------------------------------------------------------
// resources
// ----------------------------------------------------------------------------

// the application icon (under Windows it is in resources and even
// though we could still include the XPM here it would be unused)
#ifndef wxHAS_IMAGES_IN_RESOURCES
    #include "../sample.xpm"
#endif

// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------

// Define a new application type, each program should derive a class from wxApp
class MyApp : public wxApp
{
public:
    // override base class virtuals
    // ----------------------------

    // this one is called on application startup and is a good place for the app
    // initialization (doing it here and not in the ctor allows to have an error
    // return: if OnInit() returns false, the application terminates)
    virtual bool OnInit() wxOVERRIDE;
};

// Define a new frame type: this is going to be our main frame
class MyFrame : public wxFrame
{
public:
    // ctor(s)
    MyFrame(const wxString& title);

    // event handlers (these functions should _not_ be virtual)
    void OnQuit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    void OnPaint(wxPaintEvent &event);
    void OnTimer(wxTimerEvent &event);

private:
    void UpdateBGBitmap();

    wxPanel *m_panel;
    wxTimer m_timer;
    wxBitmap m_bgcache;
    double m_progress;

    // any class wishing to process wxWidgets events must use this macro
    wxDECLARE_EVENT_TABLE();
};

// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------

// IDs for the controls and the menu commands
enum
{
    // menu items
    Minimal_Quit = wxID_EXIT,

    // it is important for the id corresponding to the "About" command to have
    // this standard value as otherwise it won't be handled properly under Mac
    // (where it is special and put into the "Apple" menu)
    Minimal_About = wxID_ABOUT
};

// ----------------------------------------------------------------------------
// event tables and other macros for wxWidgets
// ----------------------------------------------------------------------------

// the event tables connect the wxWidgets events with the functions (event
// handlers) which process them. It can be also done at run-time, but for the
// simple menu events like this the static method is much simpler.
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(Minimal_Quit,  MyFrame::OnQuit)
    EVT_MENU(Minimal_About, MyFrame::OnAbout)
wxEND_EVENT_TABLE()

// Create a new application object: this macro will allow wxWidgets to create
// the application object during program execution (it's better than using a
// static object for many reasons) and also implements the accessor function
// wxGetApp() which will return the reference of the right type (i.e. MyApp and
// not wxApp)
wxIMPLEMENT_APP(MyApp);

// ============================================================================
// implementation
// ============================================================================

// ----------------------------------------------------------------------------
// the application class
// ----------------------------------------------------------------------------

// 'Main program' equivalent: the program execution "starts" here
bool MyApp::OnInit()
{
    // call the base class initialization method, currently it only parses a
    // few common command-line options but it could be do more in the future
    if ( !wxApp::OnInit() )
        return false;

    // create the main application window
    MyFrame *frame = new MyFrame("Minimal wxWidgets App");

    // and show it (the frames, unlike simple controls, are not shown when
    // created initially)
    frame->Show(true);

    // success: wxApp::OnRun() will be called which will enter the main message
    // loop and the application will run. If we returned false here, the
    // application would exit immediately.
    return true;
}

// ----------------------------------------------------------------------------
// main frame
// ----------------------------------------------------------------------------

// frame constructor
MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
{
    // set the frame icon
    SetIcon(wxICON(sample));

#if wxUSE_MENUBAR
    // create a menu bar
    wxMenu *fileMenu = new wxMenu;

    // the "About" item should be in the help menu
    wxMenu *helpMenu = new wxMenu;
    helpMenu->Append(Minimal_About, "&About\tF1", "Show about dialog");

    fileMenu->Append(Minimal_Quit, "E&xit\tAlt-X", "Quit this program");

    // now append the freshly created menu to the menu bar...
    wxMenuBar *menuBar = new wxMenuBar();
    menuBar->Append(fileMenu, "&File");
    menuBar->Append(helpMenu, "&Help");

    // ... and attach this menu bar to the frame
    SetMenuBar(menuBar);
#else // !wxUSE_MENUBAR
    // If menus are not available add a button to access the about box
    wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    wxButton* aboutBtn = new wxButton(this, wxID_ANY, "About...");
    aboutBtn->Bind(wxEVT_BUTTON, &MyFrame::OnAbout, this);
    sizer->Add(aboutBtn, wxSizerFlags().Center());
    SetSizer(sizer);
#endif // wxUSE_MENUBAR/!wxUSE_MENUBAR

#if wxUSE_STATUSBAR
    // create a status bar just for fun (by default with 1 pane only)
    CreateStatusBar(2);
    SetStatusText("Welcome to wxWidgets!");
#endif // wxUSE_STATUSBAR

    wxPanel *panel = new wxPanel(this, wxID_ANY);
    wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);

    m_panel = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE);
    m_panel->SetMinSize( wxSize(-1, 200) );
    m_panel->SetBackgroundColour(*wxRED);
    m_panel->Bind(wxEVT_PAINT, &MyFrame::OnPaint, this);

    mainSizer->Add(m_panel, 0, wxEXPAND, 0);
    panel->SetSizer(mainSizer);

    m_progress = 0;
    m_timer.SetOwner(this);
    m_timer.Start(15);
    Bind(wxEVT_TIMER, &MyFrame::OnTimer, this);
}


// event handlers
void MyFrame::OnPaint(wxPaintEvent &event)
{
    wxPaintDC dc(m_panel);

    const wxSize &size = m_panel->GetClientSize();
    if(!m_bgcache.IsOk() || m_bgcache.GetWidth() != size.x || m_bgcache.GetHeight() != size.y)
    {
      wxLogDebug("creating new bitmap");
#if 0
      m_bgcache = wxBitmap( wxImage(size.x, size.y), 24);
#else
      m_bgcache.Create(size.x, size.y, 24);
#endif
      UpdateBGBitmap();
    }

    dc.DrawBitmap(m_bgcache, 0, 0, false);

    // draw progress indicator
    int progress_x = (int)(m_progress * size.x);
    dc.SetPen(*wxRED);
    dc.DrawLine(progress_x, 0, progress_x, size.y - 1);
}

void MyFrame::OnTimer(wxTimerEvent &event)
{
  m_progress += 0.003;
  if(m_progress > 1.0 )
    m_progress -= 1.0;

  // wxLogDebug("timer %.2f", m_progress);
  m_panel->Refresh();
}

void MyFrame::UpdateBGBitmap()
{
    wxMemoryDC mdc(m_bgcache);

    // clear background
    mdc.SetBrush(*wxWHITE);
    mdc.Clear();

    mdc.SetPen(*wxBLUE);

    int yBase = m_bgcache.GetHeight() / 2;
    double x_scale = 0.1;

    for(int x = 0; x < m_bgcache.GetWidth(); x++)
    {
        int y = (int)(sin(x_scale * x) * yBase);
        mdc.DrawLine(x, yBase, x, yBase + y);
    }
}


void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    // true is to force the frame to close
    Close(true);
}

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
    wxMessageBox(wxString::Format
                 (
                    "Welcome to %s!\n"
                    "\n"
                    "This is the minimal wxWidgets sample\n"
                    "running under %s.",
                    wxVERSION_STRING,
                    wxGetOsDescription()
                 ),
                 "About wxWidgets minimal sample",
                 wxOK | wxICON_INFORMATION,
                 this);
}
Thank for the example code. I compiled it, and it ran successfully show a very small box, but it was working as intended.
Image

I added few things, that were in the code you shared, like clearing the background while drawing, and adding wxFULL_REPAINT_ON_RESIZE. But it didn't help. But I noticed that if I resize the splitter or the window, it shows the waveform then. I also tried removing the code I added from your sample, and it was still working. So I guess the problem is that it is not updating the panel. I have Refresh() in the timer event handler, I also tried changing it to m_TopWaveformPanel->Refresh(), still no luck. Also with m_WaveformBitmap.Create() still gives the old error, so I am working with wxImage only. I have the splitter resize on CallAfter() could this be an issue? In the constructor,

Code: Select all

    CallAfter(&MainFrame::SetAfterFrameCreate);
and here is the handler,

Code: Select all

void MainFrame::SetAfterFrameCreate()
{
    m_TopSplitter->SetSashPosition(200);
    m_BottomSplitter->SetSashPosition(300);
}
I have this as I was having problem with splitter not appearing on the desired position when app is launched initially.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to remove trailing effect when drawing on a panel?

Post by doublemax »

That's not how it's supposed to look like, even under Linux:
Screenshot_2021-07-31_11-37-45.png
Screenshot_2021-07-31_11-37-45.png (12.34 KiB) Viewed 1150 times
Using Mint 20

Try building my sample with wx3.1.5 and see if it makes any difference.
Use the source, Luke!
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: How to remove trailing effect when drawing on a panel?

Post by apoorv569 »

doublemax wrote: Sat Jul 31, 2021 9:39 am That's not how it's supposed to look like, even under Linux:

Screenshot_2021-07-31_11-37-45.png
Using Mint 20

Try building my sample with wx3.1.5 and see if it makes any difference.
I tried with wx3.1.5 and it looks how you showed in the screenshot. So I guess problem is with wx.3.0.x.
Image

But when I compile my application with wx3.1.5 I get a lot of assert messages about wxALIGN_RIGHT flag,

Code: Select all

./src/common/sizer.cpp(2118): assert "!(flags & wxALIGN_RIGHT)" failed in DoInsert(): Horizontal alignment flags are ignored in horizontal sizers
According to the error the problem should be with these items,

Code: Select all

    m_BrowserControlSizer->Add(m_LoopPointAButton, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
    m_BrowserControlSizer->Add(m_LoopPointAText, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
    m_BrowserControlSizer->Add(m_LoopPointBButton, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
    m_BrowserControlSizer->Add(m_LoopPointBText, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
    m_BrowserControlSizer->Add(m_MuteButton, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
    m_BrowserControlSizer->Add(m_VolumeSlider, 1, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
    m_BrowserControlSizer->Add(m_AutoPlayCheck, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 2);
I tried removing the wxALIGN_RIGHT flag, but it still gives the error.

And even after continuing through these assert messages, when I play a sample, waveform doesn't get shown. Resizing the splitter or window, again throws these wxALIGN_RIGHT assert messages.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to remove trailing effect when drawing on a panel?

Post by doublemax »

Resizing the splitter or window, again throws these wxALIGN_RIGHT assert messages.
If these are the only asserts, it should be no problem to use 3.1.5

Newer wx version are just pickier about wrong sizer flag. Having wxALIGN_RIGHT in a horizontal sizer makes no sense, so you get these asserts. Just fix them one by one.
Use the source, Luke!
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: How to remove trailing effect when drawing on a panel?

Post by apoorv569 »

doublemax wrote: Sat Jul 31, 2021 10:52 am
Resizing the splitter or window, again throws these wxALIGN_RIGHT assert messages.
If these are the only asserts, it should be no problem to use 3.1.5

Newer wx version are just pickier about wrong sizer flag. Having wxALIGN_RIGHT in a horizontal sizer makes no sense, so you get these asserts. Just fix them one by one.
Okay, I was able to fix assert messages, removed all the occurrences of wxALIGN_RIGHT flags. But the waveform is still now drawn. Only when I resize the window or splitter it gets drawn.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to remove trailing effect when drawing on a panel?

Post by doublemax »

apoorv569 wrote: Sat Jul 31, 2021 11:29 am But the waveform is still now drawn. Only when I resize the window or splitter it gets drawn.
Isn't that a huge step forward since yesterday?

So you mean you don't see the time indicator moving across the image? Is the timer running and do you call Refresh() on the waveformpanel in the event handler?
Use the source, Luke!
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: How to remove trailing effect when drawing on a panel?

Post by apoorv569 »

Isn't that a huge step forward since yesterday?
I think so :)
So you mean you don't see the time indicator moving across the image? Is the timer running and do you call Refresh() on the waveformpanel in the event handler?
The position marker moves fine, but in place of the waveform bitmap, I only see black background, I am calling Refresh() in the wxTimer event handler. I also tried calling m_TopWaveformPanel->Refresh() instead of just Refresh() which will be for the wxFrame.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to remove trailing effect when drawing on a panel?

Post by doublemax »

But during resizing etc. you see the waveform? Try setting the background color of the panel to red (with SetBackgroundColor). If you then see red instead of black background, call m_TopWaveformPanel->SetBackgroundStyle( wxBG_STYLE_PAINT ) once after creating it.
Use the source, Luke!
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: How to remove trailing effect when drawing on a panel?

Post by apoorv569 »

doublemax wrote: Sat Jul 31, 2021 12:35 pm But during resizing etc. you see the waveform? Try setting the background color of the panel to red (with SetBackgroundColor). If you then see red instead of black background, call m_TopWaveformPanel->SetBackgroundStyle( wxBG_STYLE_PAINT ) once after creating it.
I did copy that from the code you sent too, but it is always black, when I resize the splitter or window, it changes to white, which the clear background is doing. and it shows blue waveform on it then.

Code: Select all

    m_TopWaveformPanel = new wxPanel(m_TopPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER | wxFULL_REPAINT_ON_RESIZE);
    m_TopWaveformPanel->SetBackgroundColour(*wxRED);
 
Here is the OnPaint()

Code: Select all

void MainFrame::OnPaint(wxPaintEvent& event)
{
    wxPaintDC dc(m_TopWaveformPanel);

    const wxSize& size = m_TopWaveformPanel->GetClientSize();

    if(!m_WaveformBitmap.IsOk()
       // || m_WaveformBitmap.IsNull()
       || m_WaveformBitmap.GetWidth() != size.x
       || m_WaveformBitmap.GetHeight() != size.y)
    {
        wxLogDebug("Updating waveform bitmap..");
#if 0
        m_WaveformBitmap = wxBitmap(wxImage(size.x, size.y), 24);
#else
        m_WaveformBitmap.Create(size.x, size.y, 24);
#endif
        UpdateWaveformBitmap();
    }
    // else
        // wxLogDebug("Cannot update waveform bitmap..");

    dc.DrawBitmap(m_WaveformBitmap, 0, 0, false);
    // m_WaveformBitmap.SaveFile("waveform.png", wxBITMAP_TYPE_PNG);

    RenderPlayhead(dc);
}
Here is the waveform draw function,

Code: Select all

    /*===========================Draw code============================*/
    wxMemoryDC mdc(m_WaveformBitmap);

    // wxColour bgc =  GetBackgroundColour();
    mdc.SetBrush(*wxWHITE);
    mdc.Clear();

    mdc.SetPen(wxPen(wxColour(80, 140, 255, 190), 2, wxPENSTYLE_SOLID));
    // mdc.SetPen(*wxBLUE);

    for(int i = 0; i < waveform.size() - 1; i++)
    {
        mdc.DrawLine((display_width * i) / waveform.size(), waveform[i] + display_height / 2.0f,
                     (display_width * i) / waveform.size(), (waveform[i] / samples_per_pixel) + display_height / 2.0f);
    }
}
And here is the wxTimer handler,

Code: Select all

void MainFrame::UpdateElapsedTime(wxTimerEvent& event)
{
    wxString duration, position;
    wxLongLong llLength, llTell;

    llLength = m_MediaCtrl->Length();
    int total_min = static_cast<int>((llLength / 60000).GetValue());
    int total_sec = static_cast<int>(((llLength % 60000) / 1000).GetValue());

    llTell = m_MediaCtrl->Tell();
    int current_min = static_cast<int>((llTell / 60000).GetValue());
    int current_sec = static_cast<int>(((llTell % 60000) / 1000).GetValue());

    duration.Printf(wxT("%2i:%02i"), total_min, total_sec);
    position.Printf(wxT("%2i:%02i"), current_min, current_sec);

    m_SamplePosition->SetLabel(wxString::Format(wxT("%s/%s"), position.c_str(), duration.c_str()));

    m_TopWaveformPanel->Refresh();
    // Refresh();
}
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to remove trailing effect when drawing on a panel?

Post by doublemax »

Can you create another GIF of how it looks now?

Can you confirm that the "Updating waveform bitmap" does only get triggered on resize and not on every repaint?

Check your code if there is anything left that could clear the m_WaveformBitmap bitmap except the UpdateWaveformBitmap method.

BTW, if you still have the timer set at 1ms, change it to something more reasonable like 16ms.
Use the source, Luke!
apoorv569
Super wx Problem Solver
Super wx Problem Solver
Posts: 426
Joined: Tue Oct 20, 2020 3:35 pm

Re: How to remove trailing effect when drawing on a panel?

Post by apoorv569 »

Can you create another GIF of how it looks now?
Image
Can you confirm that the "Updating waveform bitmap" does only get triggered on resize and not on every repaint?
I added these print statements, it doesn't look like, they get printed, unless I resize the splitter or window.

Code: Select all

    /*===========================Draw code============================*/
    wxMemoryDC mdc(m_WaveformBitmap);

    // wxColour bgc =  GetBackgroundColour();
    mdc.SetBrush(*wxWHITE);
    mdc.Clear();

    mdc.SetPen(wxPen(wxColour(80, 140, 255, 190), 2, wxPENSTYLE_SOLID));
    // mdc.SetPen(*wxBLUE);

    wxLogDebug("Drawing bitmap..");        // <---------

    for(int i = 0; i < waveform.size() - 1; i++)
    {
        mdc.DrawLine((display_width * i) / waveform.size(), waveform[i] + display_height / 2.0f,
                     (display_width * i) / waveform.size(), (waveform[i] / samples_per_pixel) + display_height / 2.0f);
    }

    wxLogDebug("Done drawing bitmap..");       // <--------
Check your code if there is anything left that could clear the m_WaveformBitmap bitmap except the UpdateWaveformBitmap method.
I checked, as far as I can see, there is nothing, that could clear the bitmap.
BTW, if you still have the timer set at 1ms, change it to something more reasonable like 16ms.
I tried different values, but it doesn't look as smooth as it looks on 1ms, maybe 2-5ms. But anything above it feels a bit blurry when moving, and also it stops before the end of the panel for some reason, maybe it could not update the last few milliseconds.
Post Reply