|
Hi,
Your work offers a great help in my project. Thank you very much.
However, i faced a problem: mislocation of the button when my project is run and tested on other PC.
Scenario:
i created a button in the OnInitialUpdate() and place it on a FormView.
RECT stRect;
stRect.left = 0+454;
stRect.top = 0+197;
stRect.right = 454+74;
stRect.bottom = 197+23;
CRect rect1(stRect);
m_btn.Create("&Settings", WS_TABSTOP | WS_CHILD |WS_VISIBLE, rect1 ,this,IDC_SETTING);
Problem:
When this program is run on other PC, the button is no longer at the place i desired. It jumps to other location! why?
I've tested on windows resolution, but doesn't solve the prolem.
Please advice. Thank you!
|
|
|
|
|
This control was almost exactly what I needed for an application I'm working on. However, I've made a couple of minor additions to the code:
1) By default, the left side of the menu is aligned with the left side of the button. Since this looks a little strange in cases where the button is wider than the menu, I've added a method to specify whether the menu should be right- or left-aligned.
2) Added a method to set a callback function to dynamically create the menu, if desired. (I notice this has already been done by others, but isn't included in the source code from this site)
3) Added a method to set a callback function for handling menu selections, rather than using window messages.
I felt that these changes increased the flexibility of what is already an excellent control . The mods are easy enough to make, but if you want the source just drop me an email.
Cheers,
Dion Campbell
|
|
|
|
|
I've made a few small additions to the code:
- Using OBM_COMBO bitmap arrow
- Enabled use of popup menu resource
- Popup menu using keyboard (VK_DOWN)
The modified project is here: http://www.code.trak.dk
|
|
|
|
|
|
In AddImage the line
ASSERT( m_menu.SetMenuItemBitmaps( nIndex, MF_BYPOSITION, &bmpEnabled, &bmpDisabled ) );
should be
VERIFY( m_menu.SetMenuItemBitmaps( nIndex, MF_BYPOSITION, &bmpEnabled, &bmpDisabled ) );
Best wishes,
Hans
|
|
|
|
|
I have also added two new features to this class: a callback function, which allows you to load the menu at the time the menu is being dropped (for example, for a Back button); and the ability to load the menu from a resource id.
Please let me know if you want me to email the source to you - the CP email form does not allow attachments.
Best wishes,
Hans
hdietrich2@hotmail.com
|
|
|
|
|
Hans
Feel free to email the source I will include and update the article occordingly
|
|
|
|
|
What is your email address? I cannot email via CodeProject - the email form does not allow attachments.
|
|
|
|
|
well, this article should be well descriptive for the beginners. try improving it!!
Muhammad Shoaib Khan
http://geocities.com/lansolution
|
|
|
|
|
Eat my shorts...
|
|
|
|
|
Well, I have looked very much around to find a menu button implementation. This one has following weak points:
- Not visually definable
- Not very well isolated
- Not reusable across applications
Derek Lakin seems to spend much more time on this subject.
See: http://www.salamandersoftware.biz/products/cbuttonssl.htm
CButtonSSL has these advantages:
- Visually definable
- You can define your menu in the VC menu editor with flyouts, check marks etc.
- In completely isolated and reusable class form
- plus much more extras
Suha Aktan
|
|
|
|
|
So - go and use the other button - I'm really not interested on what you think.
|
|
|
|
|
Please do not take it personally, Normski.
My aim is to suggest an alternative to the public.
Let's make peace
|
|
|
|
|
Sorry for being -ne (that's negative) I get a lot of folks saying "if it could just do that" or "these a bug - fix it", one reason why I didn't post updates or fixes to all of my articles.
Apologies accepted!
|
|
|
|
|
but i don't see any support for winxp themeing
and before you say this one neither, watch the thread below
|
|
|
|
|
I fixed up CCoolBtn (as CCoolButton) to work with themes on Win/XP. I also added the ability to have the button only work as a Menu Button (no split) and to have a 2nd ID for the down-arrow part rather than an attached menu. Enjoy.
Leigh Brasington
/* >>>>>>>>>>>>>>>>>>> Here's the CoolButton.h file <<<<<<<<<<<<<<<<<<<< */
#if !defined(AFX_CoolButton_H__3A90681F_CE5F_11D3_808C_005004D6CF90__INCLUDED_)
#define AFX_CoolButton_H__3A90681F_CE5F_11D3_808C_005004D6CF90__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CoolButton.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CCoolButton window
class CCoolButton : public CButton
{
// Construction
public:
CCoolButton();
BOOL SetIDs(UINT nID1, UINT m_nID2);
BOOL AddMenuItem(UINT nMenuId,const CString strMenu, UINT nMenuFlags);
BOOL SetButtonImage(UINT nResourceId, COLORREF crMask);
void SetSplit(BOOL b) { m_bSplit = b && (m_bMenuLoaded || m_nID2); }
void SetAsDefaultBtn(BOOL b) { m_bDefaultBtn = b; }
void ClearButtonPushed();
// Attributes
protected:
CMenu m_menu;
CBitmap m_btnImage;
CImageList m_IL;
BOOL m_Initialized;
BOOL m_bPushed;
BOOL m_bMenuPushed;
BOOL m_bMenuLoaded;
BOOL m_bLoaded;
BOOL m_bDefaultBtn;
BOOL m_bActAsDefaultBtn;
BOOL m_bSplit;
BITMAP m_bm;
UINT m_nID1;
UINT m_nID2;
COLORREF m_crMask;
HBITMAP m_hbmpDisabled;
HMODULE m_themeLib; // handle to UxTheme.dll
BOOL m_bOverControl; // is the mouse over us?
BOOL m_bTracking; // are we tracking the mouse
// Operations
public:
protected:
void DrawArrow(CDC* pDC,CPoint ArrowTip);
BOOL HitMenuBtn(CPoint point);
BOOL OnMenuBtn();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CCoolButton)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CCoolButton();
// Generated message map functions
protected:
//{{AFX_MSG(CCoolButton)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnSetFocus(CWnd* pOldWnd);
afx_msg void OnKillFocus(CWnd* pNewWnd);
afx_msg void OnSysColorChange();
afx_msg void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg UINT OnGetDlgCode();
afx_msg LRESULT OnMouseHover(WPARAM wparam, LPARAM lparam);
afx_msg LRESULT OnMouseLeave(WPARAM wparam, LPARAM lparam);
afx_msg LRESULT OnSetStyle(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CoolButton_H__3A90681F_CE5F_11D3_808C_005004D6CF90__INCLUDED_)
/* >>>>>>>>>>>>>>>>>>> Here's the CoolButton.cpp file <<<<<<<<<<<<<<<<<<<< */
// CoolButton.cpp : implementation file
//
#include "stdafx.h"
#include "p4win.h"
#include "CoolBtn.h"
#if _MFC_VER >= 0x0700
#define USE_THEMES
#include <uxtheme.h>
#endif
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
const int nDropBtnWidth = 16;
/////////////////////////////////////////////////////////////////////////////
// CCoolButton
// ========
//
// To Use:
// 1. In the RC file, create the button as BS_OWNERDRAW.
// Optionally, create a Bitmap resource 16x15 Pixels
// - normal default size for a toolbar bitmap.
//
// 2. in the header for the dialog class:
// #include "CoolBtn.h"
// then create the necessary button widgets in the //{{AFX_DATA() section:
// CCoolButton m_DblBtn;
//
// 3. In the InitDialog() for the dialog:
//
// a) Optionally, Call SetButtonImage specificing the
// Transparency color reference.
// (Usally RGB(255, 0, 255) magenta)
// m_DblBtn.SetButtonImage(IDC_BTNIMAGE, RGB(255,0,255));
//
// b) Either call CCoolButton's SetIDs function:
// m_DblBtn.SetIDs(IDC_BTNPUSH, IDC_BTNMENU);
// the first ID must be the same as the ID in the RC file!
// --or--
// Add menu item(s) to the button:
// m_DblBtn.AddMenuItem(nMenuId1, strMenu1, nMenuFlags1);
// m_DblBtn.AddMenuItem(nMenuId2, strMenu2, nMenuFlags2);
//
// If you do both SetIDs() and AddMenuItem()s, only the AddMenuItem
// will be called and the second ID will be ignored.
//
// c) Optionally, call CCoolButton's show split function:
// m_DblBtn.SetSplit(bSplit);
// The default is to show the split (TRUE). If set to FALSE, only
// the AddMenuItem()s or 2nd ID in SetIDs() will be called and the
// base id (1st ID in SetIDs()==ID in RC file) will be ignored.
//
// d) Optionally call m_DblBtn.SetAsDefaultBtn(TRUE) to make the button
// the default button.
//
// 4. Add the appropiate ON_COMMAND handlers in the parent windows message map
//
// 5. You can also call SetIDs() or SetSplit() later to dynamically change the
// button and you can later add more AddMenuItem().
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: CCoolButton
//
// DESCRIPTION:
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin as CCoolBtn
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
CCoolButton::CCoolButton()
{
m_nID2 = 0;
m_bPushed = FALSE;
m_bLoaded = FALSE;
m_bMenuPushed = FALSE;
m_bMenuLoaded = FALSE;
m_bDefaultBtn = m_bActAsDefaultBtn = FALSE;
m_bSplit = TRUE;
m_bOverControl = FALSE;
m_bTracking = FALSE;
ZeroMemory(&m_bm, sizeof m_bm);
m_menu.CreatePopupMenu();
m_themeLib = LoadLibrary("UxTheme.dll");
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: ~CCoolButton
//
// DESCRIPTION:
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
//
////////////////////////////////////////////////////////////////////////////////
CCoolButton::~CCoolButton()
{
if(m_themeLib)
FreeLibrary(m_themeLib);
}
BEGIN_MESSAGE_MAP(CCoolButton, CButton)
//{{AFX_MSG_MAP(CCoolButton)
ON_WM_SYSKEYDOWN()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
ON_WM_SYSCOLORCHANGE()
ON_WM_GETDLGCODE()
//}}AFX_MSG_MAP
ON_MESSAGE(BM_SETSTYLE, OnSetStyle)
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover )
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave )
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCoolButton message handlers
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: SetIDs
//
// DESCRIPTION: Set the IDs
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
BOOL CCoolButton::SetIDs( UINT nID1, UINT nID2 )
{
m_nID1 = nID1;
m_nID2 = nID2;
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
UINT CCoolButton::OnGetDlgCode()
{
UINT nCode = CButton::OnGetDlgCode();
nCode |= (m_bActAsDefaultBtn ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON);
return nCode;
}
// mask for control's type
#define BS_TYPEMASK SS_TYPEMASK
LRESULT CCoolButton::OnSetStyle(WPARAM wParam, LPARAM lParam)
{
m_bActAsDefaultBtn = wParam & BS_DEFPUSHBUTTON;
// can't change control type after owner-draw is set.
// let the system process changes to other style bits
// and redrawing, while keeping owner-draw style
return DefWindowProc(BM_SETSTYLE,
(wParam & ~BS_TYPEMASK) | BS_OWNERDRAW, lParam);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: DrawItem
//
// DESCRIPTION: Called in response to draw the button
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton, Added XP support
//
////////////////////////////////////////////////////////////////////////////////
#ifdef USE_THEMES
typedef HTHEME(__stdcall *PFNOPENTHEMEDATA)(HWND hwnd, LPCWSTR pszClassList);
typedef HRESULT(__stdcall *PFNCLOSETHEMEDATA)(HTHEME hTheme);
typedef HRESULT(__stdcall *PFNDRAWTHEMEBACKGROUND)(HTHEME hTheme, HDC hdc,
int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect);
typedef HRESULT(__stdcall *PFNGETTHEMEBACKGROUNDCONTENTRECT)(HTHEME hTheme, HDC hdc,
int iPartId, int iStateId, const RECT *pRect, RECT *pContentRect);
#endif
void CCoolButton::DrawItem(DRAWITEMSTRUCT* lpDIS)
{
if (lpDIS->CtlType != ODT_BUTTON)
return;
CFont *pFont = CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT));
CDC dcMem;
CBitmap bmp;
CRect btnRect(lpDIS->rcItem);
CRect trueRect(btnRect);
CRect rectFocus(btnRect);
CDC *pDC = CDC::FromHandle(lpDIS->hDC);
BOOL bDisabled = ODS_DISABLED & lpDIS->itemState;
#ifdef USE_THEMES
HTHEME hTheme = 0;
if(m_themeLib)
{
PFNOPENTHEMEDATA pOpenThemeData = (PFNOPENTHEMEDATA)
GetProcAddress(m_themeLib, "OpenThemeData");
if(pOpenThemeData)
hTheme = (pOpenThemeData)(m_hWnd, L"Button");
}
if(hTheme)
{
// attempt to map owner draw states to theme pushbutton states
int iState = PBS_NORMAL;
if(m_bOverControl)//lpDIS->itemState & ODS_HOTLIGHT)
iState = PBS_HOT;
else if(m_bDefaultBtn || m_bActAsDefaultBtn)//lpDIS->itemState & ODS_DEFAULT)
iState = PBS_DEFAULTED;
else if(lpDIS->itemState & ODS_SELECTED)
iState = PBS_PRESSED;
HRESULT hr;
HDC hDC = lpDIS->hDC;
RECT rc = lpDIS->rcItem;
// let theme draw background
PFNDRAWTHEMEBACKGROUND pDrawThemeBackground = (PFNDRAWTHEMEBACKGROUND)
GetProcAddress(m_themeLib, "DrawThemeBackground");
if(!pDrawThemeBackground)
return;
hr = (pDrawThemeBackground)(hTheme, hDC,
BP_PUSHBUTTON, iState, &rc, 0);
if(hr != S_OK)
return;
// get rect to put content in
RECT rcContent;
PFNGETTHEMEBACKGROUNDCONTENTRECT pGetThemeBackgroundContentRect =
(PFNGETTHEMEBACKGROUNDCONTENTRECT)
GetProcAddress(m_themeLib, "GetThemeBackgroundContentRect");
if(!pGetThemeBackgroundContentRect)
return;
hr = (pGetThemeBackgroundContentRect)(hTheme, hDC,
BP_PUSHBUTTON, iState, &rc, &rcContent);
if(hr != S_OK)
return;
rectFocus = rcContent;
if (!m_bMenuPushed)
rectFocus.OffsetRect(m_bPushed,m_bPushed);
if (m_bSplit)
rectFocus.right -= nDropBtnWidth;
if (lpDIS->itemState & ODS_FOCUS || m_bPushed)
{
if (!m_bMenuPushed)
::DrawFocusRect(lpDIS->hDC, &rcContent);
}
}
else
#endif
{
////////////////////////////////////////
// Button Background //
////////////////////////////////////////
CBrush brush(GetSysColor(COLOR_BTNFACE));
pDC->FillRect(trueRect,&brush);
if (m_bDefaultBtn)
btnRect.DeflateRect(1,1);
rectFocus.DeflateRect(4,4);
if (!m_bMenuPushed)
rectFocus.OffsetRect(m_bPushed,m_bPushed);
if (m_bSplit)
rectFocus.right -= nDropBtnWidth;
////////////////////////////////////////
// Button in a normal state //
////////////////////////////////////////
if (!m_bPushed || m_bMenuPushed)
pDC->DrawFrameControl(&btnRect,DFC_BUTTON,DFCS_BUTTONPUSH);
////////////////////////////////////////
// Default Button State //
////////////////////////////////////////
if ((m_bDefaultBtn || m_bPushed) && !bDisabled)
{
pDC->FrameRect(&lpDIS->rcItem,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
if (m_bPushed && !m_bMenuPushed)
pDC->FrameRect(&btnRect,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
}
////////////////////////////////////////
// State Focus //
////////////////////////////////////////
if (lpDIS->itemState & ODS_FOCUS || m_bPushed)
{
pDC->FrameRect(&lpDIS->rcItem,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
if (!m_bMenuPushed)
pDC->DrawFocusRect(&rectFocus);
}
////////////////////////////////////////
// Action Focus //
////////////////////////////////////////
if ((lpDIS->itemAction & ODA_FOCUS))
if (!m_bMenuPushed)
pDC->DrawFocusRect(&rectFocus);
}
////////////////////////////////////////
// Draw out bitmap //
////////////////////////////////////////
// Draw out bitmap
if (m_bLoaded)
{
if (!bDisabled)
{
m_IL.DrawIndirect(pDC,0,CPoint(6+m_bPushed,6+m_bPushed), CSize(m_bm.bmWidth, m_bm.bmHeight), CPoint(0,0),ILD_NORMAL);
}
else
{
pDC->DrawState(CPoint(6+m_bPushed,6+m_bPushed), CSize(m_bm.bmWidth, m_bm.bmHeight), m_hbmpDisabled, DST_BITMAP | DSS_DISABLED);
}
}
////////////////////////////////////////
// Draw out text //
////////////////////////////////////////
pDC->SelectObject(pFont);
CRect rectText(rectFocus);
if (!m_bSplit)
rectText.right -= nDropBtnWidth;
rectText.left += m_bm.bmWidth + 2;
CString strCaption;
GetWindowText(strCaption);
pDC->SetBkMode(TRANSPARENT);
pDC->SetBkColor(GetSysColor(COLOR_BTNFACE));
if (ODS_DISABLED & lpDIS->itemState)
{
rectText.OffsetRect(1,1);
pDC->SetTextColor(GetSysColor(COLOR_WINDOW));
pDC->DrawText(strCaption,rectText,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
rectText.OffsetRect(-1,-1);
pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
pDC->DrawText(strCaption,rectText,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
}
else
{
pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
pDC->DrawText(strCaption,rectText,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
}
CRect rectSplit(btnRect);
rectSplit.DeflateRect(2,2);
rectSplit.right -= nDropBtnWidth;
////////////////////////////////////////
// Drop down split //
////////////////////////////////////////
if (m_bSplit)
{
CPen brFace(PS_SOLID,1,GetSysColor(COLOR_3DSHADOW));
pDC->SelectObject(&brFace);
pDC->MoveTo(rectSplit.right, rectSplit.top);
pDC->LineTo(rectSplit.right, rectSplit.bottom);
CPen brLite(PS_SOLID,1,GetSysColor(COLOR_3DHILIGHT));
pDC->SelectObject(&brLite);
pDC->MoveTo(rectSplit.right+1 , rectSplit.top);
pDC->LineTo(rectSplit.right+1, rectSplit.bottom);
}
////////////////////////////////////////
// Draw Arrow //
////////////////////////////////////////
rectSplit.left = rectSplit.right;
rectSplit.right += nDropBtnWidth;
CPoint pt(rectSplit.CenterPoint());
pt += CPoint(m_bPushed,m_bPushed);
CPen penBlack(PS_SOLID, 1, bDisabled ? GetSysColor(COLOR_GRAYTEXT) : GetSysColor(COLOR_WINDOWTEXT));
pDC->SelectObject(&penBlack);
DrawArrow(pDC,pt);
////////////////////////////////////////
// Drop down state //
////////////////////////////////////////
if (m_bMenuPushed && !bDisabled)
{
rectSplit.InflateRect(1,1);
pDC->DrawEdge(rectSplit,BDR_SUNKENOUTER, BF_RECT);
}
if(hTheme)
{
PFNCLOSETHEMEDATA pCloseThemeData = (PFNCLOSETHEMEDATA)GetProcAddress(m_themeLib, "CloseThemeData");
if(!pCloseThemeData)
return;
(pCloseThemeData)(hTheme);
}
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: DrawArrow
//
// DESCRIPTION: Draws drop down arrow, we could use DrawFrameControl - a bit too
// messy
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
//
////////////////////////////////////////////////////////////////////////////////
void CCoolButton::DrawArrow(CDC* pDC,CPoint ArrowTip)
{
CPoint ptDest;
pDC->SetPixel(ArrowTip,RGB(0,0,0));
ArrowTip -= CPoint(1,1);
pDC->MoveTo(ArrowTip);
ptDest = ArrowTip;
ptDest += CPoint(3,0);
pDC->LineTo(ptDest);
ArrowTip -= CPoint(1,1);
pDC->MoveTo(ArrowTip);
ptDest = ArrowTip;
ptDest += CPoint(5,0);
pDC->LineTo(ptDest);
ArrowTip -= CPoint(1,1);
pDC->MoveTo(ArrowTip);
ptDest = ArrowTip;
ptDest += CPoint(7,0);
pDC->LineTo(ptDest);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: OnLButtonDown
//
// DESCRIPTION: handles button pressed state, including drop down menu
//
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
void CCoolButton::OnLButtonDown(UINT nFlags, CPoint point)
{
SetFocus();
if (m_bMenuPushed)
{
m_bMenuPushed = FALSE;
Invalidate();
return;
}
if (!m_bSplit || HitMenuBtn(point))
{
OnMenuBtn();
return;
}
m_bPushed = TRUE;
Invalidate();
CButton::OnLButtonDown(nFlags, point);
}
BOOL CCoolButton::OnMenuBtn()
{
if (!m_bMenuLoaded)
{
if (m_nID2)
{
GetParent()->PostMessage(WM_COMMAND, m_nID2, 0);
m_bMenuPushed = TRUE;
Invalidate();
return TRUE;
}
}
else
{
m_bMenuPushed = TRUE;
Invalidate();
CRect rc;
GetWindowRect(rc);
int x = rc.left;
int y = rc.bottom;
m_menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON,x,y,GetParent());
m_bMenuPushed = FALSE;
Invalidate();
return TRUE;
}
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: OnLButtonUp
//
// DESCRIPTION: Redraws button in normal state
//
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
void CCoolButton::ClearButtonPushed()
{
if (m_bPushed)
{
m_bPushed = FALSE;
Invalidate();
}
if (m_bMenuPushed)
{
m_bMenuPushed = FALSE;
Invalidate();
}
}
void CCoolButton::OnLButtonUp(UINT nFlags, CPoint point)
{
ClearButtonPushed();
CButton::OnLButtonUp(nFlags, point);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: OnMouseMove
//
// DESCRIPTION: Tracks mouse whilst pressed
//
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
LRESULT CCoolButton::OnMouseHover(WPARAM wparam, LPARAM lparam)
{
m_bOverControl=TRUE;
Invalidate();
return 1;
}
LRESULT CCoolButton::OnMouseLeave(WPARAM wparam, LPARAM lparam)
{
m_bTracking = FALSE;
m_bOverControl = FALSE;
Invalidate(FALSE);
return 0;
}
void CCoolButton::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bPushed)
{
ClientToScreen(&point);
if (WindowFromPoint(point) != this)
{
m_bPushed = FALSE;
Invalidate();
}
}
if (!m_bTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE|TME_HOVER;
tme.dwHoverTime = 1;
m_bTracking = _TrackMouseEvent(&tme) != FALSE;
}
CButton::OnMouseMove(nFlags, point);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: SetButtonImage
//
// DESCRIPTION: Sets the button image, COLORREF crMask specifics the transparency
// color
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
//
////////////////////////////////////////////////////////////////////////////////
BOOL CCoolButton::SetButtonImage(UINT nResourceId, COLORREF crMask)
{
// The ID must exist also as a bitmap resource!!!
m_btnImage.LoadBitmap(nResourceId);
m_btnImage.GetObject(sizeof m_bm, &m_bm);
m_IL.Create( nResourceId, m_bm.bmWidth, 1, crMask );
m_bLoaded = TRUE;
m_crMask = crMask;
HBITMAP bmTemp;
COLORMAP mapColor;
mapColor.from = crMask;
mapColor.to = RGB(255,255,255);
bmTemp = (HBITMAP)::CreateMappedBitmap(AfxGetApp()->m_hInstance, nResourceId, IMAGE_BITMAP, &mapColor, 1);
m_hbmpDisabled = (HBITMAP)::CopyImage(bmTemp, IMAGE_BITMAP, m_bm.bmWidth, m_bm.bmHeight, LR_COPYDELETEORG);
return m_bLoaded;
}
void CCoolButton::OnSetFocus(CWnd* pOldWnd)
{
CButton::OnSetFocus(pOldWnd);
Invalidate();
}
void CCoolButton::OnKillFocus(CWnd* pNewWnd)
{
CButton::OnKillFocus(pNewWnd);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: OnSysColorChange
//
// DESCRIPTION: Called when system colors change, force a button redraw
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
//
////////////////////////////////////////////////////////////////////////////////
void CCoolButton::OnSysColorChange()
{
CButton::OnSysColorChange();
Invalidate();
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: HitMenuBtn
//
// DESCRIPTION: Helper function to test for menu button hit...
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
BOOL CCoolButton::HitMenuBtn(CPoint point)
{
if (!m_bMenuLoaded && !m_nID2)
return FALSE; // Don't allow menu button drop down if no menu items are loaded
ClientToScreen(&point);
CRect rect;
GetWindowRect(rect);
rect.left = rect.right - nDropBtnWidth;
return rect.PtInRect(point);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: AddMenuItem
//
// DESCRIPTION: Adds a menu item and id to our menu.
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
//
////////////////////////////////////////////////////////////////////////////////
BOOL CCoolButton::AddMenuItem(UINT nMenuId,const CString strMenu, UINT nMenuFlags)
{
BOOL bRet = m_menu.AppendMenu(nMenuFlags | MF_STRING, nMenuId, (LPCTSTR)strMenu);
m_bMenuLoaded |= bRet;
return bRet;
}
////////////////////////////////////////////////////////////////////////////////
void CCoolButton::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch ( nChar )
{
case VK_DOWN:
OnMenuBtn();
break;
}
CWnd::OnSysKeyDown(nChar, nRepCnt, nFlags);
}
Leigh Brasington
|
|
|
|
|
Thanks Leigh, you could of emailed me the source
Seriously I should get round to getting a new version out.
|
|
|
|
|
I have a cool push menu button in a property page and I can drive it very easily from the mouse. Unfortunately, I can't seem to drive it very well from the keyboard which is a problem as my dialogs may be used by disabled users (mouse impaired?). I have the button specified as &Add so ALT+A should drive it but I have multiple problems:
1. If the current focus is outside of the property page (on the tabs or common buttons), then the first selection of ALT+A selects the primary value of my button. If the focus is within the property page then the first selection of ALT+A sets the focus to the button and then the second press of ALT+A will issue the default command (equivalent of a mouse left-click on the non menu side of the button).
2. Can't show the menu in any form when using the keyboard. Using the context menu button has no effect.
Any suggestions on ways around this or how to enhance the class?
Carl
|
|
|
|
|
i have an ActiveX button menu which contains a list of web site names. when you press them, it takes you to the website. Users are to be able to add/delete sites from the list. i have managed to get the name of a new site added to the list, but i am unable to link the URL to it so they can go to the page. Any ideas?
|
|
|
|
|
:-DHi,
Simple eliminate the m_pParentWnd and replace it with GetParent()
so subclassing doesn't need to call your 'Create' method.
|
|
|
|
|
Allow menu states be dynamically changed with :
void CCoolBtn::ChangeMenuFlags(UINT nMenuId, UINT nMenuFlags)
{
m_menu.CheckMenuItem(nMenuId, nMenuFlags | MF_BYCOMMAND);
}
For instance, this allows me to check/uncheck menu items to reflect the GUI state.
She's so dirty, she threw a boomerang and it wouldn't even come back.
|
|
|
|
|
Hi,
Nice class but direct subclassing does not work!
Simple eliminate the m_pParentWnd and replace it with GetParent()
so subclassing doesn't need to call your 'Create' method.
My two pence,;)
Cabbi
|
|
|
|
|
Sir;
Thanks for this nice code.
I want to use this for arrow on the left side of the button,
instead of the right side.
HOW CAN I DO THAT?
Also, how can i use bitmaps for the added menu items instead of text.
I want to use bitmaps from resources.
Please help.
Regards
amit
|
|
|
|
|
There is an unneeded semicolon character ";" in CCoolBtn::Create function.
|
|
|
|
|
Normski. - Professional Windows Programmer
|
|
|
|
|