Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Changing the bitmap for a CStatic object at runtime

Posted on 2000-03-15
20
Medium Priority
?
514 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
  • 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
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!

 
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 80 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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
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.

972 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