TommyN14
asked on
LoadBitmaps doesn't load the bitmap.
Hi,
I have a dialog with a CBitmapButton on it. I set the CBitmapButton to Owner Draw mode. I have a function to Load the bitmap like this:
void MyTestDlg::DisplayBitmap(i nt iMode)
{
if (iMode == 1)
{
m_btn1.LoadBitmaps(IDC_BIT MAP1);
}
else if (iMode == 2)
{
m_btn1.LoadBitmaps(IDC_BIT MAP2);
}
}
OnInitDialog function, i called DisplayBitmap(1), that works fine. Now I have a thread that constantly call this function and update the button bitmap. like this:
myThread.h
extern MyTestDlg *myDlg;
UINT myThread(LPVOID pParam)
{
for (int i = 0; i < 100; i++)
{
if (i % 2 == 0)
{
myDlg->DisplayBitmap(1);
}
else
{
myDlg->DisplayBitmap(2);
}
::Sleep(1000);
}
}
the button doesn't change the bitmap at all. What am I missing here?
Thank you!
I have a dialog with a CBitmapButton on it. I set the CBitmapButton to Owner Draw mode. I have a function to Load the bitmap like this:
void MyTestDlg::DisplayBitmap(i
{
if (iMode == 1)
{
m_btn1.LoadBitmaps(IDC_BIT
}
else if (iMode == 2)
{
m_btn1.LoadBitmaps(IDC_BIT
}
}
OnInitDialog function, i called DisplayBitmap(1), that works fine. Now I have a thread that constantly call this function and update the button bitmap. like this:
myThread.h
extern MyTestDlg *myDlg;
UINT myThread(LPVOID pParam)
{
for (int i = 0; i < 100; i++)
{
if (i % 2 == 0)
{
myDlg->DisplayBitmap(1);
}
else
{
myDlg->DisplayBitmap(2);
}
::Sleep(1000);
}
}
the button doesn't change the bitmap at all. What am I missing here?
Thank you!
The simplest way would be to have two buttons - one for each bitmap. Then you can use code like m_btn1.ShowWindow(SW_HIDE) ; m_btn2.ShowWindow(SW_SHOW) ; to show/hide the desired bitmap. (A button click on either button could call the same function)
ASKER
Well, my application doesn't just have 1 button. I has 10 different buttons that can update statuses based on the value it received. And each button has 4 status (4 different colors). That will take up alot of resources.
I tried this:
void MyTestDlg::DisplayBitmap(i nt iMode)
{
if (iMode == 1)
{
m_btn1.LoadBitmaps(IDC_BIT MAP1_RED);
m_btn1.SetState(TRUE);
m_btn1.SetState(FALSE);
m_btn2.LoadBitmaps(IDC_BIT MAP2_RED);
m_btn2.SetState(TRUE);
m_btn2.SetState(FALSE);
.....
}
else if (iMode == 2)
{
m_btn1.LoadBitmaps(IDC_BIT MAP1_GRN);
m_btn1.SetState(TRUE);
m_btn1.SetState(FALSE);
m_btn2.LoadBitmaps(IDC_BIT MAP2_GRN);
m_btn2.SetState(TRUE);
m_btn2.SetState(FALSE);
}
}
This will show the bitmaps. But, everytime it call this function, it increasing the memory usage. So there's a memory leak here. I don't know how to free the memory. What's the best way of programming such an app like this? Please provide some sample if possible.
Thanks!
I tried this:
void MyTestDlg::DisplayBitmap(i
{
if (iMode == 1)
{
m_btn1.LoadBitmaps(IDC_BIT
m_btn1.SetState(TRUE);
m_btn1.SetState(FALSE);
m_btn2.LoadBitmaps(IDC_BIT
m_btn2.SetState(TRUE);
m_btn2.SetState(FALSE);
.....
}
else if (iMode == 2)
{
m_btn1.LoadBitmaps(IDC_BIT
m_btn1.SetState(TRUE);
m_btn1.SetState(FALSE);
m_btn2.LoadBitmaps(IDC_BIT
m_btn2.SetState(TRUE);
m_btn2.SetState(FALSE);
}
}
This will show the bitmaps. But, everytime it call this function, it increasing the memory usage. So there's a memory leak here. I don't know how to free the memory. What's the best way of programming such an app like this? Please provide some sample if possible.
Thanks!
Don't call any UI-related function directly from worker thread, this is not allowed in MFC. Instead of this, post user-defined message to the dialog and change bitmaps in message handler.
m_btn1.LoadBitmaps(IDC_BIT MAP1_RED);
m_btn1.SetState(TRUE);
m_btn1.SetState(FALSE);
m_btn1.Invalidate(); <<--------------------need ed to make the button update
ps. As Alex said passing CWnd pointers between threads is NOT safe. Some functions are thread specific. The correct way to do it is to pass the window handle (GetSafeHwnd() will get you a handle). Then use the ::PostMessage(hWnd, MY_MESSAGE, wParam, lParam). In the dialog respond to this message by running your function to modify the buttons.
m_btn1.SetState(TRUE);
m_btn1.SetState(FALSE);
m_btn1.Invalidate(); <<--------------------need
ps. As Alex said passing CWnd pointers between threads is NOT safe. Some functions are thread specific. The correct way to do it is to pass the window handle (GetSafeHwnd() will get you a handle). Then use the ::PostMessage(hWnd, MY_MESSAGE, wParam, lParam). In the dialog respond to this message by running your function to modify the buttons.
ASKER
I'm lost. Could you guys please post me some links to examples or some sample codes?
Thanks!
Thanks!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Andy,
Thanks for your quickly response.
I have a few questions:
1. In my CMyTestDlg.cpp, somewhere in OnInitDialog function, I called this
::AfxBeginThread(myThread, GetSafeHwnd(), THREAD_PRIORITY_LOWEST);
Is this how I should be starting the thread? Is that how you call the GetSafeHwnd()?
2. Do I define this #define MY_MESSAGE_DISPLAY_BITMAP (WM_APP+10) at the begin of the thread file or in my CMyTestDlg.cpp file?
3. Where is this variable come from? hWnd_myDlg
4. How do you create a Message Map entry?
I tried this and it crashed:
in CMyTestDlg.cpp file
#include "myThread.h"
BOOL CMyTestDlg::OnInitDialog()
{
....
::AfxBeginThread(myThread, GetSafeHwnd(), THREAD_PRIORITY_LOWEST);
}
void CMyTestDlg::DisplayBitmaps (WPARAM wParam, LPARAM lParam)
{
if (wParam == 1)
{
m_btn1.LoadBitmaps(IDC_BIT MAP_RED);
m_btn1.SetState(TRUE);
m_btn1.SetState(FALSE);
m_btn2.LoadBitmaps(IDC_BIT MAP_RED);
m_btn2.SetState(TRUE);
m_btn2.SetState(FALSE);
// .....
}
else if (wParam == 2)
{
m_btn1.LoadBitmaps(IDC_BIT MAP_GRN);
m_btn1.SetState(TRUE);
m_btn1.SetState(FALSE);
m_btn2.LoadBitmaps(IDC_BIT MAP2_GRN);
m_btn2.SetState(TRUE);
m_btn2.SetState(FALSE);
}
}
And in myThread.h file
#define MY_MESSAGE_DISPLAY_BITMAP (WM_APP+10)
//extern CMyTestDlg *myDlg;
UINT myThread(LPVOID pParam)
{
for (int i = 0; i < 100; i++)
{
if (i % 2 == 0)
{
//myDlg->DisplayIcons(1);
::PostMessage((HWND)pParam , MY_MESSAGE_DISPLAY_BITMAP, 1, 0);
}
else
{
//myDlg->DisplayBitmap(2);
::PostMessageA((HWND)pPara m, MY_MESSAGE_DISPLAY_BITMAP, 2, 0);
}
::Sleep(1000);
}
return 0;
}
Please help! Thank you!!!
Thanks for your quickly response.
I have a few questions:
1. In my CMyTestDlg.cpp, somewhere in OnInitDialog function, I called this
::AfxBeginThread(myThread,
Is this how I should be starting the thread? Is that how you call the GetSafeHwnd()?
2. Do I define this #define MY_MESSAGE_DISPLAY_BITMAP (WM_APP+10) at the begin of the thread file or in my CMyTestDlg.cpp file?
3. Where is this variable come from? hWnd_myDlg
4. How do you create a Message Map entry?
I tried this and it crashed:
in CMyTestDlg.cpp file
#include "myThread.h"
BOOL CMyTestDlg::OnInitDialog()
{
....
::AfxBeginThread(myThread,
}
void CMyTestDlg::DisplayBitmaps
{
if (wParam == 1)
{
m_btn1.LoadBitmaps(IDC_BIT
m_btn1.SetState(TRUE);
m_btn1.SetState(FALSE);
m_btn2.LoadBitmaps(IDC_BIT
m_btn2.SetState(TRUE);
m_btn2.SetState(FALSE);
// .....
}
else if (wParam == 2)
{
m_btn1.LoadBitmaps(IDC_BIT
m_btn1.SetState(TRUE);
m_btn1.SetState(FALSE);
m_btn2.LoadBitmaps(IDC_BIT
m_btn2.SetState(TRUE);
m_btn2.SetState(FALSE);
}
}
And in myThread.h file
#define MY_MESSAGE_DISPLAY_BITMAP (WM_APP+10)
//extern CMyTestDlg *myDlg;
UINT myThread(LPVOID pParam)
{
for (int i = 0; i < 100; i++)
{
if (i % 2 == 0)
{
//myDlg->DisplayIcons(1);
::PostMessage((HWND)pParam
}
else
{
//myDlg->DisplayBitmap(2);
::PostMessageA((HWND)pPara
}
::Sleep(1000);
}
return 0;
}
Please help! Thank you!!!
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks Alex!
Now I'm getting this popup error when executing this app.
Debug Assertion Failed!
Program: D:\MyTest\Debug\MyTest.exe
File: winbtn.cpp
Line: 107
For information on how...
Do you have any ideas?
Thanks!
Now I'm getting this popup error when executing this app.
Debug Assertion Failed!
Program: D:\MyTest\Debug\MyTest.exe
File: winbtn.cpp
Line: 107
For information on how...
Do you have any ideas?
Thanks!
Have you loaded the bitmaps into the buttons before attempting to draw them ?
(Call this DisplayBitmaps in the OnInitDialog and before the thread is started to load the bitmaps)
(Call this DisplayBitmaps in the OnInitDialog and before the thread is started to load the bitmaps)
ASKER
Sorry, i was out for a few days. I was able to get it to work. Thanks to Andy & Alex.
I'm experiencing problem with LoadBitmaps function. It seems like everytime i call this function to load a bitmap, memory usage will increase. Is there a way we can stop memory from increasing?
Thanks!
I'm experiencing problem with LoadBitmaps function. It seems like everytime i call this function to load a bitmap, memory usage will increase. Is there a way we can stop memory from increasing?
Thanks!
If you single step into the LoadBitmaps function you will find that it explicitly calls the DeleteObject on each of the four bitmaps (4 states available for a CBitmapButton) that are member variables - so you don't get any memory/resource leaks.
In other words what you are seeing is normal behaviour of windows.
<Is there a way we can stop memory from increasing? >
You could adopt my original suggestion of numbers of buttons ;-) and just show/hide the buttons.
You could create your own class based on CBitmapButton, load the different bitmaps at one go and swap the bitmaps internally to display the different ones when required.
Both of those would have a larger usage of memory initially but would stop the behaviour you are experiencing.
In other words what you are seeing is normal behaviour of windows.
<Is there a way we can stop memory from increasing? >
You could adopt my original suggestion of numbers of buttons ;-) and just show/hide the buttons.
You could create your own class based on CBitmapButton, load the different bitmaps at one go and swap the bitmaps internally to display the different ones when required.
Both of those would have a larger usage of memory initially but would stop the behaviour you are experiencing.
ASKER
Thanks, Andy!
Alex, are you GranMod by any chance or is there someone watching over our shoulders out there? (There is no question in your profile re the awarding here and you usually post a comment in the thread when not happy.)
Thanks for explaining.
ASKER
Thanks Andy & Alex!!!