|
The version in this class is oooold. I'd highly recommend using the latest version from Keith
cheers,
Chris Maunder
CodeProject.com : C++ MVP
|
|
|
|
|
Wonderful class - thanks guys. Only one little fault.
The SetMarquee function only works properly to turn marquee mode ON - doesn't turn if off completely.
I changed OnSetMarquee() to be as follows:
if ((BOOL)bShow)<br />
ModifyStyle(0, PBS_MARQUEE);<br />
else<br />
ModifyStyle(PBS_MARQUEE, 0);<br />
<br />
m_bShowPercent = !(BOOL)bShow;<br />
Change is not made without inconvenience, even from worse to better.
Samuel Johnson
|
|
|
|
|
Hi,
First let me tell you thanks - this is a really nice class. Very useful and easy to use. I just wanted to share a couple of comments that may help clarify what I found and also help anyone who may encounter the same.
I got this to work fine on VC++ 2005, after making a change in the TextProgressCtrl.cpp file. There is a section starting at line 235 as below:
// draw text if needed
CString str;
GetWindowText(str);
if (m_bShowPercent)
str.AppendFormat("%d%%", (int)((dFraction * 100.0) + 0.5));
I dont understand the AppendFormat method, I could not find such call for CString class, so I changed the line to the following:
str.Format(L"%d%%", (int)((dFraction * 100.0) + 0.5));
//removed the Append word and added a L to "%d%d"
It worked wonderfully under VS2005
Additionally, if anyone will be customizing this further, it would be nice to have a method to allow a bouncing progress bar, sort of modified marquee style so it bounces back.
Any helpful comments will be appreciated - otherwise thanks for sharing this with everyone.
dev75040 - Victor
dev75040@yahoo.com
|
|
|
|
|
I believe the problem you had in VS2005 was that you were compiling for Unicode. There was a bug in the program in the AppendFormat line. There is an _T() macro missing around the format string. The line should read:
str.AppendFormat(_T("%d%%"), (int)((dFraction * 100.0) + 0.5));
If yo change the AppendFormat to a plain Format, the fixed text option won't work anymore.
AppendFormat is a method of the CStringT class.
|
|
|
|
|
The demo project is still showing the old / previous version of the Progress Control with Text. Can you update it to the new version?
Thanks, André
|
|
|
|
|
All fixed - sorry about that
cheers,
Chris Maunder
CodeProject.com : C++ MVP
|
|
|
|
|
Thanks,
There is still one problem with the demo-project. They didn't load in my VS.NET2003 environment. I solved it by picking up the '.VSNET2002'- file, change it to '.sln'. Then editing this one and the project-file directly and change '8.00' to '7.10'.
It's now working!
thanks again,
André
|
|
|
|
|
would it have been possible to use ExtTextOut to render the text, just changing the lpRect param to control the clipping (+ ETO_CLIPPED of course)?
this is not a criticism, its just that i've not tried it before and wondered if anyone else had.
.dan.g.
AbstractSpoon Software
abstractspoon2_at_optusnet_dot_com_dot_au
|
|
|
|
|
Probably! I've not tried it either.
Anyone got some spare time to play?
cheers,
Chris Maunder
CodeProject.com : C++ MVP
|
|
|
|
|
ExtTextOut will work to render the text. That is how the newly posted version got the vertical text display to work. The original code used DrawText and that function doesn't support text output with an escapement and orientation different than zero degrees.
TonyB
|
|
|
|
|
It's simple and useful, thanks chris smart work.
liansp
|
|
|
|
|
Hi Chirs,
Any chance you can update this to use XP themes?
|
|
|
|
|
Hello all,
What a pity nobody answered this question because it would have saved me some work. Never mind, I worked out how to do the Theme support myself and will share it with you. Five easy steps:
1) Study the classes CXPStyleButtonST and CButtonST very carefully. What you will find is that the OnPaint() function in ButtonST calls a virtual function OnDrawBackground() that does the actual drawing. In CXPStyleButtonST this function is overwritten to do the themed drawing. The themed drawing uses a helper class called CThemeHelperST that tabs into the windows theme DLL.
2) In order to support a themed progress bar we will create a new class, CXPStyleProgress that derives from CTextProgressCtrl.
3) In CTextProgressCtrl, split up the OnPaint() so that the actual owner-draw painting is done in
virtual void DrawProgressBar(CDC* pDC, CRect* pRect, double dFraction);
4) Add Theme support to CXPStyleProgress. The header file will include:
#include "TextProgressCtrl.h"<br />
#include "ThemeHelperST.h"
Also add a theme helper pointer to the class:
private:<br />
CThemeHelperST* m_pTheme;<br />
public:<br />
void SetThemeHelper(CThemeHelperST* pTheme);
In SetThemeHelper you set the theme pointer:
m_pTheme = pTheme;
5) Now add the overloaded function to CXPStyleProgress:
virtual void DrawProgressBar(CDC* pDC, CRect* pRect, double dFraction);
The complete function body:
void CXPStyleTextProgress::DrawProgressBar(CDC* pDC, CRect* pRect, double dFraction)<br />
{<br />
BOOL bDefaultDraw = FALSE;<br />
<br />
if (m_pTheme == NULL || m_pTheme->IsAppThemed() == FALSE)<br />
{<br />
bDefaultDraw = TRUE;<br />
}
else<br />
{<br />
HTHEME hTheme = NULL;<br />
int iStateId = 0;<br />
<br />
hTheme = m_pTheme->OpenThemeData(GetSafeHwnd(), L"PROGRESS");<br />
if (hTheme)<br />
{<br />
CRect LeftRect, RightRect, ClientRect;<br />
ClientRect = *pRect;<br />
ClientRect.DeflateRect( 4 , 3 );
LeftRect = RightRect = ClientRect;<br />
<br />
#ifdef PBS_VERTICAL<br />
DWORD dwStyle = GetStyle();<br />
if (dwStyle & PBS_VERTICAL)<br />
{<br />
LeftRect.top = LeftRect.bottom - (int)((LeftRect.bottom - LeftRect.top) * dFraction);<br />
RightRect.bottom = LeftRect.top;<br />
m_pTheme->DrawThemeBackground(hTheme, m_hWnd, pDC->GetSafeHdc(), PP_BARVERT, iStateId, pRect, NULL);<br />
m_pTheme->DrawThemeBackground(hTheme, m_hWnd, pDC->GetSafeHdc(), PP_CHUNKVERT, iStateId, &LeftRect, NULL);<br />
}<br />
else<br />
#endif<br />
{<br />
LeftRect.right = LeftRect.left + (int)((LeftRect.right - LeftRect.left)* dFraction);<br />
RightRect.left = LeftRect.right;<br />
m_pTheme->DrawThemeBackground(hTheme, m_hWnd, pDC->GetSafeHdc(), PP_BAR, iStateId, pRect, NULL);<br />
m_pTheme->DrawThemeBackground(hTheme, m_hWnd, pDC->GetSafeHdc(), PP_CHUNK, iStateId, &LeftRect, NULL);<br />
}<br />
int iTextLength = m_strText.GetLength();<br />
if (iTextLength > 0)<br />
{<br />
TCHAR *pszText = new TCHAR[iTextLength+1];<br />
_tcscpy(pszText, m_strText);<br />
int widelen = MultiByteToWideChar(CP_ACP, 0, pszText, iTextLength+1, NULL, 0);<br />
WCHAR *pszWideText = new WCHAR[widelen+1];<br />
MultiByteToWideChar(CP_ACP, 0, pszText, iTextLength, pszWideText, widelen);<br />
<br />
<br />
SetBkMode(pDC->GetSafeHdc(), TRANSPARENT);<br />
m_pTheme->DrawThemeText(hTheme,<br />
pDC->GetSafeHdc(),<br />
PP_BAR,<br />
0,<br />
pszWideText,<br />
iTextLength,<br />
DT_CENTER | DT_VCENTER | DT_SINGLELINE,<br />
NULL,<br />
ClientRect);<br />
}<br />
<br />
m_pTheme->CloseThemeData(hTheme);<br />
<br />
<br />
}
else<br />
{<br />
bDefaultDraw = TRUE;<br />
}
}
<br />
if (bDefaultDraw)<br />
{<br />
return CTextProgressCtrl::DrawProgressBar(pDC, pRect, dFraction);<br />
}
}<br />
Some remarks:
This themed drawing only supports horizontal text drawing. I do not need vertical text drawing myself so I'll leave it as an excercise for someone else.
I use themed text drawing with something like DrawThemeText(). Alternatively you can use pDC->DrawText() but I think that it is better not to 'mix and match' themed drawing and DC drawing. I tried it and was unhappy with the results: sometimes the text did not redraw properly after 'wiping over' the progress control with another dialog.
Hope this helps.
Hidde Wallaart
software engineer
|
|
|
|
|
I'm also adding XP styles support to this, I've noticed some bugs in your code.
Char conversion is too complicated and does not free allocated memory.
I've used ATL's conversion:
<br />
USES_CONVERSION;<br />
WCHAR *pszWideText = T2W(str);<br />
Your should use something like this to find proper border size of the progress:
<br />
GetThemeBackgroundContentRect(dc,PP_BAR,0,ClientRect,chunkRect);<br />
The problem with text is that it's not comfortable to see above XP style chunk
rrrado
|
|
|
|
|
Hi, Chris
Is very Good, this Control.
I have detect one problem, when I call function
SetRange32(0, 0)
The CPU is 100%.
If I comment:
void CTextProgressCtrl::OnPaint()
{
//if (m_nMin >= m_nMax)
// return;
...
}
Not occur ???.
|
|
|
|
|
The OnPaint() handler should have the CPaintDC moved to be the first line
of the routine, ie, from this
void CTextProgressCtrl::OnPaint()<br />
{<br />
if (m_nMin >= m_nMax)<br />
return;<br />
<br />
CPaintDC PaintDC(this);
....
to this
void CTextProgressCtrl::OnPaint()<br />
{<br />
CPaintDC PaintDC(this);
<br />
if (m_nMin >= m_nMax)<br />
return;<br />
....
In the code as presented, if you do happen to set the min and max values the
same the CPaintDC is never created, which means that the Win32 API
BeginPaint()/EndPaint() pair is never called, which means that an infinite
number of WM_PAINT messages are sent to the progress control. Result is upto
100% CPU usage and the application stalls
You should keep the test against m_nMin and m_nMax in place (don't just comment it out) otherwise you risk a divide-by-zero error.
|
|
|
|
|
Hi,
I cant get the example project to compile under VC7 (.net), also i have no idea as to what the problem is as im to inexperienced to understand!
The compiler throws these errors:
c:\Documents and Settings\Joe\Desktop\text_progressctrl_demo\TextProgressCtrl.cpp(157): error C2440: 'static_cast' : cannot convert from 'LRESULT (__thiscall CTextProgressCtrl::* )(UINT,LPCTSTR)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
c:\Documents and Settings\Joe\Desktop\text_progressctrl_demo\TextProgressCtrl.cpp(158): error C2440: 'static_cast' : cannot convert from 'LRESULT (__thiscall CTextProgressCtrl::* )(UINT,LPTSTR)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
c:\Documents and Settings\Joe\Desktop\text_progressctrl_demo\TextProgressCtrl.cpp(165): error C2440: 'static_cast' : cannot convert from 'void (__thiscall CTextProgressCtrl::* )(WPARAM,LPARAM)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
c:\Documents and Settings\Joe\Desktop\text_progressctrl_demo\TextProgressCtrl.cpp(166): error C2440: 'static_cast' : cannot convert from 'void (__thiscall CTextProgressCtrl::* )(WPARAM,LPARAM)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
c:\Documents and Settings\Joe\Desktop\text_progressctrl_demo\TextProgressCtrl.cpp(170): error C2440: 'static_cast' : cannot convert from 'void (__thiscall CTextProgressCtrl::* )(WPARAM,LPARAM)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
Any ideas?
Joe
#
|
|
|
|
|
Hi Joe,
I had the same problem and expected some update for VC7 on this forum. What your VC7 compiler is complaining about is that you windows message handler functions return the wrong type of parameter, or the arguments are wrong. What it says is that it wants functions to look like:
LRESULT CTextProgressCtrl::OnSomeWindowsMessage(WPARAM wParam, LPARAM lParam)
{
LRESULT lResult;
....
return lResult;
}
So why does something that used to compile before in VC6 not work with VC7? I think this is because Microsoft 'streamlined' the format of the windows messages and now wants you to write stronger-typed code. The old compiler was more forgiving: you could have your own message handler with parameters like:
LRESULT CTextProgressCtrl::OnSomeWindowsMessage(UINT,LPCTSTR) {..}
and VC6 would do the conversion for you. From a user point of view this was good because you had the parameters in the format you wanted them. And it worked most of the time but could give unexpected errors in the release build that couldn't be traced in the debugger.
The windows messages that are not correctly handled are:
WM_SETTEXT, WM_GETTEXT, PBM_SETSHOWTEXT, PBM_SETRANGE, PBM_SETRANGE32. Look in the Help for these messages to understand what the wParam and lParam are. The message handlers need to be re-written. I did it myself.
In the header file TextProgressCtrl.h you have to change:
afx_msg LRESULT OnSetText(WPARAM, LPARAM);
afx_msg LRESULT OnGetText(WPARAM, LPARAM);
afx_msg LRESULT OnSetRange(WPARAM, LPARAM range);
afx_msg LRESULT OnSetRange32(WPARAM lower, LPARAM higher);
afx_msg LRESULT OnSetShowText(WPARAM bShow, LPARAM);
In the CPP file you have to change:
// This function handles the SetWindowText message
LRESULT CTextProgressCtrl::OnSetText(WPARAM wParam, LPARAM szText)
{
LRESULT result = Default();
UINT iTChar = wParam;
LPCTSTR szTmp = (LPCTSTR)szText;
m_strText = (CString)szTmp;
Invalidate();
return result;
}
// This function is supposed to handle the GetWindowText message.
// Note: it doesn't work, but I don't use it. Sorry.
LRESULT CTextProgressCtrl::OnGetText(WPARAM cchTextMax, LPARAM szText)
{
cchTextMax = m_strText.GetLength();
LPCTSTR szTmp = m_strText;
szText = (LPARAM)szTmp;
return min(cchTextMax, (UINT) m_strText.GetLength());
}
// display text or not
LRESULT CTextProgressCtrl::OnSetShowText(WPARAM bShow, LPARAM)
{
LRESULT result = Default();
SetShowText((BOOL)bShow);
return result;
}
LRESULT CTextProgressCtrl::OnSetRange(WPARAM, LPARAM range)
{
LRESULT result = Default();
OnSetRange32(LOWORD(range), HIWORD(range));
return result;
}
LRESULT CTextProgressCtrl::OnSetRange32(WPARAM Lower, LPARAM Upper)
{
LRESULT result = Default();
m_nMax = (int)Upper;
m_nMin = (int)Lower;
return result;
}
When I tested the functions I discovered that OnGetText(..) doesn't work, i.e. when I called it using a call like:
LPTSTR tmp = _T("");
int count = 0;
int iReturn = m_cMyProgress.GetWindowText(tmp, count);
It returned an empty string. I look forward to a solution for this, but at the moment I don't use this function. Maybe Cris Maunder is going to upgrade CTextProgressCtrl in the future.
Hope this helps, Hidde
Hidde Wallaart
software engineer
www.leo-em.co.uk
|
|
|
|
|
|
could you share me the solution if you find.
my mail address tyildirg2000@gmail.com
regards
|
|
|
|
|
Nice Progress Control Chris
Regards,
Brian Dela
|
|
|
|
|
Easy to implement!
|
|
|
|
|
Dear Chris,
I would like to change the font in the progress bar. I use the CWnd::SetFont(.,.) function but it's not changing the font. The parent font of the dialog box is used...
Best regard from Switzerland
|
|
|
|
|
On 25 Mar '03 Patrick N wrote:
I would like to change the font in the progress bar. I use the CWnd::SetFont(.,.) function but it's not changing the font. The parent font of the dialog box is used...
Don't know if you already figured it out, but the solution is pretty straight forward:
In TextProgressCtrl.h add a protected member variable CFont m_Font . Then declare two message handler functions:
afx_msg void OnSetFont (WPARAM hFont, LPARAM bRedraw);<br />
afx_msg LRESULT OnGetFont (WPARAM, LPARAM);
In TextProgressCtrl.cpp add the following:
void CTextProgressCtrl::OnSetFont(WPARAM hFont, LPARAM bRedraw)
{
m_Font.Detach();
if (hFont)
m_Font.Attach((HFONT)hFont);
if (bRedraw)
RedrawWindow();
}
LRESULT CTextProgressCtrl::OnGetFont(WPARAM, LPARAM)
{
return ((LRESULT)m_Font.m_hObject);
} And in the message map add the following lines
ON_MESSAGE(WM_SETFONT, OnSetFont)
ON_MESSAGE(WM_GETFONT, OnGetFont) And in the CTextProgressCtrl::OnPaint() function, change the line dc.SelectObject(GetParent()->GetFont()); to dc.SelectObject(&m_Font);
Now the control will handle the WM_SETFONT and WM_GETFONT messages which are sent by the CWnd::SetFont() and CWnd::GetFont() functions.
Sonork 100.11743 Chicken Little
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
Within you lies the power for good - Use it!
|
|
|
|
|
Thanks Chris and Pete for this extremely simple but useful class. "It worked straight from the box" - as most customers who buy online review their recent buys . Your CTextProgressCtrl class just adds to CProgressCtrl what I perceived to be missing, but without getting overly fancy.
I read that MFC supports the ComCtl32.dll but I wonder what type of support there is for the newer MsComCtl? I suppose you just have to add the MsComCtl.ocx to your project and drag the new slider control on your form. Any experience with these new controls?
Hidde Wallaart
software engineer
www.leo-em.co.uk
|
|
|
|
|