 |
|
 |
Great buttons. Only issue I've found is sometimes I'd like the user to be able to hammer the button and get a quick response. Currently however, the foo button (being an Owner Draw button) swallows the double click, so you have to wait for the next single click to be able to respond. This is fixed thanks to Nishad S at http://www.codeproject.com/KB/buttons/ODBaseBtn.aspx?display=Print who gives the following advice...
// This is a tricky one. Buttons having the BS_OWNERDRAW style will not respond to double click as // normal buttons do. So the solution is as below. When the double click occurs, call the default // window procedure of the button with WM_LBUTTONDOWN instead of the actual WM_LBUTTONDBLCLK. void FooButton::OnLButtonDblClk (UINT nFlags, CPoint point) { UNREFERENCED_PARAMETER(nFlags); UNREFERENCED_PARAMETER(point); // Convert the double click to single click const MSG* pstMSG = GetCurrentMessage(); DefWindowProc( WM_LBUTTONDOWN, pstMSG->wParam, pstMSG->lParam ); }
Works a treat for me. Thanks Nishad.
|
|
|
|
 |
|
 |
Let me eat that message and spit out another one. I love it!
/ravi
|
|
|
|
 |
|
 |
Sorry, also meant to thank you Ravi for absolutely rock-solid and extremely versatile buttons that are proving extremely useful.
Many thanks, Phil.
|
|
|
|
 |
|
 |
Has anyone used FooButton with a Windows Common dialog? I am using bitmaps on my own dialogs, but would like the buttons on CFileDialog to have bitmaps as well. I thought it should be a simple matter of doing the following:
1) In the declaration for my derrived dialog class (class CLocalFileDlg : public CFileDialog), I have the following:
FooButton OpenButton, CancelButton;
2) In DoDataExchange() I have:
DDX_Control(pDX, IDOK, OpenButton); DDX_Control(pDX, IDCANCEL, CancelButton);
3) In OnInitDialog() I have:
OpenButton.setBitmapId( IDB_CHECK ); CancelButton.setBitmapId( IDB_EX );
The error I am getting appears to be a result of IDOK and IDCANCEL not being valid resource IDs in the dialog, even though Microsoft's documentation indicates they are. I tried using GetDlgItem() on both these IDs and both return NULL.
Anyone have an idea of what I am missing?
|
|
|
|
 |
|
 |
This control really is cool! by the way, I can't find the way why the GROUPBOX(IDC_STATIC) appears to be rounded. Is there any related codes?
|
|
|
|
 |
|
 |
Thanks!
librorum wrote: I can't find the way why the GROUPBOX(IDC_STATIC) appears to be rounded.
You need to add a manifest resource to the project in order to get the XP look and feel.
/ravi
|
|
|
|
 |
|
 |
I created some FooButton objects dynamically and set the type to hyperlink. The FooButton::drawCaption rountine failed as GetFont() returns NULL.
When I create a font and set the underline text, the control (inside of CListCtrl) is not clickable.
Any help is appreciated.
Thanks.
modified on Tuesday, December 2, 2008 1:54 PM
|
|
|
|
 |
|
 |
Sorry for the late reply! Did you associate the FooButton instance with a Windows button control?
/ravi
|
|
|
|
 |
|
 |
I have little problem about the gradient feature. If the button enable gradient and atteched bitmap. When the button change to disable, the bitmap will show the transparent area. So, I have add some code like below.
In the void FooButton::DisabledBlt() function
if(!m_bGradient) { FillRect (hdcDest, CRect (nXDest, nYDest, nXDest + nWidth, nYDest + nHeight), GetSysColorBrush (COLOR_3DFACE)); }
HBRUSH hb;
if(!m_bGradient) hb = CreateSolidBrush (GetSysColor (COLOR_3DHILIGHT)); else hb = CreateSolidBrush (RGB(200,200,200));
if(!m_bGradient) { BitBlt (hdcDest, nXDest, nYDest, nWidth, nHeight, bwDC, 0, 0, 0xB8074A); } The button will better then before when it's disable.
BTW, this class is really good. Thanks
Enjoy!
|
|
|
|
 |
|
|
 |
|
 |
Hi, Thanks for this great class! I enjoy to use it in my app.
I have found a little problem: The text is not updated correctly when it is changed. This happens when using the button with the style hyperlink or as hottrack and in combination with a menu. I change the text of the button according to the choice in the menu (comparable to a dropdown list). It works fine as long as I use the mouse to select the menu item. If I use the keyboard to open the menu and to select the item the button shows the old and the new text on top of each other. I could solve the problem by calling Invalidate() before setting the new text:
if( !cstrText.IsEmpty() ) { // necessary to delete old text when selecting menu entry by keyboard pBtn->Invalidate(); pBtn->SetWindowText( cstrText ); }
I think it would be better to modifiy the button text by a member function which cares for the necessary update.
|
|
|
|
 |
|
 |
Hi Klaus, thanks for your comments! I'll look into it asap.
/ravi
|
|
|
|
 |
|
 |
I saw in a previous post that someone else asked about XP Theme support and you agreed. Is this something to difficult to add or is this something you are looking into. Great control, it just looks funny in my application when XP Themes are used. This control sticks out.
Thanks so much, Tim.
|
|
|
|
 |
|
 |
Hi Tim, thanks for your post. I've been meaning to add support for themes but continue to buried under work.
Hopefully I'll have some free cycles before long and eventually be able to get to this. Thanks,
/ravi
|
|
|
|
 |
|
 |
I have put together an XP-themed demo using some code cannibalised from XPButtonST and modified by myself, plus some other stuff from CodeProject. I've tried it with about ten different themes and it seems to work nicely.
I can send you the modified code if you like.
- Pfft. Coddled kids. In my day, we used to telnet to port 80, then render the page with pencil and paper-- and that's the way we liked it!
- Pshaw! Youngster. Your UID barely fits inside 16 bits. In _my_ day we had to whistle the 1's and 0's through an acoustic coupler!
Tools that support "all of UTF-8 as long as it starts with ASCII" and tools that cannot handle these three [BOM] bytes at all are not really supporting UTF-8.
- Michael Kaplan
|
|
|
|
 |
|
 |
It looks like you need to add the line m_btnGroups.RemoveAll() to the end of FooButton::reset() as the CPtrArray is deleted by this code but it's entry is left in the list. Subsequent calls through FooButton::reset() cause the code to attempt to delete the previously deleted CPtrArray object causing an exception.
void FooButton::reset() { POSITION pos = m_btnGroups.GetStartPosition(); while (pos != NULL) { CString strGroupName; void* pGroup = NULL; m_btnGroups.GetNextAssoc (pos, strGroupName, pGroup); ASSERT (pGroup != NULL); delete (CPtrArray *) pGroup; }
// Added to prevent re-delete of CPtrArray object in pGroup on subsequent calls to reset() m_btnGroups.RemoveAll(); }
This is only a problem if you are using addToGroup() to add named groups for buttons (as I am).
Hope that helps.
"If you think life is easy you are probably not paying close enough attention."
|
|
|
|
 |
|
 |
Hi. I think that it's so great .. but, reset() function need to initialze code...
void FooButton::reset() { int nCnt = m_btnGroups.GetCount(); POSITION pos = m_btnGroups.GetStartPosition(); while (pos != NULL) { CString strGroupName; void* pGroup = NULL; m_btnGroups.GetNextAssoc (pos, strGroupName, pGroup); ASSERT (pGroup != NULL); delete (CPtrArray *) pGroup; } //070105, mania : Bug fix. m_btnGroups.RemoveAll(); }
if this code not add then occrrence error at second dialog show time.
|
|
|
|
 |
|
 |
Thanks for your post. I'm looking into the best way to resolve this issue and will post an update soon.
/ravi
|
|
|
|
 |
|
 |
Is it possible to use this in a dialog based app which doesn't use MFC? Would it be difficult for me to modify the code (and would that be allowed) to do this? Or would simply linking against the MFC dlls do the trick?
|
|
|
|
 |
|
 |
Neounk wrote: Is it possible to use this in a dialog based app which doesn't use MFC?
No, because FooButton derives from an MFC CButton.
Neounk wrote: would simply linking against the MFC dlls do the trick?
Well, you'd need to do that and more - i.e. rewrite your GUI using MFC.
Neounk wrote: Would it be difficult for me to modify the code
It's certainly possible to create a Win32 version of FooButton. But it may be less effort to modify your application to use MFC. You'd be the best judge of that.
Neounk wrote: (and would that be allowed)
Certainly! If you do create a Win32 version of FooButton, I'd request that you post an article at CP if your company won't object.
/ravi
|
|
|
|
 |
|
 |
Thanks for your reply!
I don't really like using MFC because of all the "junk" code it generates when you make an app. I don't know where to put my code (it makes like 4 .cpp files). and the fact that you either need a MFC dll as a dependancy or you need to increase the size of your app by 100kb (for a small project I don't really like that). And you can get all the same functionality using a dialog (and I prefer the way you handle messages with a normal dialog).
I'll take a look into either converting it or rewriting my project. If I do convert it I'll certainly post it here.
|
|
|
|
 |
|
 |
I have create a FooButton::Type::checkButton with a bitmap. When pressed i have a green-bitmap, when i released have a red-bitmap. If i pressed quickly sometimes the bitmap is wrong. I must create a flag antibounce on the OnLButtonDown and OnLButtonUp; this is the code
void FooButton::OnLButtonDown (UINT nFlags, CPoint point) { multiHitTest (point); // sets m_bMultiClicked CButton::OnLButtonDown (nFlags, point); m_bBounce = TRUE; }
void FooButton::OnLButtonUp (UINT nFlags, CPoint point) { if (m_bBounce) { m_bBounce = FALSE;
// If this is a checkbutton... if ((m_type == FooButton::Type::checkButton) || (m_type == FooButton::Type::hotCheckButton) || (m_type == FooButton::Type::checkBox) || (m_type == FooButton::Type::radio)) {
// Check ourself if mouse was released over button CRect rectButton; GetClientRect (&rectButton); if (rectButton.PtInRect (point)) { if ((m_type != FooButton::Type::radio) && m_strButtonGroup.IsEmpty()) check (!isChecked()); else check (true); } } }
// Standard handling CButton::OnLButtonUp (nFlags, point); HWND hWnd = GetSafeHwnd(); if ((hWnd != NULL) && ::IsWindow (hWnd)) { m_bMultiClicked = false; Invalidate(); } }
Correct ?
Sorry for my english.
CIAO
|
|
|
|
 |
|
 |
We have come across a bug in the OnLButtonUp() handler. The scenario is as follows: the FooButton is used to close a dialog; the dialog deletes itself in its PostNcDestory() handler; after that the FooButton::OnLButtonUp() handler continues. But the button does not exist, and even the FooButton instance has been freed. The Visual Studio (debug) displays a heap corruption dialog:
HEAP[abc.exe]: HEAP: Free Heap block 373e160 modified at 373e378 after it was freed Windows has triggered a breakpoint in abc.exe.
The fix we used was to check the instance before the member m_bMultiChecked is accessed:void FooButton::OnLButtonUp (UINT nFlags, CPoint point) { if ((m_type == FooButton::Type::checkButton) || (m_type == FooButton::Type::hotCheckButton) || (m_type == FooButton::Type::checkBox) || (m_type == FooButton::Type::radio)) {
CRect rectButton; GetClientRect (&rectButton); if (rectButton.PtInRect (point)) if ((m_type != FooButton::Type::radio) && m_strButtonGroup.IsEmpty()) check (!isChecked()); else
check (true); }
CButton::OnLButtonUp (nFlags, point); m_bMultiClicked = false;
HWND hWnd = GetSafeHwnd(); if ((hWnd != NULL) && ::IsWindow (hWnd)) { m_bMultiClicked = false;
Invalidate();
}
}
Sincerely,
Alex Cohn
-- modified at 9:42 Thursday 7th December, 2006
|
|
|
|
 |
|
 |
Many thanks, Alex! I'll update the article soon.
/ravi
|
|
|
|
 |
|
 |
I'm using visual studio 2005..
I'm got warning C4482 with "nonstandard extension used: enum 'FooButton::Type' used in qualified name" when i'm copmpile this file("FooButton.cpp" & "FooButton.h")
this warning is ok?
help me plz~
|
|
|
|
 |