Solved

Changing the bitmap for a CStatic object at runtime

Posted on 2000-03-15
20
445 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:knowlton
  • 8
  • 6
  • 2
  • +2
20 Comments
 
LVL 5

Expert Comment

by:Wyn
ID: 2622182
dont subclass
0
 
LVL 30

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
 
LVL 30

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: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: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 30

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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 5

Author Comment

by: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:knowlton
ID: 2623798
Adjusted points from 10 to 20
0
 
LVL 5

Author Comment

by: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 30

Expert Comment

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

have a nice day,

regards,

ZOPPO
0
 
LVL 5

Author Comment

by: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: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 30

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: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 30

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

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Often, when implementing a feature, you won't know how certain events should be handled at the point where they occur and you'd rather defer to the user of your function or class. For example, a XML parser will extract a tag from the source code, wh…
What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
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.

708 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

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now