Images/Controls + Text Boxes - transparent background colour

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
uketernity
Earned a small fee
Earned a small fee
Posts: 13
Joined: Sun May 21, 2006 9:36 am

Images/Controls + Text Boxes - transparent background colour

Post by uketernity » Mon May 29, 2006 10:19 am

Hi,

Ive searched through the forums to try and find a solution to this, but so far have not found a solution.

This is my situation:

I have an image painted onto the back of my frame using DC, now this works fine, however, the problem comes when putting in.
StaticBitmap images with transparency - the transparent regions of the image show up with the background colour of the frame (grey) and not the DC image painted on.
controls that dont have square corners - the region of the square that the control "occupies" is grey, ie, with a radio button, each corner has a grey part.
Text boxes. The background to the text is the background colour of the wxFrame.

I have found a kind of solution that draws the text labels onto the background in the onPaint method and this works, however, I cant do the same thing for images as my programs needs to hide them

Code: Select all

Image1->Show(false);
as part of its operation. Also, when you hide the image, the image correctly dissappears, however the region that it takes up in the frame is grey for a split second and then is overwritten with the background image to the frame.

Does anyone know how to fix this problem?

Thanks.

Oli

Cursor
Earned some good credits
Earned some good credits
Posts: 120
Joined: Sun Aug 29, 2004 3:09 pm
Location: Grenoble, France
Contact:

Post by Cursor » Tue May 30, 2006 9:23 am

Perhaps it do that beacause you use wxCLIP_CHILDREN style for your frame.
Indeed, this style force to not repaint the background under children.
test without this style.
What is little and green, witch go up and down ??
Yoda playing with the force.

uketernity
Earned a small fee
Earned a small fee
Posts: 13
Joined: Sun May 21, 2006 9:36 am

Post by uketernity » Tue May 30, 2006 9:29 am

Hi,

Unfortunately im not using the wxClip_Children style for my frame. Any other ideas?

Oli

wxjonas
In need of some credit
In need of some credit
Posts: 1
Joined: Tue May 30, 2006 11:10 am

Post by wxjonas » Tue May 30, 2006 4:28 pm

Hi

You shouldn't put your controls directly on the frame, instead put a wxPanel on the frame, and your controls on the panel. This is more crossplatform safe, and make sure things like taborder works.

As for painting a background, look at wxEraseEvent.

HTH
/Jonas

micros
Super wx Problem Solver
Super wx Problem Solver
Posts: 317
Joined: Sat Mar 18, 2006 10:41 am
Location: Ustek, Bohemia

Post by micros » Tue May 30, 2006 6:02 pm

Anyone please correct me if I'm wrong, but I don't think there is a way one could make wxStaticBitmap honour alpha channel (at least not a portable one).
uketernity wrote:I have found a kind of solution that draws the text labels onto the background in the onPaint method and this works, however, I cant do the same thing for images as my programs needs to hide them.
Why not? You can have bitmap-position-visibility tuples and refresh parts of the window that need it when anything changes. Here's a simple class I would write to move this functionality out of the containing window:

Code: Select all

class PositionedBitmap
{
  public:
    PositionedBitmap(wxWindow* parent, const wxPoint& pos, wxBitmap bmp)
      : m_parent(parent), m_pos(pos), m_bmp(bmp), m_shown(false)
    { }

    wxPosition getPosition() const
    {
      return m_pos;
    }

    wxSize getSize() const
    {
      return wxSize(m_bmp.GetWidth(), m_bmp.GetHeight());
    }

    void show(bool show = true)
    {
      if (show != m_shown) {
        wxRect rc(m_pos, getSize());
        m_shown = show;
        m_parent->Refresh(true, &rc);
      }
    }

    bool isShown() const
    {
      return m_shown;
    }

    void drawOnto(wxDC& dc) const
    {
      dc.DrawBitmap(m_bmp, m_pos.x, m_pos.y, true);
    }

  private:
    wxWindow* m_parent;
    wxPoint m_pos;
    wxBitmap m_bmp;
    bool m_shown;
};
It's not even a control, but a mere envelope for all the required information. The containing window will just keep some instances and in it's onPaint draw each of them like:

Code: Select all

if (pb.isShown()) pb.drawOnto(dc);
Calling pb.show() in response to any other event will cause repainting of the damaged area.

amititz
Earned a small fee
Earned a small fee
Posts: 15
Joined: Tue Dec 20, 2005 7:06 am

Post by amititz » Tue May 30, 2006 11:27 pm

Hi,

I'm also having the same problem. What do you suggest I can do with controls such as radio buttons and text labels? I'm basically trying to lay them out using a structure of nested sizers and panels, but the background color of the frame keeps showing as the background of the text labels, radio buttons, etc., instead of the badkground IMAGE of the frame.

uketernity
Earned a small fee
Earned a small fee
Posts: 13
Joined: Sun May 21, 2006 9:36 am

Post by uketernity » Wed May 31, 2006 7:22 pm

Im with you on that one. I dont really understand how the class method works.

The wxStaticBitmaps do support an transparency, and this works fine, however, the transparent regions of the image do not show the image pained onto my frame, instead, they show the background colour. Its as if the background to the frame is being drawn after the controls are drawn, and as such, the controls adopt the frame bg colour before the background image is drawn on.

Refering to my previous example about the region the control/image takes up being grey for a split second when you use

Code: Select all

Image1->Show(false);
is shown in these 2 images:

Image shown:
Image

Image hidden:
Image

Please, someone help me :) thanks.

Oli

uketernity
Earned a small fee
Earned a small fee
Posts: 13
Joined: Sun May 21, 2006 9:36 am

Post by uketernity » Thu Jun 01, 2006 9:47 am

Hi micros,

I looked through your class and managed to work out what its doing, however, I need to know how to create my image in the first place, how do you do that?

Could you give me an example of how to do this?

Thanks.

Oli

micros
Super wx Problem Solver
Super wx Problem Solver
Posts: 317
Joined: Sat Mar 18, 2006 10:41 am
Location: Ustek, Bohemia

Post by micros » Thu Jun 01, 2006 11:15 am

uketernity wrote:I looked through your class and managed to work out what its doing, however, I need to know how to create my image in the first place, how do you do that?

Could you give me an example of how to do this?
You mean how to use the class I posted? Have to warn you it's just an untested suggestion :)

First, since you're going to need a lot of images, add a default constructor and an initializer method. If you didn't have these, everything would have to be set up in the initialization section of the frame's ctor, and (1) I think loading bitmaps is too complex to put in there, and (2) MSVC thinks that using this in initialization section is evil. ('f course you could allocate the PositionedBitmaps dynamically, but I always try to avoid too much news and deletes).

Code: Select all

class PositionedBitmap
{
  public:
    // a default constructor, initialize must be called before use!
    PositionedBitmap()
      : m_parent(NULL), m_pos(wxDefaultPosition), m_shown(false)
    { }

    void initialize(wxWindow* parent, const wxPoint& pos, wxBitmap bmp)
    {
      m_parent = parent;
      m_pos = pos;
      m_bmp = bmp;
    }

    // and leave the rest as it was; perhaps you could add some checking
    // as for (m_parent != NULL) and m_bmp.Ok() at the right places
    // ...
};
Now you'll have a bunch of these in your frame.

Code: Select all

class MyFrame : public wxFrame
{
  // ...

  PositionedBitmap m_imgVolume;
  PositionedBitmap m_imgSub;
  PositionedBitmap m_imgFader;
  PositionedBitmap m_imgCenter;
  // and so on

  std::vector<PositionedBitmap*> m_images; // will explain later
};

// in the frame's ctor, you'll initialize them
MyFrame::MyFrame(...)
{
  // ...
  m_imgVolume.initialize(this, wxPoint(30, 150), wxBitmap(wxT("volume.png"), wxBITMAP_TYPE_PNG));
  m_images.push_back(&m_imgVolume);
  m_imgSub.initialize(this, wxPoint(50, 150), wxBitmap(wxT("sub.png"), wxBITMAP_TYPE_PNG));
  m_images.push_back(&m_imgSub);
  // etc.
}
You will then want to draw some/all of them in MyFrame::OnPaint. This is why I created the m_images vector. It's not absolutely necessary -- without it, you would just draw m_imgVolume, then m_imgSub, and so on. But adding a new button would require changes to OnPaint(); with the vector, you only put one more line after initialize() in the ctor. Now we can draw them all in a loop. I don't know how your OnPaint() is implemented, guess it can't be far from this:

Code: Select all

void MyFrame::OnPaint(wxPaintEvent& event)
{
  wxBufferedPaintDC dc(this);

  // draw background and other stuff
  // ...

  // now draw the hideable images
  for (size_t i = 0; i < m_images.size(); ++i) {
    if (m_images[i]->isShown())
      m_images[i]->drawOnto(dc);
  }
}

uketernity
Earned a small fee
Earned a small fee
Posts: 13
Joined: Sun May 21, 2006 9:36 am

Post by uketernity » Thu Jun 01, 2006 3:39 pm

Hi micros,


Ive tried implementing your solution, while I understand what it does, I cant seem to get it to work. Would you be kind enough to drop it into some source files and send them to me at all?

Im a bit stuck.

Thanks.

Oli

Post Reply