{ //Specify new angle. stFont.lfEscapement=nAngle; //Create and select font into dc. font.CreateFontIndirect (&stfont); CFont* pOldFont=pDC->SelectObject (&font); //Draw the text. pDC->SelectObject (pOldFont); font.DelectObjext (); } 如何让 TOOLTIP 的字体变大 前几天有个虫虫问如何让 vc4.0 的 Tooltip 的字体变大,可现在文章没有了.不过现在我 有个方法:在 Windows 95 Desktop 属性中有 desktop scheme 中有 Tooltip 一项,可以该变 TOOLTIP 的字体和大小.不过这样做所有程序的 Tooltip 都变大了.这可能不是你的本意. 但 Tooltip 是 Windows 95 Common Control,由 Windows 95 内部实现,VC4.0 的 CTooltip 类并不实现 Tips 的显示,所以要实现针对某个程序的 Tooltip 的特殊显示,有一定难度.我以前曾经试图实现 Tooltip 的多行显示,做到了当 Toolt. 显示时触发我的函数,消失时触发我的函数,但在显示时却出 GP 错误.现在我认为最简 单的方法是从头自己实现 Tooltip 类.一切随心所欲.* 在 TreeList 中使用 Edit 功能 首先了讲该 TreeList 应该使用 TVS_EDITLABELS 风格,可以在创建资源时指定,或者在使用 Create 时指定,或者在 PreCreateWindos()中改变。 接下来需要处理 TVN_BEGINLABELEDIT 和 TVN_ENDLABELEDIT 消息。 void CXXXX::OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; // Limit text length GetEditControl()->LimitText(127); *pResult = 0; } 如果不处理 TVN_ENDLABELEDIT 消息,则文本的更改不会生效。 void COutline::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) { GetEditControl()->GetWindowText(s); // Set result to TRUE to accept the changes *pResult = TRUE; } TreeList control 中使用 check box 方法很简单,一句话总结:定义用户定义状态,并对不同的状态(state)使用不同的图片。 在下面的 sample 中,我们使用 CTreeListCtrl 作为父类。由于 TreeList control 支持一些现有 state 所以用户定义的 state 必需 使用 INDEXTOSTATEIMAGEMASK(i)进行变换。 如果对本文所讲的方法有不明的地方,可以先熟悉一下 TreeList Control 的使用,然后再看本文。 Step 1: 创建 state list image 创建的图片有三种状态。 state ImageList 只是用于和 state 改变有关的显示图片,TreeList Control 中还应包含其他 image List,如:焦点选择改变的 imageList,用于在选中和未选中是改变显示图片。 Step 2: 初始化 CImageList m_imageState; 成员变量 m_imageState.Create( IDB_STATE, 13, 1, RGB(255,255,255) );//创建 ImageList m_tree.SetImageList( &(m_tree.m_imageState), TVSIL_STATE );//在 TreeList 中加入表示状态的 ImageList。 Step 3: 增加结点时设置标记 重新定义一个 InsertItem 函数。使用 TV_INSERTSTRUCT 来插入结点。 即使用函数 HTREEITEM InsertItem( LPTV_INSERTSTRUCT lpInsertStruct ); lpInsertStruct->item.mask |= TVIF_STATE ;//保证 state 和 stateMask 是有效的。 你必须在 TV_ITEM 中标明 state 和 stateMask。( INDEXTOSTATEIMAGEMASK 宏可以得到 state image 的下标) state 设置为 INDEXTOSTATEIMAGEMASK(1)表示用户定义的第一种状态 stateMask 设置为 TVIS_STATEIMAGEMASK.表示用户定义的状态。 当然也可以调用 SetItemState 设置 state. SetItemState( hItem, INDEXTOSTATEIMAGEMASK(1), TVIS_STATEIMAGEMASK ); Step 4: 增加 mouse button down 消息映射 通过使用 HitTest 来得知是否按在 State 图片上。并需要得到当前 state。 void CTreeCtrlX::OnLButtonDown(UINT nFlags, CPoint point) { UINT uFlags=0; HTREEITEM hti = HitTest(point,&uFlags); if( uFlags & TVHT_ONITEMSTATEICON ) { int iImage = GetItemState( hti, TVIS_STATEIMAGEMASK )>>12; //GetItemState( hti, TVIS_STATEIMAGEMASK )>>12 对用户定义 state 反变换 SetItemState( hti, INDEXTOSTATEIMAGEMASK(iImage == 1 ? 2 : 1), TVIS_STATEIMAGEMASK ); return; } } Step 5:处理 OnKeyDown void CTreeCtrlX::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if( nChar == VK_SPACE ) { HTREEITEM hti = GetSelectedItem(); int iImage = GetItemState( hti, TVIS_STATEIMAGEMASK )>>12; SetItemState( hti, INDEXTOSTATEIMAGEMASK(iImage == 1 ? 2 : 1), TVIS_STATEIMAGEMASK ); return; } } Step 6: 增加其他的功能函数 BOOL CTreeCtrlX::IsItemChecked(HTREEITEM hItem) { return GetItemState( hItem, TVIS_STATEIMAGEMASK )>>12 == 2; } HTREEITEM CTreeCtrlX::GetFirstCheckedItem() { for ( HTREEITEM hItem = GetRootItem(); hItem!=NULL; hItem = GetNextItem( hItem ) ) if ( IsItemChecked(hItem) ) return hItem; return NULL; } HTREEITEM CTreeCtrlX::GetNextCheckedItem( HTREEITEM hItem ) { for ( hItem = GetNextItem( hItem ); hItem!=NULL; hItem = GetNextItem( hItem ) ) if ( IsItemChecked(hItem) ) return hItem; return NULL; } HTREEITEM CTreeCtrlX::GetPrevCheckedItem( HTREEITEM hItem ) { for ( hItem = GetPrevItem( hItem ); hItem!=NULL; hItem = GetPrevItem( hItem ) ) if ( IsItemChecked(hItem) ) return hItem; return NULL; } 可以使用 Drag&Drop 的 CTreeView CTreeViewExt 是 MFC 使用者可重用的类,该类由 CTreeView 派生,可以用在文档-视结构的应用程序中,并且支持 Drag&Drop。 使用者所需要做的仅仅是将文件加到 AppWizard 产生的工程中,(CTreeView 为基类)并且将 CTreeView 替换为 CTreeViewExt。 并重载三个 Virtual Function。 (WenYY:这很简单吧,下面是源代码,我会在必要的地方加上注释,但由于原作者并未加,所以如果有出入请原谅,作者定 义了三处虚拟函数,其作用是让使用者重载后,加入自己的判断条件和结果处理的功能,很巧妙的思想: CopyItemProperties IsItemCanBeDroppedOn(HTREEITEM hSource, HTREEITEM hTarget); BOOL ItemCanBeDragged(HTREEITEM hItem);//检查是否可以对该 ITEM 实施 Drag&Drop ) Header file #if !defined(AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_) #define AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 // TreeViewExt.h : header file // ///////////////////////////////////////// // CTreeViewExt view class CTreeViewExt : public CTreeView { protected: CTreeViewExt(); // protected constructor used by dynamic creation DECLARE_DYNCREATE(CTreeViewExt) // Attributes public: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CTreeViewExt) protected: virtual void OnDraw(CDC* pDC); // overridden to draw this view //}}AFX_VIRTUAL // Implementation protected: HTREEITEM m_hDraggedItem; BOOL m_bDraggingNow; //标记 CImageList *m_pDragImageList; virtual ~CTreeViewExt(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif // Generated message map functions protected: virtual void CopyItemProperties(HTREEITEM hNewItem, HTREEITEM hDraggedItem); virtual BOOL IsItemCanBeDroppedOn(HTREEITEM hSource, HTREEITEM hTarget); virtual BOOL ItemCanBeDragged(HTREEITEM hItem);//检查是否可以对该 ITEM 实施 Drag&Drop //{{AFX_MSG(CTreeViewExt) afx_msg void OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult);//必须重载的函数 afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; ///////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately before the previous line. #endif // !defined(AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_) Implementation file // TreeViewExt.cpp : implementation file // #include "stdafx.h" #include "TreeViewExt.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////// // CTreeViewExt IMPLEMENT_DYNCREATE(CTreeViewExt, CTreeView) CTreeViewExt::CTreeViewExt() { m_bDraggingNow = FALSE; m_hDraggedItem = NULL; m_pDragImageList = NULL; } CTreeViewExt::~CTreeViewExt() { } BEGIN_MESSAGE_MAP(CTreeViewExt, CTreeView) //{{AFX_MSG_MAP(CTreeViewExt) ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag) ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////// // CTreeViewExt drawing void CTreeViewExt::OnDraw(CDC* pDC) { CDocument* pDoc = GetDocument(); // TODO: add draw code here } ///////////////////////////////////////// // CTreeViewExt diagnostics #ifdef _DEBUG void CTreeViewExt::AssertValid() const { CTreeView::AssertValid(); } void CTreeViewExt::Dump(CDumpContext& dc) const { CTreeView::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////// // CTreeViewExt message handlers void CTreeViewExt::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; if (!m_bDraggingNow) {//先检查是否正在过程中 if (ItemCanBeDragged(pNMTreeView->itemNew.hItem)) {//查询条件,是否允许 Drag&Drop CTreeCtrl& tree = GetTreeCtrl(); tree.SetCapture(); m_bDraggingNow = TRUE; m_hDraggedItem = pNMTreeView->itemNew.hItem;//保存变量 tree.Select(m_hDraggedItem, TVGN_CARET); m_pDragImageList = tree.CreateDragImage(m_hDraggedItem); m_pDragImageList->DragEnter(&tree, pNMTreeView->ptDrag); m_pDragImageList->BeginDrag(0, CPoint(0, 0)); } } *pResult = 0; } void CTreeViewExt::OnMouseMove(UINT nFlags, CPoint point) { if (m_bDraggingNow) { CTreeCtrl& tree = GetTreeCtrl(); m_pDragImageList->DragEnter(&tree, point); m_pDragImageList->DragMove(point); } CTreeView::OnMouseMove(nFlags, point); } void CTreeViewExt::OnLButtonUp(UINT nFlags, CPoint point) { if (m_bDraggingNow) { ReleaseCapture(); m_bDraggingNow = FALSE; m_pDragImageList->EndDrag(); delete m_pDragImageList; m_pDragImageList = NULL; CTreeCtrl& tree = GetTreeCtrl(); UINT flags; HTREEITEM hTargetItem = tree.HitTest(point, &flags);//得到目标 if (hTargetItem != NULL && IsItemCanBeDroppedOn(m_hDraggedItem, hTargetItem)) {//查询是否可以成功完成,条件是开始时选中的 Item 和结束使选中的 ITEM 是否满足你的条件 HTREEITEM hNewItem = tree.InsertItem("Untitled", hTargetItem); CopyItemProperties(hNewItem, m_hDraggedItem);//进行处理 if (nFlags != MK_CONTROL) tree.DeleteItem(m_hDraggedItem); } m_hDraggedItem = NULL; } CTreeView::OnLButtonUp(nFlags, point); } BOOL CTreeViewExt::ItemCanBeDragged(HTREEITEM hItem) {//作用为决定现在是否能开始,可以作为一种运行时的选项 return FALSE; } BOOL CTreeViewExt::IsItemCanBeDroppedOn(HTREEITEM hSource, HTREEITEM hTarget) {//决定现在结束条件是否正常,如不正常则放弃这次操作 return FALSE; } void CTreeViewExt::CopyItemProperties(HTREEITEM hNewItem, HTREEITEM hDraggedItem) {//按照你的需要对两个 ITEM 进行处理。 } 有关属性对话框(property sheet )的几个提示 下面的所有例子,都假定你从 CPropertySheet 中派生了新类。 1、隐藏 APPLY 按钮 使用 PSH_NOAPPLYNOW 标志. propsheet.m_psh.dwFlags |= PSH_NOAPPLYNOW; 2、增加新的子窗口 使用成员变量。CEdit m_edit. BOOL CMyPropSheet::OnInitDialog() { BOOL bResult = CPropertySheet::OnInitDialog(); CRect rectWnd; GetWindowRect(rectWnd); SetWindowPos(NULL, 0, 0, rectWnd.Width() + 100, rectWnd.Height(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); m_edit.CreateEx( WS_EX_CLIENTEDGE, _T("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER, rectWnd.Width(), 20, 80, 24, m_hWnd, 0, 0 ); m_edit.SetFont( GetFont() ); CenterWindow(); return bResult; } 3、改变页片上的字体 在 OnInitDialog() 中: // m_fontEdit is a member variable // Create a bold font m_fontEdit.CreateFont( -8, 0, 0, 0, 700, 0, 0, 0, 1, 0, 0, 0, 0, _T("MS Sans Serif") ); GetTabControl()->SetFont( &m_fontEdit ); 4、使用 Image m_imageTab 为成员变量。 BOOL CMyPropSheet::OnInitDialog() { BOOL bResult = CPropertySheet::OnInitDialog(); m_imageTab.Create( IDB_TABIMAGES, 13, 1, RGB(255,255,255) ); CTabCtrl *pTab = GetTabControl(); pTab->SetImageList( &m_imageTab ); TC_ITEM tcItem; tcItem.mask = TCIF_IMAGE; for( int i = 0; i <3; i++ ) { tcItem.iImage = i; pTab->SetItem( i, &tcItem ); } return bResult; } 为 TreeCtrl 中的项增加 ToolTip 要点:通过 OnToolHitTest 来增加 ToolTip,CTreeCtrl::HitTest(...)的使用,TTN_NEEDTEXT 消息的处理。 定义一个新类,有 CTreeCtrl 派生 Step 1:打开 ToolTip 功能 void CTreeCtrlX::PreSubclassWindow() { CTreeCtrl::PreSubclassWindow(); EnableToolTips(TRUE); } Step 2: OnToolHitTest() 的重载 首先通过 HitTest 决定是否增加 ToolTip,如果需要则返回非零。 在本例中 ToolTip 使用了 LPSTR_TEXTCALLBACK,而没有立即设定显示字符串。 在本例只在鼠标指向每项的图片时才显示 ToolTip int CTreeCtrlX::OnToolHitTest(CPoint point, TOOLINFO * pTI) const { RECT rect; UINT nFlags; HTREEITEM hitem = HitTest( point, &nFlags ); if( nFlags & TVHT_ONITEMICON ) { CImageList *pImg = GetImageList( TVSIL_NORMAL ); IMAGEINFO imageinfo; pImg->GetImageInfo( 0, &imageinfo ); GetItemRect( hitem, &rect, TRUE ); rect.right = rect.left - 2; rect.left -= (imageinfo.rcImage.right + 2); pTI->hwnd = m_hWnd; pTI->uId = (UINT)hitem; pTI->lpszText = LPSTR_TEXTCALLBACK; pTI->rect = rect; return pTI->uId; } else if( nFlags & TVHT_ONITEMSTATEICON ) { CImageList *pImg = GetImageList( TVSIL_NORMAL ); IMAGEINFO imageinfo; pImg->GetImageInfo( 0, &imageinfo ); GetItemRect( hitem, &rect, TRUE ); rect.right = rect.left - (imageinfo.rcImage.right + 2); pImg = GetImageList( TVSIL_STATE ); rect.left = rect.right - imageinfo.rcImage.right ; pTI->hwnd = m_hWnd; pTI->uId = (UINT)hitem; pTI->lpszText = LPSTR_TEXTCALLBACK; pTI->rect = rect; // return value should be different from that used for item icon return pTI->uId*2; } return -1; } Step 3: ?? TTN_NEEDTEXT 由于在增加 ToolTip 是使用用了 LPSTR_TEXTCALLBACK,因此 ToolTip 在显示时会发送该消息来得到显示字符串。 BEGIN_MESSAGE_MAP(CTreeCtrlX, CTreeCtrl) //{{AFX_MSG_MAP(CTreeCtrlX) //}}AFX_MSG_MAP ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText) END_MESSAGE_MAP() protected: //{{AFX_MSG(CTreeCtrlX) //}}AFX_MSG afx_msg BOOL OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult ); DECLARE_MESSAGE_MAP() BOOL CTreeCtrlX::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult ) { // need to handle both ANSI and UNICODE versions of the message TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR; TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR; CString strTipText; UINT nID = pNMHDR->idFrom; // Do not process the message from built in tooltip if( nID == (UINT)m_hWnd && (( pNMHDR->code == TTN_NEEDTEXTA && pTTTA->uFlags & TTF_IDISHWND ) || ( pNMHDR->code == TTN_NEEDTEXTW && pTTTW->uFlags & TTF_IDISHWND ) ) ) return FALSE; // Get the mouse position const MSG* pMessage; CPoint pt; pMessage = GetCurrentMessage(); ASSERT ( pMessage ); pt = pMessage->pt; ScreenToClient( &pt ); UINT nFlags; HTREEITEM hitem = HitTest( pt, &nFlags ); if( nFlags & TVHT_ONITEMICON ) { int nImage, nSelImage; GetItemImage( (HTREEITEM ) nID, nImage, nSelImage ); strTipText.Format( "Image : %d", nImage ); } else { strTipText.Format( "State : %d", GetItemState( (HTREEITEM ) nID, TVIS_STATEIMAGEMASK ) ); } #ifndef _UNICODE if (pNMHDR->code == TTN_NEEDTEXTA) lstrcpyn(pTTTA->szText, strTipText, 80); else _mbstowcsz(pTTTW->szText, strTipText, 80); #else if (pNMHDR->code == TTN_NEEDTEXTA) _wcstombsz(pTTTA->szText, strTipText, 80); else lstrcpyn(pTTTW->szText, strTipText, 80); #endif *pResult = 0; return TRUE; // message was handled } 在 MFC 加入"这是什么?"的帮助提示 MFC 在 CPropertySheet 中封装了属性,但不支持标题的"这是什么?"帮助提示.函数 CPropertySheet::OnNcCreate()屏蔽了扩展风 格 WS_EX_CONTEXTHELP, 因此,即使你在构造函数中加入了扩展风格,它也不能出现在窗口中. 解决方法很简单,在继承类中设置好风格位,如下所示: BOOL CWhatsThisPropertySheet::OnNcCreate( LPCREATESTRUCT lpCreateStruct) ( if(!CPropertySheet::OnNcCreate(lpCreateStruct)) return FALSE; //显式地定义此风格 //CPropertySheet 默认是关 ModifyStyleEx(0, WS_EX_CONTEXTHELP); return true; ) 精通工具条 VC++的工具条有很多特性,但有时候也会让你感到困惑. 这里有一些使它们服服贴贴的小技巧. 要移走一个工具条项,只须将它拖到空工具条的右边,然后点击右上角的关闭按钮. 注意显示在浮动工具条菜单条上的工具条的名称,可以通过右击菜单条来关闭 一个工具条,使之挂起. 反过来,激活一个挂起的工具条,右击你菜单条或另一个工具条,然后选中 你想看到的工具条的名字. 如果你想同时开关好几个工具条,不用一个一个地去右击,使用菜单上的工具, 用户化菜单命令,会出现工具条制表顺序对话框, 然后进行选择. 这个对话框也允许挂起干扰你的工具条,或者增大看不见工具条按钮的图标. 你可以在调试时使用和编辑代码时不同的工具条布局,而二者不互相干扰. 当你发现浮动工具条停在不期望的位置时,按住 Ctrl 键,然后用鼠标将它移到旁边去, 当你停下来的时候,它不再回去,即使你 把它放在另一个工具条的上面. 如何改变视窗的背景颜色 Windows 向窗口发送一个 WM_ERASEBKGND 消息通知该窗口擦除背景,可以使用 ClassWizard 重载该消息的缺省处理程序来擦除背景(实际是画),并返回 TRUE 以 防止 Windows 擦除窗口。 //Paint area that needs to be erased. BOOL CSampleView : : OnEraseBkgnd (CDC* pDC) { // Create a pruple brush. CBrush Brush (RGB (128 , 0 , 128) ); // Select the brush into the device context . CBrush* pOldBrush = pDC—>SelcetObject (&brush); // Get the area that needs to be erased . CRect reClip ; pDC—>GetCilpBox (&rcClip); //Paint the area. pDC—> PatBlt (rcClip.left , rcClip.top , rcClip.Width ( ) , rcClip.Height ( ) , PATCOPY ); //Unselect brush out of device context . pDC—>SelectObject (pOldBrush ); // Return nonzero to half fruther processing . return TRUE; } 为 MFC 应用程序添加全屏幕显示功能 在 CMainFrame 类中添加下列成员变量和成员函数(使用 ClassWizard),下面是这些变量和函数的功能说明: 成员变量: BOOL m_bFullScreen; //全屏幕显示标志 CRect m_FullScreenWindowRect; //全屏幕显示窗口 Rect WINDOWPLACEMENT m_wpPrev; //用于保存正常视图时的窗口位置信息 CToolBar * m_wndFullScreenBar; //全屏幕显示时的浮动工具条 成员函数: void OnMenuFullscreen(); //全屏幕显示的处理函数 void OnGetMinMaxInfo(); //捕获 WM_GETMINMAXINFO 消息以便允许你增加窗口大小 void OnUpdateViewFullScreen(); //更新“全屏幕显示”菜单的状态 源码 void CMainFrame::OnMenuFullscreen() {//全屏幕显示的处理函数 RECT rectDesktop; WINDOWPLACEMENT wpNew; if (m_bFullScreen) {//全屏幕显示模式 //隐藏工具条和状态条 m_wndStatusBar.ShowWindow(SW_HIDE); m_wndToolBar.ShowWindow(SW_HIDE); //保存正常视图时的窗口位置信息以便恢复原来状态 GetWindowPlacement (&m_wpPrev); m_wpPrev.length = sizeof m_wpPrev; //调整 RECT 为新的窗口尺寸 ::GetWindowRect ( ::GetDesktopWindow(), &rectDesktop ); ::AdjustWindowRectEx(&rectDesktop, GetStyle(), TRUE, GetExStyle()); //保存 RECT 以便 OnGetMinMaxInfo()使用 m_FullScreenWindowRect = rectDesktop; wpNew = m_wpPrev; wpNew.showCmd = SW_SHOWNORMAL; wpNew.rcNormalPosition = rectDesktop; //生成新的工具条 m_wndFullScreenBar=new CToolBar; if(!m_wndFullScreenBar->Create(this, CBRS_SIZE_DYNAMIC|CBRS_FLOATING) || !m_wndFullScreenBar->LoadToolBar(IDR_FULLSCREEN)) { TRACE0("Failed to create toolbar\n"); return; // fail to create } //不允许工具条停泊 m_wndFullScreenBar->EnableDocking(FALSE); m_wndFullScreenBar->SetWindowPos(0,100,100,0,0,SWP_NOSIZE |SWP_NOZORDER|SWP_NOACTIVATE|SWP_SHOWWINDOW); m_wndFullScreenBar->SetWindowText(_T("全屏幕显示")); FloatControlBar(m_wndFullScreenBar, CPoint(100,100)); m_bFullScreen=TRUE; } else {//正常显示模式 //删除全屏幕工具条 m_wndFullScreenBar->DestroyWindow(); delete m_wndFullScreenBar; m_bFullScreen=FALSE; //恢复工具条和状态条 m_wndStatusBar.ShowWindow(SW_SHOWNORMAL); m_wndToolBar.ShowWindow(SW_SHOWNORMAL); wpNew = m_wpPrev; } //设置窗口显示状态 SetWindowPlacement ( &wpNew ); } void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { if (m_bFullScreen) { lpMMI->ptMaxSize.y = m_FullScreenWindowRect.Height(); lpMMI->ptMaxTrackSize.y = lpMMI->ptMaxSize.y; lpMMI->ptMaxSize.x = m_FullScreenWindowRect.Width(); lpMMI->ptMaxTrackSize.x = lpMMI->ptMaxSize.x; } } void CMainFrame::OnUpdateMenuFullscreen(CCmdUI* pCmdUI) {//更新菜单的状态 pCmdUI->Enable(); pCmdUI->SetCheck(m_bFullScreen); } VC 常用数据类型使用转换详解 我们先定义一些常见类型变量借以说明 int i = 100; long l = 2001; float f=300.2; double d=12345.119; char username[]="女侠程佩君"; char temp[200]; char *buf; CString str; _variant_t v1; _bstr_t v2; 一、其它数据类型转换为字符串 短整型(int) itoa(i,temp,10);///将 i 转换为字符串放入 temp 中,最后一个数字表示十进制 itoa(i,temp,2); ///按二进制方式转换 长整型(long) ltoa(l,temp,10); 二、从其它包含字符串的变量中获取指向该字符串的指针 CString 变量 str = "2008 北京奥运"; buf = (LPSTR)(LPCTSTR)str; BSTR 类型的_variant_t 变量 v1 = (_bstr_t)"程序员"; buf = _com_util::ConvertBSTRToString((_bstr_t)v1); 三、字符串转换为其它数据类型 strcpy(temp,"123"); 短整型(int) i = atoi(temp); 长整型(long) l = atol(temp); 浮点(double) d = atof(temp); 四、其它数据类型转换到 CString 使用 CString 的成员函数 Format 来转换,例如: 整数(int) str.Format("%d",i); 浮点数(float) str.Format("%f",i); 字符串指针(char *)等已经被 CString 构造函数支持的数据类型可以直接赋值 str = username; 五、BSTR、_bstr_t 与 CComBSTR CComBSTR、_bstr_t 是对 BSTR 的封装,BSTR 是指向字符串的 32 位指针。 char *转换到 BSTR 可以这样: BSTR b=_com_util::ConvertStringToBSTR("数据");///使用前需要加上头文件 comutil.h 反之可以使用 char *p=_com_util::ConvertBSTRToString(b); 六、VARIANT 、_variant_t 与 COleVariant VARIANT 的结构可以参考头文件 VC98\Include\OAIDL.H 中关于结构体 tagVARIANT 的定义。 对于 VARIANT 变量的赋值:首先给 vt 成员赋值,指明数据类型,再对联合结构中相同数据类型的变量赋值,举个例子: VARIANT va; int a=2001; va.vt=VT_I4;///指明整型数据 va.lVal=a; ///赋值 对于不马上赋值的 VARIANT,最好先用 Void VariantInit(VARIANTARG FAR* pvarg);进行初始化,其本质是将 vt 设置为 VT_EMPTY,下表我们列举 vt 与常用数据的对应关系: unsigned char bVal; VT_UI1 short iVal; VT_I2 long lVal; VT_I4 float fltVal; VT_R4 double dblVal; VT_R8 VARIANT_BOOL boolVal; VT_BOOL SCODE scode; VT_ERROR CY cyVal; VT_CY DATE date; VT_DATE BSTR bstrVal; VT_BSTR IUnknown FAR* punkVal; VT_UNKNOWN IDispatch FAR* pdispVal; VT_DISPATCH SAFEARRAY FAR* parray; VT_ARRAY|* unsigned char FAR* pbVal; VT_BYREF|VT_UI1 short FAR* piVal; VT_BYREF|VT_I2 long FAR* plVal; VT_BYREF|VT_I4 float FAR* pfltVal; VT_BYREF|VT_R4 double FAR* pdblVal; VT_BYREF|VT_R8 VARIANT_BOOL FAR* pboolVal; VT_BYREF|VT_BOOL SCODE FAR* pscode; VT_BYREF|VT_ERROR CY FAR* pcyVal; VT_BYREF|VT_CY DATE FAR* pdate; VT_BYREF|VT_DATE BSTR FAR* pbstrVal; VT_BYREF|VT_BSTR IUnknown FAR* FAR* ppunkVal; VT_BYREF|VT_UNKNOWN IDispatch FAR* FAR* ppdispVal; VT_BYREF|VT_DISPATCH SAFEARRAY FAR* FAR* pparray; VT_ARRAY|* VARIANT FAR* pvarVal; VT_BYREF|VT_VARIANT void FAR* byref; VT_BYREF _variant_t 是 VARIANT 的封装类,其赋值可以使用强制类型转换,其构造函数会自动处理这些数据类型。 例如: long l=222; ing i=100; _variant_t lVal(l); lVal = (long)i; COleVariant 的使用与_variant_t 的方法基本一样,请参考如下例子: COleVariant v3 = "字符串", v4 = (long)1999; CString str =(BSTR)v3.pbstrVal; long i = v4.lVal; 七、其它 对消息的处理中我们经常需要将 WPARAM 或 LPARAM 等 32 位数据(DWORD)分解成两个 16 位数据(WORD),例如: LPARAM lParam; WORD loValue = LOWORD(lParam);///取低 16 位 WORD hiValue = HIWORD(lParam);///取高 16 位 对于 16 位的数据(WORD)我们可以用同样的方法分解成高低两个 8 位数据(BYTE),例如: WORD wValue; BYTE loValue = LOBYTE(wValue);///取低 8 位 BYTE hiValue = HIBYTE(wValue);///取高 8 位 后记:本文匆匆写成,错误之处在所难免,欢迎来信指正. Email:appleII@sohu.com 用 Visual C++操作 INI 文件 一.将信息写入.INI 文件中. 1.所用的 WINAPI 函数原型为: BOOL WritePrivateProfileString( LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpString, LPCTSTR lpFileName ); 其中各参数的意义: LPCTSTR lpAppName 是 INI 文件中的一个字段名. LPCTSTR lpKeyName 是 lpAppName 下的一个键名,通俗讲就是变量名. LPCTSTR lpString 是键值,也就是变量的值,不过必须为 LPCTSTR 型或 CString 型的. LPCTSTR lpFileName 是完整的 INI 文件名. 2.具体使用方法:设现有一名学生,需把他的姓名和年龄写入 c:\stud\student.ini 文件中. CString strName,strTemp; int nAge; strName="张三"; nAge=12; ::WritePrivateProfileString("StudentInfo","Name",strName,"c:\\stud\\student.ini"); 此时 c:\stud\student.ini 文件中的内容如下: [StudentInfo] Name=张三 3.要将学生的年龄保存下来,只需将整型的值变为字符型即可: strTemp.Format("%d",nAge); ::WritePrivateProfileString("StudentInfo","Age",strTemp,"c:\\stud\\student.ini"); 二.将信息从 INI 文件中读入程序中的变量. 1.所用的 WINAPI 函数原型为: DWORD GetPrivateProfileString( LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName ); 其中各参数的意义: 前二个参数与 WritePrivateProfileString 中的意义一样. lpDefault : 如果 INI 文件中没有前两个参数指定的字段名或键名,则将此值赋给变量. lpReturnedString : 接收 INI 文件中的值的 CString 对象,即目的缓存器. nSize : 目的缓存器的大小. lpFileName : 是完整的 INI 文件名. 2.具体使用方法:现要将上一步中写入的学生的信息读入程序中. CString strStudName; int nStudAge; GetPrivateProfileString("StudentInfo","Name"," 默认姓名 ",strStudName.GetBuffer(MAX_PATH),MAX_PATH,"c:\\stud\\student.ini"); 执行后 strStudName 的值为:"张三",若前两个参数有误,其值为:"默认姓名". 3.读入整型值要用另一个 WINAPI 函数: UINT GetPrivateProfileInt( LPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault, LPCTSTR lpFileName ); 这里的参数意义与上相同.使用方法如下: nStudAge=GetPrivateProfileInt("StudentInfo","Age",10,"c:\\stud\\student.ini"); 三.循环写入多个值,设现有一程序,要将最近使用的几个文件名保存下来,具体程序如下: 1.写入: CString strTemp,strTempA; int i; int nCount=6; file://共有 6 个文件名需要保存 for(i=0;i
贡献于2013-06-17