wxGrid and wxBitmap 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: wxGrid and wxBitmap

Post by doublemax »

Which compiler do you use? If it's Visual Studio, does it report memory leaks when you quit the application?

In the code you posted, there are two potential memory leaks, the pointers "pBlob" and "pFoto". Most likely these need to be freed, but it depends on the functions that return them.

E.g. it could be possible that the CloseResultSet() call also frees the memory "pBlob" points to.
Use the source, Luke!
Melandr
Experienced Solver
Experienced Solver
Posts: 53
Joined: Thu Oct 28, 2021 6:07 am

Re: wxGrid and wxBitmap

Post by Melandr »

I'm using MinGW under codeBlocks .
pBlob and pFoto are pointers to one element (image). Also, they are not allocated dynamically.
I found a similar topic on the forum viewtopic.php?t=31071, the question also arose about a memory leak. The fact is that the string information in the cells is deleted by the following method
Grid1->ClearGrid();
But the documentation also says that in order to display information that differs from string data, it is necessary to redefine the renderer, which we did. But I noticed that by making several different queries to the database, the allocated memory for the application grows, while the display in the cells is cleared.
PS:
Perhaps you need to override the destructor of the wxBmpGridCellRenderer class and explicitly delete the member of the wxImage m_img; class in it?

Code: Select all

class wxBmpGridCellRenderer : public wxGridCellRenderer
{
public:
    wxBmpGridCellRenderer(const wxImage& image) : wxGridCellRenderer(), m_img(image) {}
/*
    ~wxBmpGridCellRenderer()
    {
        delete m_img;
    }
*/
    void Draw(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc,
                 const wxRect& rect, int row, int col, bool isSelected);

    wxSize GetBestSize(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc,
                       int row, int col)
    {
        return wxSize(m_img.GetWidth(), m_img.GetHeight());
    }
    wxGridCellRenderer *Clone() const
    {
        return new wxBmpGridCellRenderer(m_img);
    }
private:
    wxImage m_img;
};
however, this does not work if the class member is not a pointer to a wxImage object. And I don't know how to rewrite the wxBmpGridCellRenderer constructor using an initialization list with a pointer.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid and wxBitmap

Post by doublemax »

m_img in wxBmpGridCellRenderer is a member variable, it will be destroyed when the renderer gets destroyed.
pBlob and pFoto are pointers to one element (image). Also, they are not allocated dynamically.

Code: Select all

void *pBlob = pResults->GetResultBlob(_("FIMG"),BufferOut);
Check the documentation for GetResultBlob(), it should say something about who's responsible for freeing the memory.

Code: Select all

m_foto = LoadImageFromBlob(pRetrievedBuffer,len);
What does LoadImageFromBlob do? If it creates the wxImage with new, someone must delete it later.
Use the source, Luke!
Melandr
Experienced Solver
Experienced Solver
Posts: 53
Joined: Thu Oct 28, 2021 6:07 am

Re: wxGrid and wxBitmap

Post by Melandr »

Below is the implementation of the LoadImageFromBlob() method

Code: Select all

wxImage* testWxSmithFrame::LoadImageFromBlob(const unsigned char *data, int size)
{
    if( data != NULL )
    {
        wxMemoryInputStream mi(data, size);
        wxImage *img = new wxImage(mi, wxBITMAP_TYPE_ANY);
        if( img != NULL && img->IsOk() ) return img;
        // wxLogDebug( wxT("DB::LoadImageFromBlob error: data=%p size=%d"), data, size);
        // caller is responsible for deleting the pointer
        delete img;
    }
    return NULL;
}
pFoto is a pointer to wxImage and is declared in the main form class

Code: Select all

class testWxSmithFrame: public wxFrame
{
public:
     testWxSmithFrame(wxWindow* parent,wxWindowID id = -1);
     virtual ~testWxSmithFrame();

     wxImage*pPhoto;
private:

     //(*Handlers(testWxSmithFrame)
     void OnQuit(wxCommandEvent& event);
     void OnAbout(wxCommandEvent& event);
     void OnSendQueryButtonClick(wxCommandEvent& event);
     void OnClearEntryFieldButtonClick(wxCommandEvent& event);
     void OnCheckBoxEnableFotoClick(wxCommandEvent& event);
     //*)
     virtual int OnExit();
     bool OpenDB();
     wxImage* LoadImageFromBlob(const unsigned char*, int);
...
}
I make several identical queries to the database in a row and in the Windows task manager it is clear that the memory consumed by the application is increasing. Therefore, I concluded that there is a memory leak, but I can not understand how it can be detected.

How can I check how much memory is allocated for the renderer? Since most likely

Code: Select all

     Grid1->ClearGrid();
     for(int i = 0; i < Grid1->GetNumberRows(); i++)
         Grid1->SetCellRenderer(i,0,NULL);
do not remove the renderer from memory
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid and wxBitmap

Post by doublemax »

pPhoto doesn't need to be a member variable.

And as the renderer makes a copy of the image, you can (and should) delete pPhoto after creating the renderer.
Use the source, Luke!
Melandr
Experienced Solver
Experienced Solver
Posts: 53
Joined: Thu Oct 28, 2021 6:07 am

Re: wxGrid and wxBitmap

Post by Melandr »

And since I'm displaying the image through DrawBitmap, it is necessary to refine the implementation of the Draw method, with the ability to change the display. But, to be honest, I find it difficult to use the DrawBitmap method to hide it and then display it
Last edited by doublemax on Mon Jan 24, 2022 1:33 pm, edited 1 time in total.
Reason: Sorry, i accidently edited your post instead of replying to it. So some parts are missing now.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid and wxBitmap

Post by doublemax »

Melandr wrote: Mon Jan 24, 2022 1:19 pm And since I'm displaying the image through DrawBitmap, it is necessary to refine the implementation of the Draw method, with the ability to change the display. But, to be honest, I find it difficult to use the DrawBitmap method to hide it and then display it
Don't overthink it, this is very simple program logic. Depending on a condition you either call DrawBitmap() or you don't.
Use the source, Luke!
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7458
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: wxGrid and wxBitmap

Post by ONEEYEMAN »

Hi,
Are you doing it the same way as in the sample?

Thank you.
Melandr
Experienced Solver
Experienced Solver
Posts: 53
Joined: Thu Oct 28, 2021 6:07 am

Re: wxGrid and wxBitmap

Post by Melandr »

Indeed, it is simple. True, I have a visibility condition
if(CheckBoxEnableFoto->GetValue())
not available in renderer method
Melandr
Experienced Solver
Experienced Solver
Posts: 53
Joined: Thu Oct 28, 2021 6:07 am

Re: wxGrid and wxBitmap

Post by Melandr »

ONEEYEMAN wrote: Mon Jan 24, 2022 2:22 pm Hi,
Are you doing it the same way as in the sample?

Thank you.
What sample do you mean? And what exactly do I do?
Melandr
Experienced Solver
Experienced Solver
Posts: 53
Joined: Thu Oct 28, 2021 6:07 am

Re: wxGrid and wxBitmap

Post by Melandr »

doublemax wrote: Mon Jan 24, 2022 1:33 pm
Melandr wrote: Mon Jan 24, 2022 1:19 pm And since I'm displaying the image through DrawBitmap, it is necessary to refine the implementation of the Draw method, with the ability to change the display. But, to be honest, I find it difficult to use the DrawBitmap method to hide it and then display it
Don't overthink it, this is very simple program logic. Depending on a condition you either call DrawBitmap() or you don't.
Or do I need to add a public class member (photo display flag) in the renderer class and set or uncheck the flag in the checkbox handler, and check its state in the Draw method?
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid and wxBitmap

Post by doublemax »

Melandr wrote: Mon Jan 24, 2022 2:36 pm
doublemax wrote: Mon Jan 24, 2022 1:33 pm
Melandr wrote: Mon Jan 24, 2022 1:19 pm And since I'm displaying the image through DrawBitmap, it is necessary to refine the implementation of the Draw method, with the ability to change the display. But, to be honest, I find it difficult to use the DrawBitmap method to hide it and then display it
Don't overthink it, this is very simple program logic. Depending on a condition you either call DrawBitmap() or you don't.
Or do I need to add a public class member (photo display flag) in the renderer class and set or uncheck the flag in the checkbox handler, and check its state in the Draw method?
That depends on whether this is a global switch (turn off/on images), or can be set for each item. In the latter case: yes, you'll need another flag for that.
Use the source, Luke!
Melandr
Experienced Solver
Experienced Solver
Posts: 53
Joined: Thu Oct 28, 2021 6:07 am

Re: wxGrid and wxBitmap

Post by Melandr »

If I declare a checkbox in the declaration of the class of the Main form in the private section, then I can access the checkbox properties from the methods of the main form class, but I cannot access from the method of the renderer class. And vice versa. How can I check if the checkbox is enabled from all classes?
As I understand it, I should get a pointer to the parent of the checkbox - the main form, and then check the state of the checkbox? But which class should the pointer to the main form be a member of?
How to get checkbox state from renderer class?
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGrid and wxBitmap

Post by doublemax »

There are several ways to do that.

1)
- renderer has bool flag to control image visibility, startvalue passed to constructor
- renderer has public method to change status of that flag
When the status of the checkbox changes, iterate over the grid, get the renderers, and call method to change visibility

2)
- subclass wxGrid
- custom wxGrid has bool flag to control image visibility
- custom wxGrid has public method to change status of that flag
renderer Draw() method gets reference to wxGrid. Use that to check status of flag
Use the source, Luke!
Melandr
Experienced Solver
Experienced Solver
Posts: 53
Joined: Thu Oct 28, 2021 6:07 am

Re: wxGrid and wxBitmap

Post by Melandr »

The first two points are not difficult.
- renderer has bool flag to control image visibility, startvalue passed to constructor
- renderer has public method to change status of that flag
But on the third point, how can you control the displayed information in a cell without clearing the renderer? After filling the cells of the first column with images, I can remove the images before a new request with the following code

Code: Select all

    Grid1->ClearGrid();
    ClearCellGrid(*Grid1);
I can not understand how you can hide the display in the cell, and then display it again? Below is the renderer code in the cell

Code: Select all

void wxBmpGridCellRenderer::Draw(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, const wxRect& rect, int row, int col, bool isSelected)
{
    if(m_IsVisiblePhoto)
    {
        wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
        dc.SetClippingRegion(rect);
        m_img.Rescale(wxSize(109,145).GetWidth(),wxSize(109,145).GetHeight());
        wxBitmap cellBitmap(m_img);
        dc.DrawBitmap(cellBitmap,rect.x,rect.y);
        dc.DestroyClippingRegion();
    }
}
Post Reply