Solved

Changing the bitmap for a CStatic object at runtime

Posted on 2000-03-15
20
494 Views
Last Modified: 2008-02-20
I have this "picure" control (CStatic) which I want to have one of two bitmaps (a lightswitch depicting "on" or "off").

At runtime I want to click on the picture and have the bitmap switch from "on" to "off".

I set up the OnClick event for the CStatic object and this is the code I am using to switch the bitmap:

Don't ask me why I am subclassing the dialog item.  I don't even know if this is necessary.  I have been going through several books trying to gather bits and pieces of how this works.

What happens right now is when I click on the CStatic object the bitmap disappears completely.

Anyway, here is the code for my OnClick event:

void CRoom04Dlg::OnStaticBit7()
{
      HINSTANCE appinstance = AfxGetInstanceHandle();
      CStatic m_static;
      m_static.SubclassDlgItem(IDC_STATIC_BIT7,this);
      m_static.SetBitmap(HBITMAP (LoadBitmap(appinstance,MAKEINTRESOURCE(IDB_BITMAP_ON))));            
}
0
Comment
Question by:Tom Knowlton
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 6
  • 2
  • +2
20 Comments
 
LVL 5

Expert Comment

by:Wyn
ID: 2622182
dont subclass
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 2622723
Since this is not a derived class (so there isn't some extra PreSubclassWindow implemented) I agree with Wyn:

use GetDlgItem() to get a pointer to the static control like this:

void CRoom04Dlg::OnStaticBit7()
{
 HINSTANCE appinstance = AfxGetInstanceHandle();
 CStatic pStatic;
 pStatic = (CStatic*)GetDlgItem(IDC_STATIC_BIT7);
 pStatic->SetBitmap(HBITMAP (LoadBitmap(appinstance,MAKEINTRESOURCE(IDB_BITMAP_ON))));
}


ZOPPO
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 2622960
What's about standard window's message STM_SETIMAGE?
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 31

Expert Comment

by:Zoppo
ID: 2623009
Hi MichaelS: since knowIton uses MFC I think it's a good idea to stay in MFC ... SetBitmap just calls ::SendMessage( m_hWnd, STM_SETIMAGE, ... )
0
 
LVL 1

Expert Comment

by:Amor_
ID: 2623231
I can advise u to use a CBitmapButton Class. You can load in constructor till 4 images, and one of them is if button focused.
You should define a CBitmapButton  (but).
In constructor but.LoadBitmaps and in
OnInitDialog :
VERIFY(but.SubclassDlgItem(IDOK,this));
but.SizeToContent();

Hope this will work.
 
0
 
LVL 6

Expert Comment

by:MichaelS
ID: 2623260
2 Zoppo, 100% agree.
0
 
LVL 5

Expert Comment

by:Wyn
ID: 2623417
->since knowIton uses MFC I think it's a good idea to stay in MFC ... SetBitmap just calls ::SendMessage( m_hWnd, STM_SETIMAGE, ... )
===============================
1000% :)
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2623710
Zoppo:  Your code didn't work.

Amor_:  I do not understand your idea or why it will be useful.  Can you take my function and rewrite it to demonstrate what you are talking about?

Tom
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2623719
Zoppo:

In regards to your posted code:

HINSTANCE appinstance = AfxGetInstanceHandle();
 CStatic pStatic;

//Here, GetDlgItem is a member function of pStatic.  You don't need to cast it.
 pStatic = (CStatic*)GetDlgItem(IDC_STATIC_BIT7);



//Here, pStatic was not declared as a pointer, so you don't need to use -> to access member function SetBitmap.
 pStatic->SetBitmap(HBITMAP (LoadBitmap(appinstance,MAKEINTRESOURCE(IDB_BITMAP_ON))));
0
 
LVL 31

Accepted Solution

by:
Zoppo earned 20 total points
ID: 2623748
sorry, forgot the * before the pStatic:

void CRoom04Dlg::OnStaticBit7()
{
 HINSTANCE appinstance = AfxGetInstanceHandle();
 CStatic *pStatic;
 pStatic = (CStatic*)GetDlgItem(IDC_STATIC_BIT7);
 Static->SetBitmap(HBITMAP (LoadBitmap(appinstance,MAKEINTRESOURCE(IDB_BITMAP_ON))));
}

ZOPPO
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2623792
Zoppo:

It worked...but WHY did it work?  Can you explain what difference declaring pStatic as a pointer makes?

Please explain your rational for each line of your function.  I want to learn why this code works, not just blindly use it.

The points are yours!

I will reject Amor_'s answer (sorry Amor_).  Zoppo, please repost your *corrected* code as an answer.

Thanks,

Tom
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2623798
Adjusted points from 10 to 20
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2623799
Nevermind about reposting.  I forgot about "Accept comment as answer".

Thanks again.

Tom
0
 
LVL 1

Expert Comment

by:Amor_
ID: 2623806
knowlton:
 Add Button to your dialog in size of your bitmap( by using Class Wizard or other way). In your Dialog Class add
variable CBitmapButton but.
In Dialog Constructor write next code:
but.LoadBitmaps(1,2,3,4) where num are
id of the bitmaps.
first bitmap is picture "off"
third bitmap is picture "on"
second bitmap is when button is down.
If you dont want use button,simple disable it.
In InitDialog add next:
VERIFY(but.SubclassDlgItem(ID_Button, this));
but.SizeToContent();
 
 
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 2623808
you're welcome          :)

have a nice day,

regards,

ZOPPO
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2624098
Zoppo:

So you're not going to explain the code to me?  :(

Well, thanks anyway.

Tom
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2624108
Amor_:

Your answer probably works fine, but it is more complex than it needs to be for what I am doing.

Thanks!

Tom
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 2626994
Hi knowIton,

here's a brief explanation:

void CRoom04Dlg::OnStaticBit7()
{
 HINSTANCE appinstance = AfxGetInstanceHandle();
 CStatic *pStatic;
 pStatic = (CStatic*)GetDlgItem(IDC_STATIC_BIT7);
 Static->SetBitmap(HBITMAP (LoadBitmap(appinstance,MAKEINTRESOURCE(IDB_BITMAP_ON))));
}

GetDlgItem() returns a a pointer to a (temporary) CWnd object which represantates the control with given ID. We then cast this CWnd pointer to CStatic to make it possible to call a CStatic member function for this control.
--------------------------------------------------------------------------------------------
CAUTION: This pStatic pointer is not really a pointer to a CStatic object but a pointer to a generic CWnd object. Calling a member function of the CStatic pointer only works here because the function itself does simply send a message to the window (so no function call or member access of in the CStatic class occurs). You cannot use this method if you want i.e. call a function which directly accesses some data or function of the CStatic (or any other derived class), i.e. if you implement your own CStatic derived class with i.e. a virtual function which uses any member you've implemented, a call against an object returned by GetDlgItem() will crash. For such a case you'll have to subclass the control.
--------------------------------------------------------------------------------------------
The SetBitmap() then just sends the control the STM_SETIMAGE message which then is handled by the static control's window procedure.

further question?

ZOPPO
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 2628519
So WHY doesn't a normal CStatic variable work here?  That still is not quite clear.

If you took the same code above but used a normal CStatic variable, what would be the difference?  I mean, other than the fact it wouldn't work properly?

Thanks.
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 2635178
The problem with your code was simply that subclassing a window to a CWnd-derived object 'attaches' this window to the CWnd object in the same manner as CWnd::Attach() does. Then, the destructor of the CWnd-derived object causes the window to be destroyed (take a look at the CWnd-destructor at file wincore.cpp, about line 745). You could also have your problem solved by calling CWnd::UnsubclassWindow() or by using Attach()/Detach() instead of subclassing the control, but each of these solutions implicies overhead which is not needed, i.e. you never need to create a CWnd-derived object on the stack and call its constructor.

Here's the same code using Attach()/Detach() as example:

void CRoom04Dlg::OnStaticBit7()
{
 HINSTANCE appinstance = AfxGetInstanceHandle();
 CStatic m_static;
 m_static.Attach(GetDlgItem(IDC_STATIC_BIT7));
 m_static.SetBitmap(HBITMAP(LoadBitmap(appinstance,MAKEINTRESOURCE(IDB_BITMAP_ON))));
 m_static.Detach(); // have to do this to avoid the CStatic's dtor destroyes the control
}

ZOPPO
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

630 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question