flatpopupmenu.cpp

来自「《突破Visual C++.NET编程实例五十讲+源文件,初学者学习的好东东!」· C++ 代码 · 共 917 行 · 第 1/2 页

CPP
917
字号

//是分隔条?
  if((item.m_dwFlags & itemSeparator)!=0)
  {
    DrawSeparator(hDC,item.m_Top);
    return;
  }

// 获取菜单项左上角
  x=3;
  y=item.m_Top;

// 是图标?
  if(item.m_IconIndex!=-1)
  {
    p[0].x=p[1].x=x;
    p[0].y=y+16;
    p[1].y=p[2].y=item.m_Top;
    p[2].x=x+17;
    hOldPen=SelectObject(hDC,bSelected ? m_hLightShadowPen : m_hBackPen);
    Polyline(hDC,p,3);

    p[0].x=p[1].x=x+17;
    p[0].y=item.m_Top;
    p[1].y=p[2].y=y+16;
    p[2].x=x;
    SelectObject(hDC,bSelected ? m_hDarkShadowPen : m_hBackPen);
    Polyline(hDC,p,3);
    SelectObject(hDC,hOldPen);

  // 画位图
    DrawTransparentBitmap(hDC,item.m_IconIndex*16,x+1,item.m_Top+1);
    x+=18;
  }

// 绘制/清除选择区域矩形
  hOldBrush=SelectObject(hDC,bSelected ? m_hSelectedBrush : m_hBackBrush);
  hOldPen=SelectObject(hDC,GetStockObject(NULL_PEN));

  Rectangle(hDC,x,item.m_Top,m_Width-2,item.m_Top+18);

  SelectObject(hDC,hOldPen);
  SelectObject(hDC,hOldBrush);

// 绘制菜单项文本
  if((item.m_dwFlags & itemBold)!=0)
  {
    h=m_BoldFontHeight;
    hOldFont=SelectObject(hDC,m_hBoldFont);
  }
  else
  {
    h=m_FontHeight;
    hOldFont=SelectObject(hDC,m_hFont);
  }

  SetBkMode(hDC,TRANSPARENT);

  if(bSelected)
    nColor=colorHighlightText;
  else
  {
    if((item.m_dwFlags & itemGrayed)!=0)
      nColor=colorGrayedText;
    else
      nColor=colorText;
  }

  rect.left=1+2+18+2;
  rect.top=item.m_Top+((17-h)/2);
  rect.bottom=rect.top+1000;
  rect.right=rect.left+1000;

  SetTextColor(hDC,m_Colors[nColor]);
  DrawText(hDC,item.m_strName.c_str(),item.m_strName.length(),&rect,DT_LEFT | DT_TOP | DT_NOCLIP);
  SelectObject(hDC,hOldFont);

// 绘制指向子菜单的箭头
  if(item.m_pPopup)
  {
    hOldPen=SelectObject(hDC,bSelected ? m_hSelectedTextPen : m_hTextPen);

    p[0].x=p[1].x=m_Width-7;
    p[0].y=item.m_Top+8;
    p[1].y=item.m_Top+9;

    for(i=0;i<4;i++)
    {
      Polyline(hDC,p,2);
      p[0].x--;
      p[1].x--;
      p[0].y--;
      p[1].y++;
    }

    SelectObject(hDC,hOldPen);
  }
}

//绘制分隔条
void CFlatPopupMenu::DrawSeparator(HDC hDC,int top)
{
  POINT   p[2];
  HGDIOBJ hOldPen;

  p[0].x=0;
  p[1].x=m_Width;
  p[0].y=p[1].y=top+2;
  hOldPen=SelectObject(hDC,m_hBorderPen);
  Polyline(hDC,p,2);
  SelectObject(hDC,hOldPen);
}

// WM_DESTROY消息处理函数
void CFlatPopupMenu::OnDestroy(HWND hWnd)
{
  std::vector<CItem>::const_iterator it;

  for(it=m_Items.begin();it!=m_Items.end();it++)
    if(it->m_pPopup && it->m_pPopup->m_State!=stateInactive)
      DestroyWindow(it->m_pPopup->m_hWnd);

  if(m_State==stateTrack)
    ReleaseCapture();

  m_State=stateInactive;
  m_hWnd=NULL;

  if(!m_bModal && m_SelectedID && !m_bChild)
    PostMessage(m_hWndCommand,WM_COMMAND,m_SelectedID,0);
}

// WM_MOUSEMOVE 消息处理函数
void CFlatPopupMenu::OnMouseMove(HWND hWnd,short x,short y)
{
  RECT            rect;
  HDC             hDC;
  HWND            hPointWnd;
  int             item,newitem;
  POINT           p;
  TCHAR           szClass[100];
  CFlatPopupMenu *pClass;

// 获取DC和窗口矩形
  GetClientRect(hWnd,&rect);
  hDC=GetDC(hWnd);

  p.x=x;
  p.y=y;
  ClientToScreen(hWnd,&p);

  if((hPointWnd=WindowFromPoint(p))!=NULL && GetClassName(hPointWnd,szClass,sizeof(szClass)/sizeof(TCHAR)) && !lstrcmp(szClass,"fpmMenuClass"))
  {
    pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hPointWnd,GWL_USERDATA));

    if(pClass!=this)
    {
      ReleaseCapture();
      m_State=stateShow;

      SetCapture(pClass->m_hWnd);
      pClass->m_State=stateTrack;

      return;
    }
  }

// 获取最新选择
  newitem=GetItem(x,y,rect);

// 清除以前选择?
  if(m_SelectedItem!=-1 && newitem!=m_SelectedItem)
  {
    KillTimer(m_hWnd,1);

    if(m_Items[m_SelectedItem].m_pPopup && m_Items[m_SelectedItem].m_pPopup->m_State!=stateInactive)
      DestroyWindow(m_Items[m_SelectedItem].m_pPopup->m_hWnd);

    item=m_SelectedItem;
    m_SelectedItem=-1;
    DrawItem(hWnd,hDC,item,m_Items[item]);
  }

// 最新选择
  if(newitem!=-1 && m_SelectedItem!=newitem)
  {
  // 绘制新菜单项
    m_SelectedItem=newitem;
    DrawItem(hWnd,hDC,m_SelectedItem,m_Items[m_SelectedItem]);

  // 若为弹出式菜单
    if(m_Items[m_SelectedItem].m_pPopup)
      SetTimer(m_hWnd,1,m_PopupDelay,NULL);
  }
}

//获取菜单项位置
int CFlatPopupMenu::GetItem(short x,short y,const RECT& rect)
{
  int newitem;
  std::vector<CItem>::size_type i;

  if(x<=2 || y<=2 || x>rect.right || y>rect.bottom)
    newitem=-1;
  else
  {
    for(i=0;i<m_Items.size();i++)
      if(y>m_Items[i].m_Top && y<m_Items[i].m_Top+m_Items[i].m_Height)
        break;

    newitem=i==m_Items.size() ? -1 : i;
    if(newitem!=-1 && (m_Items[newitem].m_dwFlags & itemNotSelectable)!=0)
      newitem=-1;
  }

  return newitem;
}


void CFlatPopupMenu::ButtonDown(HWND hWnd,short x,short y,const bool bLeft)
{
  RECT rect;

  GetClientRect(hWnd,&rect);
  if(CheckOutsideMenu(hWnd,rect,x,y))
    return;

  if(m_SelectedItem!=-1 && m_Items[m_SelectedItem].m_pPopup && m_Items[m_SelectedItem].m_pPopup->m_State==stateInactive)
    OnTimer(hWnd,1);
}

// WM_LBUTTONUP消息处理函数
void CFlatPopupMenu::OnLButtonUp(HWND hWnd,short x,short y)
{
  RECT rect;

  if(m_bWaitLeftButton)
  {
    m_bWaitLeftButton=false;
    return;
  }

  GetClientRect(hWnd,&rect);
  if(CheckOutsideMenu(hWnd,rect,x,y))
    return;

  if(m_SelectedItem!=-1 && m_Items[m_SelectedItem].m_ItemID)
    SetReturn(m_Items[m_SelectedItem].m_ItemID);
}

// WM_RBUTTONUP消息处理函数
void CFlatPopupMenu::OnRButtonUp(HWND hWnd,short x,short y)
{
  RECT rect;

  if(m_bWaitRightButton)
  {
    m_bWaitRightButton=false;
    return;
  }

  GetClientRect(hWnd,&rect);
  if(CheckOutsideMenu(hWnd,rect,x,y))
    return;

  if(m_SelectedItem!=-1 && m_Items[m_SelectedItem].m_ItemID)
    SetReturn(m_Items[m_SelectedItem].m_ItemID);
}

//设置返回值
void CFlatPopupMenu::SetReturn(const UINT id)
{
  CFlatPopupMenu *pMenu;

  for(pMenu=this;pMenu->m_pPrevious;pMenu=pMenu->m_pPrevious);
  pMenu->m_SelectedID=id;
  DestroyAll();
}


//检查是否在菜单外
bool CFlatPopupMenu::CheckOutsideMenu(HWND hWnd,const RECT& rect,short x,short y)
{
  if(x<=2 || y<=2 || x>rect.right || y>rect.bottom)
  {
  // 在窗口外单击
    m_SelectedItem=-1;
    m_SelectedID=0;
    DestroyAll();

    return true;
  }

  return false;
}

// WM_ERASEBKGND 消息处理函数
void CFlatPopupMenu::OnEraseBkgnd(HWND hWnd,HDC hDC)
{
  RECT    rect;
  HGDIOBJ hOldBrush,hOldPen;

  GetClientRect(hWnd,&rect);
  hOldBrush=SelectObject(hDC,m_hBackBrush);
  hOldPen=SelectObject(hDC,m_hBorderPen);
  
  Rectangle(hDC,rect.left,rect.top,rect.right,rect.bottom);

  SelectObject(hDC,hOldBrush);
  SelectObject(hDC,hOldPen);
}

// 赋值 
void CFlatPopupMenu::CItem::Assign(const CItem& src)
{
  m_dwFlags=src.m_dwFlags;
  m_strName=src.m_strName;
  m_ItemID=src.m_ItemID;
  m_IconIndex=src.m_IconIndex;
  m_Top=src.m_Top;
  m_Height=src.m_Height;
  m_pPopup=src.m_pPopup;
}

//绘制透明位图
void CFlatPopupMenu::DrawTransparentBitmap(HDC hdc,const int xSrcOffset,const int xStart,const int yStart)
{
  BITMAP    bm;
  COLORREF  cColor;
  HBITMAP   bmAndBack,bmAndObject,bmAndMem,bmSave;
  HBITMAP   bmBackOld,bmObjectOld,bmMemOld,bmSaveOld;
  HDC       hdcMem,hdcBack,hdcObject,hdcTemp,hdcSave;
  POINT     ptSize;

  hdcTemp=CreateCompatibleDC(hdc);
  SelectObject(hdcTemp,m_hBitmap);    

  GetObject(m_hBitmap,sizeof(BITMAP),(LPSTR)&bm);
  ptSize.x=bm.bmWidth;                
  ptSize.y=bm.bmHeight;              
  DPtoLP(hdcTemp,&ptSize,1);          

  hdcBack=CreateCompatibleDC(hdc);
  hdcObject=CreateCompatibleDC(hdc);
  hdcMem=CreateCompatibleDC(hdc);
  hdcSave=CreateCompatibleDC(hdc);

  bmAndBack=CreateBitmap(ptSize.x,ptSize.y,1,1,NULL);

  bmAndObject=CreateBitmap(ptSize.x,ptSize.y,1,1,NULL);

  bmAndMem=CreateCompatibleBitmap(hdc,ptSize.x,ptSize.y);
  bmSave=CreateCompatibleBitmap(hdc,ptSize.x,ptSize.y);

  bmBackOld=(HBITMAP)SelectObject(hdcBack,bmAndBack);
  bmObjectOld=(HBITMAP)SelectObject(hdcObject,bmAndObject);
  bmMemOld=(HBITMAP)SelectObject(hdcMem,bmAndMem);
  bmSaveOld=(HBITMAP)SelectObject(hdcSave,bmSave);

  SetMapMode(hdcTemp,GetMapMode(hdc));

  BitBlt(hdcSave,0,0,ptSize.x,ptSize.y,hdcTemp,0,0,SRCCOPY);
  cColor=SetBkColor(hdcTemp,m_Colors[colorIconTransparent]);
  BitBlt(hdcObject,0,0,ptSize.x,ptSize.y,hdcTemp,0,0,SRCCOPY);
  SetBkColor(hdcTemp,cColor);
  BitBlt(hdcBack,0,0,ptSize.x,ptSize.y,hdcObject,0,0,NOTSRCCOPY);
  BitBlt(hdcMem,xSrcOffset,0,16,15,hdc,xStart,yStart,SRCCOPY);
  BitBlt(hdcMem,0,0,ptSize.x,ptSize.y,hdcObject,0,0,SRCAND);
  BitBlt(hdcTemp,0,0,ptSize.x,ptSize.y,hdcBack,0,0,SRCAND);
  BitBlt(hdcMem,0,0,ptSize.x,ptSize.y,hdcTemp,0,0,SRCPAINT);
  BitBlt(hdc,xStart,yStart,16,15,hdcMem,xSrcOffset,0,SRCCOPY);
  BitBlt(hdcTemp,0,0,ptSize.x,ptSize.y,hdcSave,0,0,SRCCOPY);

  DeleteObject(SelectObject(hdcBack,bmBackOld));
  DeleteObject(SelectObject(hdcObject,bmObjectOld));
  DeleteObject(SelectObject(hdcMem,bmMemOld));
  DeleteObject(SelectObject(hdcSave,bmSaveOld));

  DeleteDC(hdcMem);
  DeleteDC(hdcBack);
  DeleteDC(hdcObject);
  DeleteDC(hdcSave);
  DeleteDC(hdcTemp);
}

//修改菜单文本
bool CFlatPopupMenu::SetMenuItemText(const UINT itemid,LPCTSTR pszName,const bool bByPosition)
{
  CItem *pItem;

  if((pItem=GetItem(itemid,bByPosition))==NULL)
    return false;

  pItem->m_strName=pszName;
  return true;
}

//修改菜单标志
bool CFlatPopupMenu::SetMenuItemFlags(const UINT itemid,const DWORD dwFlags,const bool bByPosition)
{
  CItem *pItem;

  if((pItem=GetItem(itemid,bByPosition))==NULL)
    return false;

  pItem->m_dwFlags=dwFlags;
  return true;
}

//获取菜单项文本
bool CFlatPopupMenu::GetString(const UINT itemid,LPTSTR pszText,const UINT cchText,const bool bByPosition)
{
  CItem *pItem;

  if((pItem=GetItem(itemid,bByPosition))==NULL)
    return false;

  if(pItem->m_strName.length()+1>cchText)
    return false;

  lstrcpy(pszText,pItem->m_strName.c_str());
  return true;
}

//修改菜单标志
bool CFlatPopupMenu::SetMenuItemIcon(const UINT itemid,const int icon,const bool bByPosition)
{
  CItem *pItem;

  if((pItem=GetItem(itemid,bByPosition))==NULL)
    return false;

  pItem->m_IconIndex=icon;
  return true;
}

//查找菜单项
CFlatPopupMenu::CItem *CFlatPopupMenu::GetItem(const UINT itemid,const bool bByPosition)
{
  std::vector<CItem>::iterator it;

  if(bByPosition)
  {
    if(itemid>=m_Items.size())
      return false;

    return &m_Items[itemid];
  }
  else
  {
    for(it=m_Items.begin();it!=m_Items.end();it++)
      if(it->m_ItemID==itemid)
        return &(*it);

    return NULL;
  }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?