Difference between function overwrite in derived class and bind 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.
Post Reply
cookielau
Earned a small fee
Earned a small fee
Posts: 12
Joined: Mon May 22, 2023 9:21 am

Difference between function overwrite in derived class and bind

Post by cookielau »

Hi all!
I'm currently writing a csv visualization task using wxWidgets, and I use notebook to store different panels.
In one panel, I need to draw the grid using imported data. I notice that if the grid is under a frame, it automatically supports scrolling, while if the parent is a normal panel, it can not be scrolled.
Then I found the wxScrolledWindow which satisfies my needs, but it seems the mousewheel event does not propagate to its parent, so I tried the Bind function to propagate event like this:

Code: Select all

  wxGrid* grid = new wxGrid(scrolledWindow, wxID_ANY);
  grid->CreateGrid(100, 100);
  grid->Bind(wxEVT_MOUSEWHEEL, [&](wxMouseEvent& ev)
    {
      wxScrolledWindow* scrolledWindow = dynamic_cast<wxScrolledWindow*>(GetParent());
      if (scrolledWindow)
      {
        // Pass the event to the parent wxScrolledWindow
        scrolledWindow->GetEventHandler()->ProcessEvent(ev);
      }
    });
However, it still can not help. so I asked ChatGPT, it teaches me to write a derived class of grid and implement the onMouseEvent function inside like this:

Code: Select all

class MyScrolledGrid : public wxGrid
{
public:
	MyScrolledGrid(wxWindow* parent, wxWindowID id)
		: wxGrid(parent, id)
	{
	}

	void OnMouseWheel(wxMouseEvent& event)
	{
		wxScrolledWindow* scrolledWindow = dynamic_cast<wxScrolledWindow*>(GetParent());
		if (scrolledWindow)
		{
			// Pass the event to the parent wxScrolledWindow
			scrolledWindow->GetEventHandler()->ProcessEvent(event);
		}
	}

	wxDECLARE_EVENT_TABLE();
};

wxBEGIN_EVENT_TABLE(MyScrolledGrid, wxGrid)
EVT_MOUSEWHEEL(MyScrolledGrid::OnMouseWheel)
wxEND_EVENT_TABLE()
Surprisingly it works!
Due to my limited knowledge, I cannot find the difference between these two implementation, could you please help me understand it?

Plus, ChatGPT also advices me to add a

Code: Select all

scrolledWindow->SetFocus();
but I found it does not have any difference even though I delete it, may I know in which situation this set focus is required?
Windows 10, wxWidgits 3.1.5/3.3.0
Kvaz1r
Super wx Problem Solver
Super wx Problem Solver
Posts: 352
Joined: Tue Jun 07, 2016 1:07 pm

Re: Difference between function overwrite in derived class and bind

Post by Kvaz1r »

cookielau wrote: Thu May 25, 2023 9:09 am but I found it does not have any difference even though I delete it, may I know in which situation this set focus is required?
Unfocused widget is not getting mouse events so the widget won't scroll.
Don't reinvent the wheel - wxGrid should work under panel - provide code for reproducing behaviour.
PB
Part Of The Furniture
Part Of The Furniture
Posts: 3816
Joined: Sun Jan 03, 2010 5:45 pm

Re: Difference between function overwrite in derived class and bind

Post by PB »

Kvaz1r wrote: Thu May 25, 2023 9:28 am Unfocused widget is not getting mouse events so the widget won't scroll.
Actually, in recentish Windows versions, mouse wheel scrolling works even when the window does not have input focus (unless one turns "Scroll Inactive Windows When I Hover Over Them" off in Settings). It may be the same for the other two platforms.

I have no idea what the OP is trying to achieve, so I won't comment on this.
PB
Part Of The Furniture
Part Of The Furniture
Posts: 3816
Joined: Sun Jan 03, 2010 5:45 pm

Re: Difference between function overwrite in derived class and bind

Post by PB »

I am probably misunderstanding the OP, but FWIW, both wxScrolledWindow and wxGrid behave as expected (on Windows 10). When the cursor is over a wxGrid mousewheel scrolls the grid and when the cursor hovers over a non-scrollable part of wxScrolledWindow, the scrolled window is scrolled.

Code: Select all

#include <wx/wx.h>
#include <wx/grid.h>
#include <wx/scrolwin.h>

class MyFrame : public wxFrame
{
public:
    MyFrame(wxWindow* parent = nullptr) : wxFrame(parent, wxID_ANY, "Test")
    {
        wxScrolledWindow* scrolled = new wxScrolledWindow(this);
        wxBoxSizer* scrolledSizer = new wxBoxSizer(wxVERTICAL);
        wxBoxSizer* gridSizer = new wxBoxSizer(wxHORIZONTAL);

        auto CreateGrid = [](wxWindow* parent)
        {
            wxGrid* grid = new wxGrid(parent, wxID_ANY);
            
            grid->CreateGrid(50, 50);
            grid->SetInitialSize(grid->FromDIP(wxSize(300, 300)));
            return grid;
        };

        scrolledSizer->Add(new wxButton(scrolled, wxID_ANY, "Button"), wxSizerFlags().Expand().Border());
        scrolledSizer->Add(new wxButton(scrolled, wxID_ANY, "Button"), wxSizerFlags().Expand().Border());

        gridSizer->Add(CreateGrid(scrolled), wxSizerFlags().DoubleBorder());
        gridSizer->Add(CreateGrid(scrolled), wxSizerFlags().DoubleBorder());
        scrolledSizer->Add(gridSizer, wxSizerFlags().Border());

        scrolledSizer->Add(new wxButton(scrolled, wxID_ANY, "Button"), wxSizerFlags().Expand().Border());

        scrolled->SetSizerAndFit(scrolledSizer);        
        scrolled->SetScrollRate(FromDIP(16), FromDIP(16));
        scrolled->EnableScrolling(true, true);    
    }
};

class MyApp : public wxApp
{
    bool OnInit() override
    {
        (new MyFrame())->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);
gridscroll.gif
gridscroll.gif (117.31 KiB) Viewed 129 times
Kvaz1r
Super wx Problem Solver
Super wx Problem Solver
Posts: 352
Joined: Tue Jun 07, 2016 1:07 pm

Re: Difference between function overwrite in derived class and bind

Post by Kvaz1r »

PB wrote: Thu May 25, 2023 11:20 am Actually, in recentish Windows versions, mouse wheel scrolling works even when the window does not have input focus (unless one turns "Scroll Inactive Windows When I Hover Over Them" off in Settings). It may be the same for the other two platforms.

I have no idea what the OP is trying to achieve, so I won't comment on this.
Wow, interesting, didn't know about such settings, every day learn something new, thanks.
In my Windows it was disabled by default, guess OP have the same settings as me.
cookielau
Earned a small fee
Earned a small fee
Posts: 12
Joined: Mon May 22, 2023 9:21 am

Re: Difference between function overwrite in derived class and bind

Post by cookielau »

PB wrote: Thu May 25, 2023 12:02 pm I am probably misunderstanding the OP, but FWIW, both wxScrolledWindow and wxGrid behave as expected (on Windows 10). When the cursor is over a wxGrid mousewheel scrolls the grid and when the cursor hovers over a non-scrollable part of wxScrolledWindow, the scrolled window is scrolled.

Code: Select all

#include <wx/wx.h>
#include <wx/grid.h>
#include <wx/scrolwin.h>

class MyFrame : public wxFrame
{
public:
    MyFrame(wxWindow* parent = nullptr) : wxFrame(parent, wxID_ANY, "Test")
    {
        wxScrolledWindow* scrolled = new wxScrolledWindow(this);
        wxBoxSizer* scrolledSizer = new wxBoxSizer(wxVERTICAL);
        wxBoxSizer* gridSizer = new wxBoxSizer(wxHORIZONTAL);

        auto CreateGrid = [](wxWindow* parent)
        {
            wxGrid* grid = new wxGrid(parent, wxID_ANY);
            
            grid->CreateGrid(50, 50);
            grid->SetInitialSize(grid->FromDIP(wxSize(300, 300)));
            return grid;
        };

        scrolledSizer->Add(new wxButton(scrolled, wxID_ANY, "Button"), wxSizerFlags().Expand().Border());
        scrolledSizer->Add(new wxButton(scrolled, wxID_ANY, "Button"), wxSizerFlags().Expand().Border());

        gridSizer->Add(CreateGrid(scrolled), wxSizerFlags().DoubleBorder());
        gridSizer->Add(CreateGrid(scrolled), wxSizerFlags().DoubleBorder());
        scrolledSizer->Add(gridSizer, wxSizerFlags().Border());

        scrolledSizer->Add(new wxButton(scrolled, wxID_ANY, "Button"), wxSizerFlags().Expand().Border());

        scrolled->SetSizerAndFit(scrolledSizer);        
        scrolled->SetScrollRate(FromDIP(16), FromDIP(16));
        scrolled->EnableScrolling(true, true);    
    }
};

class MyApp : public wxApp
{
    bool OnInit() override
    {
        (new MyFrame())->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);
gridscroll.gif
Thanks for your prompt reply. I've made up my grid under your suggestion. Attached herewith my implementation.

The critical point I find is the `SetInitialSize` function called by the Grid, I didn't do that before, so it seems it just fills the whole panel directly. But now I use these code to make it fit with the parent size properly:

Code: Select all

wxWindow* MyPanel::CreatePanel2(wxWindow* parent)
{
  wxScrolledWindow* scrolledWindow = new wxScrolledWindow(parent);
  wxBoxSizer* scrolledSizer = new wxBoxSizer(wxVERTICAL);

  _grid = new wxGrid(scrolledWindow, wxID_ANY);
  _grid->CreateGrid(100, 100);
  _grid->SetInitialSize(parent->GetEffectiveMinSize());
  scrolledSizer->Add(_grid, wxSizerFlags(2).Expand());

  scrolledWindow->SetSizerAndFit(scrolledSizer);
  scrolledWindow->SetScrollRate(1, 1);
  scrolledWindow->EnableScrolling(true, true);

  return scrolledWindow;
}
Again, thanks for your prompt reply and valuable help!
Attachments
grid.PNG
Windows 10, wxWidgits 3.1.5/3.3.0
cookielau
Earned a small fee
Earned a small fee
Posts: 12
Joined: Mon May 22, 2023 9:21 am

Re: Difference between function overwrite in derived class and bind

Post by cookielau »

Kvaz1r wrote: Thu May 25, 2023 9:28 am
cookielau wrote: Thu May 25, 2023 9:09 am but I found it does not have any difference even though I delete it, may I know in which situation this set focus is required?
Unfocused widget is not getting mouse events so the widget won't scroll.
Don't reinvent the wheel - wxGrid should work under panel - provide code for reproducing behaviour.
Thanks for your reply as well!
Windows 10, wxWidgits 3.1.5/3.3.0
PB
Part Of The Furniture
Part Of The Furniture
Posts: 3816
Joined: Sun Jan 03, 2010 5:45 pm

Re: Difference between function overwrite in derived class and bind

Post by PB »

cookielau wrote: Fri May 26, 2023 3:29 am Thanks for your prompt reply. I've made up my grid under your suggestion. Attached herewith my implementation.
Ah, now I see where the problem was. The grid does not fit the notebook page, it just expands to show all its contents and there is no way to scroll it past what is visible. I believe this for some reason happens only when the grid is in a notebook page.

I would consider another solution: Not using a wxScrolled but let the grid scroll itself (which among else should make grid scroll more naturally by rows, and if frozen rows/columns are used, only those should be scrolled). All you need is to make it fit the notebook page on resize, i.e., something like this:

Code: Select all

#include <wx/wx.h>
#include <wx/grid.h>
#include <wx/notebook.h>

class MyFrame : public wxFrame
{
public:
    MyFrame(wxWindow* parent = nullptr) : wxFrame(parent, wxID_ANY, "Test")
    {
        wxNotebook* notebook = new wxNotebook(this, wxID_ANY);

        for ( size_t i = 0; i < 3; ++i )
        {
            wxPanel* page = new wxPanel(notebook);            
            wxGrid*  grid = new wxGrid(page, wxID_ANY);
            
            grid->CreateGrid(50, 50);
            notebook->AddPage(page, wxString::Format("Page %zu", i + 1), true);
            page->Bind(wxEVT_SIZE, [page, grid](wxSizeEvent& e)
                {
                    grid->SetSize(page->GetClientSize());
                    e.Skip();
                });
         };        
    }
};

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        (new MyFrame())->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);
No sizers are needed in the code above because: (1) If a top level window (wxFrame here) has just one child (wxNotebook here), it will fit it to cover its client area and (2) the grid is the only child of a notebook page so we use the page area fully.

gridscroll.png
gridscroll.png (12.58 KiB) Viewed 87 times
cookielau
Earned a small fee
Earned a small fee
Posts: 12
Joined: Mon May 22, 2023 9:21 am

Re: Difference between function overwrite in derived class and bind

Post by cookielau »

My PB God, why are you so brilliant, I sincerely wish I could be as smart as you one day!
It works well for my program, plz accept my worship! Orz
Windows 10, wxWidgits 3.1.5/3.3.0
Post Reply