Search code examples
pythonwxpythonwxwidgets

How to overlap wxStaticBitmap images in wxGridBagSizer using wxFormBuilder in wxPython


I need to create an OR Gate by using 4 images(3 lines and Gate symbol). This requires overlapping of images placed in cells in wxGridBagSizer. How can I achieve that?

Attempt using wxFormBuilder

I am trying to set negative vgap and hgap using wxFormBuilder to overlap the images but wxFormBuilder is not accepting negative values.

Then I tried to write raw code to achieve the same:

 self.widgetSizer = wx.GridBagSizer(hgap=-6,vgap=-20)


 self.orGateImage = wx.StaticBitmap(self, -1, self.orGateImageBitmap, style=wx.BITMAP_TYPE_PNG) 
 self.LineImageOffA = wx.StaticBitmap(self, -1, self.LineImageOffBitmap, style=wx.BITMAP_TYPE_PNG)
 self.LineImageOffB = wx.StaticBitmap(self, -1, self.LineImageOffBitmap, style=wx.BITMAP_TYPE_PNG)
 self.LineImageOffX = wx.StaticBitmap(self, -1, self.LineImageOffBitmap, style=wx.BITMAP_TYPE_PNG)


 self.LetterAImage = wx.StaticBitmap(self, -1, self.LetterAImageBitmap, style=wx.BITMAP_TYPE_PNG)
 self.LetterBImage = wx.StaticBitmap(self, -1, self.LetterBImageBitmap, style=wx.BITMAP_TYPE_PNG)
 self.LetterXImage = wx.StaticBitmap(self, -1, self.LetterXImageBitmap, style=wx.BITMAP_TYPE_PNG)


 self.widgetSizer.Add(self.LineImageOffA, pos=(0,1), border=10) 
 self.widgetSizer.Add(self.LineImageOffB, pos=(2,1), border=2)
 self.widgetSizer.Add(self.LineImageOffX, pos=(1,3), flag=wx.ALIGN_CENTER,border=2)
 self.widgetSizer.Add(self.orGateImage, pos=(1,2), border=10)
 self.widgetSizer.Add(self.LetterAImage, pos=(0,0), border=10)
 self.widgetSizer.Add(self.LetterBImage, pos=(2,0), border=10)
 self.widgetSizer.Add(self.LetterXImage, pos=(1,4), flag=wx.ALIGN_CENTER, border=10)

 self.frame.fSizer.Layout()

And it worked. I could get the following output:

Attempt using raw code

Please help me achieve this using wxFormBuilder as I need to create such elements quickly in my project. Is there any other alternative to get this done?

The code generated by wxFormBuilder is as follows:

MyFrame1::MyFrame1( 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 );

    wxBoxSizer* bSizer1;
    bSizer1 = new wxBoxSizer( wxVERTICAL );

    wxGridBagSizer* gbSizer1;
    gbSizer1 = new wxGridBagSizer( 0, 0 );
    gbSizer1->SetFlexibleDirection( wxBOTH );
    gbSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );

    m_bitmap1 = new wxStaticBitmap( this, wxID_ANY, wxBitmap( wxT("../../home/ece/Desktop/scripts/fromPI/GREEN_LINE_OFF_SMALL.png"), wxBITMAP_TYPE_ANY ), wxDefaultPosition, wxSize( 85,5 ), 0 );
    gbSizer1->Add( m_bitmap1, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALL, 5 );

    m_bitmap2 = new wxStaticBitmap( this, wxID_ANY, wxBitmap( wxT("../../home/ece/Desktop/scripts/fromPI/GREEN_LINE_OFF_SMALL.png"), wxBITMAP_TYPE_ANY ), wxDefaultPosition, wxSize( 85,5 ), 0 );
    gbSizer1->Add( m_bitmap2, wxGBPosition( 2, 0 ), wxGBSpan( 1, 1 ), wxALL, 5 );

    m_bitmap3 = new wxStaticBitmap( this, wxID_ANY, wxBitmap( wxT("../../home/ece/Desktop/scripts/fromPI/OR_GATE_SMALL.png"), wxBITMAP_TYPE_ANY ), wxDefaultPosition, wxDefaultSize, 0 );
    gbSizer1->Add( m_bitmap3, wxGBPosition( 1, 2 ), wxGBSpan( 1, 1 ), wxALL, 5 );

   m_bitmap4 = new wxStaticBitmap( this, wxID_ANY, wxBitmap( wxT("../../home/ece/Desktop/scripts/fromPI/GREEN_LINE_OFF_SMALL.png"), wxBITMAP_TYPE_ANY ), wxDefaultPosition, wxSize( 85,5 ), 0 );
   gbSizer1->Add( m_bitmap4, wxGBPosition( 1, 3 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER|wxALL, 5 );

   bSizer1->Add( gbSizer1, 1, wxEXPAND, 5 );

   this->SetSizer( bSizer1 );
   this->Layout();
}

MyFrame1::~MyFrame1()
{
}

Solution

  • wxWidgets does not support overlapping sibling widgets (your wx.StaticBitmaps in this case,) and the behavior of what happens when you try to do so is undefined. In addition, sizers are not designed to be able to overlap items, that goes against their fundamental purpose IMO.

    However, you can easily draw the bitmaps yourself without using a widget for each one, and have them overlap as much or as little as you need. To do this you can handle the EVT_PAINT method in a class based on wx.Window or wx.Panel and draw the bitmaps in that paint handler, and then put an instance of that window in your frame. There are lots of examples of drawing in a paint handler in the demo and various tutorials.