⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 propertygrid.h

📁 这是一本学习 window编程的很好的参考教材
💻 H
📖 第 1 页 / 共 3 页
字号:
      // Hmm, this would be an awfully slooow method!
      // So most of the time we're really searching for the in-place editor...
      if( m_iInplaceRow != -1 ) {
         IProperty** props = reinterpret_cast<IProperty**>(TBase::GetItemData(m_iInplaceRow));
         if( props ) {
            for( int i = 0; i < m_nColumns; i++ ) {
               if( props[i] == prop ) {
                  iItem = m_iInplaceRow;
                  iSubItem = i;
                  return TRUE;
               }
            }
         }
      }
      // Ok, scan all items...
      iItem = GetNextItem(-1, LVNI_ALL);
      while( iItem != -1 ) {
         IProperty** props = reinterpret_cast<IProperty**>(TBase::GetItemData(iItem));
         for( int i = 0; i < m_nColumns; i++ ) {
            if( props[i] == prop ) {
               iSubItem = i;
               return TRUE;
            }
         }
         iItem = GetNextItem(iItem, LVNI_ALL);
      }
      return FALSE;
   }
   IProperty* GetProperty(int iRow, int iCol) const
   {
      ATLASSERT(iCol >= 0 && iCol < m_nColumns);
      ATLASSERT(iRow >= 0 && iRow < TBase::GetItemCount());
      if( iCol < 0 || iCol >= m_nColumns ) return NULL;
      if( iRow < 0 || iRow >= TBase::GetItemCount() ) return NULL;
      IProperty** props = reinterpret_cast<IProperty**>(TBase::GetItemData(iRow));
      ATLASSERT(props);
      if( props == NULL ) return NULL;
      IProperty* prop = props[iCol];
      ATLASSERT(prop); // If you hit this assert, most likely you forgot to add properties to all subitems.
                       // Use read-only properties to fill out with dummies.
      return prop;
   }
   LPARAM GetItemData(HPROPERTY hProp) const
   {
      ATLASSERT(::IsWindow(m_hWnd));
      ATLASSERT(hProp);
      if( hProp == NULL ) return 0;
      return hProp->GetItemData();
   }
   void SetItemData(HPROPERTY hProp, LPARAM lParam)
   {
      ATLASSERT(::IsWindow(m_hWnd));
      ATLASSERT(hProp);
      if( hProp == NULL ) return;
      hProp->SetItemData(lParam);
   }
   BOOL GetItemEnabled(HPROPERTY hProp) const
   {
      ATLASSERT(hProp);
      if( hProp == NULL ) return FALSE;
      return hProp->IsEnabled();
   }
   void SetItemEnabled(HPROPERTY hProp, BOOL bEnable)
   {
      ATLASSERT(::IsWindow(m_hWnd));
      ATLASSERT(hProp);
      if( hProp == NULL ) return;
      hProp->SetEnabled(bEnable);
      // Repaint item...
      int nItem;
      int nSubItem;
      if( !FindProperty(hProp, nItem, nSubItem) ) return;
      _InvalidateItem(nItem, nSubItem);
   }
   void Navigate(UINT wCode)
   {
      SendMessage(WM_USER_PROP_NAVIGATE, wCode);
   }

   // Unsupported methods

   BOOL SetItem(int /*nItem*/, int /*nSubItem*/, UINT /*nMask*/, LPCTSTR /*lpszItem*/,
      int /*nImage*/, UINT /*nState*/, UINT /*nStateMask*/, LPARAM /*lParam*/)
   {
      ATLASSERT(false);
      return FALSE;
   }
   BOOL SetItemText(int /*nItem*/, int /*nSubItem*/, LPCTSTR /*lpszText*/)
   {
      ATLASSERT(false);
      return FALSE;
   }
   DWORD SetViewType(DWORD /*dwType*/)
   {
      ATLASSERT(false);
      return FALSE;
   }
   CEdit EditLabel(int /*nItem*/)
   {
      ATLASSERT(false);
      return NULL;
   }

   // Implementation

   void _Init()
   {
      ATLASSERT(::IsWindow(m_hWnd));
      // We need the LVS_SINGLESEL style
      ATLASSERT((GetStyle() & (LVS_SINGLESEL))==(LVS_SINGLESEL));
      ATLASSERT((GetStyle() & (LVS_EDITLABELS|LVS_OWNERDRAWFIXED|LVS_OWNERDATA))==0);
      // Prepare ListView control
      TBase::SetViewType(LVS_REPORT);
      SetExtendedListViewStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_TRACKSELECT|LVS_EX_HEADERDRAGDROP|LVS_EX_FLATSB);
      m_ctrlHeader = GetHeader();
      // Update colours and text
      SendMessage(WM_SETTINGCHANGE);
   }
   BOOL _SpawnInplaceWindow(IProperty* prop, int iItem, int iSubItem)
   {
      ATLASSERT(prop);
      ATLASSERT(iItem!=-1);
      ATLASSERT(iSubItem!=-1);
      // Destroy old in-place editor
      _DestroyInplaceWindow();
      // Do we need an editor here?
      if( iItem == -1 || iSubItem == -1 || iItem != GetSelectedIndex() ) return FALSE;
      if( !prop->IsEnabled() ) return FALSE;
      // Create a new editor window
      RECT rcValue;
      _GetSubItemRect(iItem, iSubItem, &rcValue);
      rcValue.right--;   // Let the borders
      rcValue.bottom--;  // display (right/bottom)
      m_hwndInplace = prop->CreateInplaceControl(m_hWnd, rcValue);
      if( m_hwndInplace ) {
         // Activate the new editor window
         ATLASSERT(::IsWindow(m_hwndInplace));
         ::SetWindowPos(m_hwndInplace, HWND_TOP, 0,0,0,0, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE);
         ::SetFocus(m_hwndInplace);
         m_iInplaceRow = iItem;
         m_iInplaceCol = iSubItem;
         return TRUE;
      }
      return m_hwndInplace != NULL;
   }
   void _DestroyInplaceWindow()
   {
      if( ::IsWindow(m_hwndInplace) ) {
         IProperty* prop = GetProperty(m_iInplaceRow, m_iInplaceCol);
         ATLASSERT(prop);
         BYTE bKind = prop->GetKind();
         // Set focus back to our control
         if( ::GetFocus() != m_hWnd && IsChild(::GetFocus()) ) SetFocus();
         // Destroy control
         switch( bKind ) {
         case PROPKIND_CONTROL:
            ::DestroyWindow(m_hwndInplace);
            break;
         default:
            ::PostMessage(m_hwndInplace, WM_CLOSE, 0,0);
         }
      }
      m_hwndInplace = NULL;
      m_iInplaceRow = -1;
      m_iInplaceCol = -1;
   }
   void _GetSubItemRect(int iItem, int iSubItem, RECT* pRect) const
   {
      if( iSubItem == 0 && _IsLastAddItem(iItem) ) {
         GetItemRect(iItem, pRect, LVIR_BOUNDS);
      }
      else if( iSubItem == 0 ) {
         GetItemRect(iItem, pRect, LVIR_BOUNDS);
         if( m_nColumns > 1 ) {
            RECT rcSecondColumn;
            GetSubItemRect(iItem, 1, LVIR_BOUNDS, &rcSecondColumn);
            pRect->right = rcSecondColumn.left - 1;
         }
      }
      else {
         GetSubItemRect(iItem, iSubItem, LVIR_BOUNDS, pRect);
      }
   }
   void _InvalidateItem(int iItem, int iSubItem)
   {
      if( iItem == -1 || iSubItem == -1 ) return;
      RECT rc;
      _GetSubItemRect(iItem, iSubItem, &rc);
      InvalidateRect(&rc);
   }
   bool _IsValidSelection() const
   {
      ATLASSERT(m_iSelectedRow==GetSelectedIndex()); // Should be in sync!
      return (m_iSelectedRow != -1) && (m_iSelectedCol != -1);
   }
   bool _IsLastAddItem(int iItem) const
   {
      return (m_di.dwExtStyle & PGS_EX_ADDITEMATEND) != 0 && 
             (iItem == TBase::GetItemCount()-1);
   }

   // Message map and handlers

   BEGIN_MSG_MAP(CPropertyGridImpl)
      MESSAGE_HANDLER(WM_CREATE, OnCreate)
      MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
      MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
      MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
      MESSAGE_HANDLER(WM_SIZE, OnScroll)
      MESSAGE_HANDLER(WM_VSCROLL, OnScroll)
      MESSAGE_HANDLER(WM_HSCROLL, OnScroll)
      MESSAGE_HANDLER(WM_MOUSEWHEEL, OnScroll)      
      MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
      MESSAGE_HANDLER(WM_CHAR, OnChar)
      MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
      MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
      MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
      MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown)
      MESSAGE_HANDLER(WM_USER_PROP_NAVIGATE, OnNavigate);
      MESSAGE_HANDLER(WM_USER_PROP_UPDATEPROPERTY, OnUpdateProperty);
      MESSAGE_HANDLER(WM_USER_PROP_CANCELPROPERTY, OnCancelProperty);
      MESSAGE_HANDLER(WM_USER_PROP_CHANGEDPROPERTY, OnChangedProperty);
      NOTIFY_CODE_HANDLER(HDN_ITEMCHANGEDA, OnHeaderChanging)
      NOTIFY_CODE_HANDLER(HDN_ITEMCHANGEDW, OnHeaderChanging)
      NOTIFY_CODE_HANDLER(HDN_ITEMCHANGINGA, OnHeaderChanging) // See Q183258 why we all need these
      NOTIFY_CODE_HANDLER(HDN_ITEMCHANGINGW, OnHeaderChanging)
      NOTIFY_CODE_HANDLER(HDN_TRACKA, OnHeaderChanging)
      NOTIFY_CODE_HANDLER(HDN_TRACKW, OnHeaderChanging)
      NOTIFY_CODE_HANDLER(HDN_DIVIDERDBLCLICKA, OnHeaderDblClick)
      NOTIFY_CODE_HANDLER(HDN_DIVIDERDBLCLICKW, OnHeaderDblClick)
      REFLECTED_NOTIFY_CODE_HANDLER(LVN_ITEMCHANGED, OnSelChanged)
      REFLECTED_NOTIFY_CODE_HANDLER(LVN_DELETEITEM, OnDeleteItem)
      CHAIN_MSG_MAP_ALT(CCustomDraw<CPropertyGridImpl>, 1)
      DEFAULT_REFLECTION_HANDLER()
   END_MSG_MAP()

   LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      LRESULT lRes = DefWindowProc();
      _Init();
      return lRes;
   }
   LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {      
      DeleteAllItems(); // Make sure we clean up all items...
      return 0;
   }
   LRESULT OnFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
   {      
      // Avoid focus-rectangle problem in ownerdrawn ListView
      _InvalidateItem(m_iSelectedRow, m_iSelectedCol);
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnScroll(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
   {      
      // HACK: When scrolling we need to destroy the in-place editor
      //       because the cursor would become out-of-sync...
      _DestroyInplaceWindow();
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      // Repaint previous item in any case
      _InvalidateItem(m_iSelectedRow, m_iSelectedCol);

      // Gather information about clicked item.
      // We need this information before the control processes the
      // actual click event...
      LVHITTESTINFO hti = { 0 };
      DWORD dwPos = ::GetMessagePos();
      POINTSTOPOINT(hti.pt, dwPos);
      ScreenToClient(&hti.pt);
      int iItem = SubItemHitTest(&hti);
      int iOldRow = m_iSelectedRow;
      int iOldColumn = m_iSelectedCol;

      // FIX: To prevent selection from jumping to colunm 0 since
      //      the DefWindowProc() below invokes LVN_ITEMCHANGED, which
      //      in turn sets the selection to the correct row (but not column)!
      m_iSelectedCol = hti.iSubItem;

      _DestroyInplaceWindow();

      // Let control process WM_LBUTTONDOWN event!
      // This may cause LVN_ITEMCHANGED to fire...
      LRESULT lRes = DefWindowProc();

      // Check if we've changed selection.
      // We delayed this to now, because we need to check
      // if we clicked on the same item...
      if( iItem != -1 ) {
         // Do click thing
         bool bIsLastAddItem = _IsLastAddItem(hti.iItem);
         if( bIsLastAddItem ) hti.iSubItem = 0;
         IProperty* prop = GetProperty(hti.iItem, hti.iSubItem);
         if( prop == NULL ) return 0;

         // Ask owner first
         NMPROPERTYITEM nmh = { m_hWnd, GetDlgCtrlID(), PIN_CLICK, prop };
         if( ::SendMessage(GetParent(), WM_NOTIFY, nmh.hdr.idFrom, (LPARAM) &nmh) == 0 ) {

            // Property is allowed to react on click event
            LPARAM lParam = ::GetMessagePos();
            prop->Activate(PACT_CLICK, lParam);

            // Set new selection...
            m_iSelectedRow = hti.iItem;
            m_iSelectedCol = hti.iSubItem;

            if( !bIsLastAddItem ) {         
               
               // Generate selection change notification on pure horizontal moves
               if( (iOldRow == m_iSelectedRow) && (iOldColumn != m_iSelectedCol) ) {
                  // Let owner know
                  NMPROPERTYITEM nmh = { m_hWnd, GetDlgCtrlID(), PIN_SELCHANGED, prop };
                  ::SendMessage(GetParent(), WM_NOTIFY, nmh.hdr.idFrom, (LPARAM) &nmh);
               }

               // Recycle in-place editor...
               if( prop->IsEnabled() ) {
                  bool fActivate = false;
                  if( iOldRow == m_iSelectedRow && iOldColumn == m_iSelectedCol ) fActivate = true;
                  if( (m_di.dwExtStyle & PGS_EX_SINGLECLICKEDIT) != 0 ) fActivate = true;
                  if( fActivate ) {
                     if( _SpawnInplaceWindow(prop, m_iSelectedRow, m_iSelectedCol) ) {
                        prop->Activate(PACT_SPACE, 0);
                     }
                     else {
                        prop->Activate(PACT_ACTIVATE, 0);
                     }
                  }
               }
            }

            // Repaint item
            _InvalidateItem(m_iSelectedRow, m_iSelectedCol);
         }
      }
      else {
         // Clicked outside list elements; remove selection...
         _DestroyInplaceWindow();
         _InvalidateItem(m_iSelectedRow, m_iSelectedCol);
         m_iSelectedRow = m_iSelectedCol = -1;
         // Let owner know
         NMPROPERTYITEM nmh = { m_hWnd, GetDlgCtrlID(), PIN_SELCHANGED, NULL };
         ::SendMessage(GetParent(), WM_NOTIFY, nmh.hdr.idFrom, (LPARAM) &nmh);
      }
      return lRes;
   }
   LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
   {      
      switch( wParam ) {
      case VK_F2:
      case VK_SPACE:
      case VK_RETURN:
         if( _IsValidSelection() ) {
            IProperty* prop = GetProperty(m_iSelectedRow, m_iSelectedCol);
            ATLASSERT(prop);
            if( prop->IsEnabled() ) {
               _SpawnInplaceWindow(prop, m_iSelectedRow, m_iSelectedCol);
               prop->Activate(PACT_SPACE, 0);
               _InvalidateItem(m_iSelectedRow, m_iSelectedCol);
            }
         }
         return 0;
      case VK_TAB:
         if( (m_di.dwExtStyle & PGS_EX_TABNAVIGATION) != 0 ) {
            SendMessage(WM_USER_PROP_NAVIGATE, VK_TAB);
         }
         else {
            ::PostMessage(GetParent(), WM_NEXTDLGCTL, ::GetKeyState(VK_SHIFT) < 0 ? 1 : 0, (LPARAM) FALSE);
         }
         return 0;
         break;
      case VK_LEFT:
      case VK_RIGHT:
         SendMessage(WM_USER_PROP_NAVIGATE, wParam);
         return 0;
      case VK_DELETE:
         if( _IsValidSelection() ) {
            IProperty* prop = GetProperty(m_iSelectedRow, m_iSelectedCol);
            ATLASSERT(prop);

⌨️ 快捷键说明

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