zoukankan      html  css  js  c++  java
  • (转)MFC技巧学习<六>

    66. 解决外部符号错误:_main,_WinMain@16,__beginthreadex
    在创建MFC项目时, 不使用MFC AppWizard向导, 如果没有设置好项目参数, 就会在编译时产生很多连接错误, 如error LNK2001错误, 典型的错误提示有:
    libcmtd.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
    LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol _WinMain@16
    msvcrtd.lib(crtexew.obj) : error LNK2001: unresolved external symbol _WinMain@16
    nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
    nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
    下面介绍解决的方法:
    1). Windows子系统设置错误, 提示:
    libcmtd.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
    Windows项目要使用Windows子系统, 而不是Console, 可以这样设置:
    [Project] --> [Settings] --> 选择"Link"属性页,
    在Project Options中将/subsystem:console改成/subsystem:windows
    2). Console子系统设置错误, 提示:
    LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol _WinMain@16
    控制台项目要使用Console子系统, 而不是Windows, 设置:
    [Project] --> [Settings] --> 选择"Link"属性页,
    在Project Options中将/subsystem:windows改成/subsystem:console
    3). 程序入口设置错误, 提示:
    msvcrtd.lib(crtexew.obj) : error LNK2001: unresolved external symbol _WinMain@16
    通常, MFC项目的程序入口函数是WinMain, 如果编译项目的Unicode版本, 程序入口必须改为wWinMainCRTStartup, 所以需要重新设置程序入口:
    [Project] --> [Settings] --> 选择"C/C++"属性页,
    在Category中选择Output,
    再在Entry-point symbol中填入wWinMainCRTStartup, 即可
    4). 线程运行时库设置错误, 提示:
    nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
    nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
    这是因为MFC要使用多线程时库, 需要更改设置:
    [Project] --> [Settings] --> 选择"C/C++"属性页,
    在Category中选择Code Generation,
    再在Use run-time library中选择Debug Multithreaded或者multithreaded
    其中,
    Single-Threaded单线程静态链接库(release版本)
    Multithreaded多线程静态链接库(release版本)
    multithreaded DLL多线程动态链接库(release版本)
    Debug Single-Threaded单线程静态链接库(debug版本)
    Debug Multithreaded多线程静态链接库(debug版本)
    Debug Multithreaded DLL多线程动态链接库(debug版本)
    单线程: 不需要多线程调用时, 多用在DOS环境下
    多线程: 可以并发运行
    静态库: 直接将库与程序Link, 可以脱离MFC库运行
    动态库: 需要相应的DLL动态库, 程序才能运行
    release版本: 正式发布时使用
    debug版本: 调试阶段使用

    67. 创建包含多个子目录的目录

    void CreateAllDirectories(CString strDir)
    {
    //remove ending / if exists
    if(strDir.Right(1)=="\\")
     strDir=strDir.Left(strDir.GetLength()-1); 
    // base case . . .if directory exists
    if(GetFileAttributes(strDir)!=-1) 
     return;
    // recursive call, one less directory
    int nFound = strDir.ReverseFind('\\');
    CreateAllDirectories(strDir.Left(nFound)); 
    // actual work
    CreateDirectory(strDir,NULL); 
    }


    68. ReverseFind()

    #include <STDIO.H>
    #include <AFX.H>
    int main()
    {
      CString s;
      s.Format("abcdefghijk");
      int nPos = s.ReverseFind('a');
      printf("nPos is %d\n",nPos);
      return 0;
    }

    其中,'a'对应的nPos是0,'h'对应的nPos是7,以此类推。但是:s.ReverseFind('a')和s.Find('a')的结果是一样的。
    问题是:ReverseFind() 和 Find() 有什么区别呢:
    对于ReverseFind(),查找顺序是从后往前,找到后的nPos是按前后顺序排列的。
    而Find()是从前往后查的,找到后的nPos也是按前后顺序排列的。


    69. MDI中如何只屏蔽掉子框架的右上角的关闭按钮

    int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
    {
      if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1)
        return -1;
    。。。
      CMenu* pSysMenu = GetSystemMenu(FALSE);
      pSysMenu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND |MF_DISABLED|MF_GRAYED);
      return 0;
    }


    70. 程序如何删除自己

    /////////////////////////////////////////////////
    int WINAPI WinMain(HINSTANCE h, HINSTANCE b, LPSTR psz, int n) {
    // Is this the Original EXE or the clone EXE?
    // If the command-line 1 argument, this is the Original EXE
    // If the command-line >1 argument, this is the clone EXE
    if (__argc == 1) {
    // Original EXE: Spawn clone EXE to delete this EXE
    // Copy this EXEcutable image into the user''s temp directory
    TCHAR szPathOrig[_MAX_PATH], szPathClone[_MAX_PATH];
    GetModuleFileName(NULL, szPathOrig, _MAX_PATH);
    GetTempPath(_MAX_PATH, szPathClone);
    GetTempFileName(szPathClone, __TEXT("Del"), 0, szPathClone);
    CopyFile(szPathOrig, szPathClone, FALSE);
    //***注意了***:
    // Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE
    HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL, OPEN_EXISTI
    NG, FILE_FLAG_DELETE_ON_CLOSE, NULL);
    // Spawn the clone EXE passing it our EXE''s process handle
    // and the full path name to the Original EXE file.
    TCHAR szCmdLine[512];
    HANDLE hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE, GetCurrentProcessId());
    wsprintf(szCmdLine, __TEXT("%s %d \"%s\""), szPathClone, hProcessOrig, szPat
    hOrig);
    STARTUPINFO si;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    PROCESS_INFORMATION pi;
    CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
    CloseHandle(hProcessOrig);
    CloseHandle(hfile);
    // This original process can now terminate.
    } else {
    // Clone EXE: When original EXE terminates, delete it
    HANDLE hProcessOrig = (HANDLE) _ttoi(__targv[1]);
    WaitForSingleObject(hProcessOrig, INFINITE);
    CloseHandle(hProcessOrig);
    DeleteFile(__targv[2]);
    // Insert code here to remove the subdirectory too (if desired).
    // The system will delete the clone EXE automatically
    // because it was opened with FILE_FLAG_DELETE_ON_CLOSE
    }
    return(0);
    }

      这一段程序思路很简单:不是不能在运行时直接删除本身吗?好,那么程序先复制(CLONE)一个自己,用复制品起动另一个进程,然后自己结束运行,则原来的EXE文件不被系统保护.这时由新进程作为杀手删除原来的EXE文件,并且继续完成程序其他的功能。
      新进程在运行结束后,复制品被自动删除。这又是值得介绍的一个把戏了,注意:

    // Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE
    HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL,OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);

      这里面的FILE_FLAG_DELETE_ON_CLOSE标志,这个标志是告诉操作系统,当和这个文件相关的所有句柄都被关闭之后(包括上面这个CREATEFILE创建的句炳),就把这个文件删除。几乎所有的临时文件在创建时,都指明了这个标志。另外要注意的是:在复制品进程对原始程序操刀之前,应该等待原进程退出.在这里用的是进程同步技术.用

    HANDLE hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE,GetCurrentProcessId());

    得到原进程句柄.SYNCHRONICE标志在NT下有效,作用是使OpenProcess得到的句柄可以做为同步对象.复制品进程用WaitForSingleObject函数进行同步,然后一个DeleteFile,以及进行其它销毁证据(比如删目录)的工作,一切就完事了。
      程序是基于CONSOLE的,通过传入的参数确定是原始的进程还是复制品新进程,并且得到需要操作的目标文件的信息(主要是路径),复制品放在系统的TEMP目录(GetTempPath得到),你也可以随便找个你认为安全的地方(比如:WINDOWS\SYSTEM32等等)。这里面没有甚么深的技术.再看其他的一些实现删除自己的例子,比如说在进程退出前,用fwrite等方法输出一个.BAT文件,在里面写几句DEL,然后WINEXEC一下这个BAT文件即可.玩儿过DOS的虫虫大多都会。

    71. 隐藏标题栏和菜单栏
    隐藏标题栏 ModifyStyle(WS_CAPTION,0)
    隐藏菜单栏 SetMenu(NULL)

    72. InflateRect
    InflateRect这个函数用于增大或减小一个矩形的大小.如

    m_graphRect.InflateRect(-70, -30, -30, -50);

    将矩形左边坐标加70,上面加30,右边减30,下面减50。

    73. 怎么让无模式对话框显示在主窗口后面
    要解决这个问题的关键在于CDialog的Create并不能建立一个无属主的窗口.必须用另外方式建窗口. 
     比如你的对话框类叫CDlgNoOwner,在CMainFrame中加一个CDlgNoOwner类的成员变量, 
     弹出这个对话框的消息处理函数为 

     void  CMainFrame::OnNoowner()   
     {  
      CDlgNoOwner  *m_dlgTest=new  CDlgNoOwner(this); 
     HWND  hwndDlg=::CreateDialog(AfxGetInstanceHandle(),MAKEINTRESOURCE(CDlgNoOwner::IDD),NULL/*owner*/,NULL/*dlgproc*/);  
     //注意此处DLGPROC为NULL,并不要紧,因为接下要subclass啦  
     m_dlgTest->SubclassWindow  (hwndDlg);//挂接到成员变量!  
     m_dlgTest->ShowWindow  (SW_SHOW);  
     //这时可以看到一个"自由"的对话框弹出,和你的主窗口是平起平坐的.  
     }  

     当然不要忘了在对话框关闭时DestroyWindow()..那都是在对话框类中的标准处理了.


    74. 隐藏窗口(子窗口没有焦点时)
    在程序启动时  InitDialog  中使用  SetWindowPos  将窗体设置到屏幕以外
    然后再隐藏
      1.在OnInitDialog()函数里设置定时器:(WINDOWS  API里面响应消息WM_INITDIALOG) 
     SetTimer(1,  1,  NULL); 
     2.添加处理WM_TIMER的消息处理函数OnTimer,添加代码: 

     if(nIDEvent  ==  1)  
     {  
     DeleteTimer(1);  
     ShowWindow(SW_HIDE);  
     } 


    75.修改视图背景
    How do I change the background color of a view?
    To change the background color for a CView, CFrameWnd, or CWnd object, process the WM_ERASEBKGND message. The following code shows how:

    BOOL CSampleView::OnEraseBkgnd(CDC* pDC)
    {
      // Set brush to desired background color.
      CBrush backBrush(RGB(255, 128, 128));
      // Save old brush.
      CBrush* pOldBrush = pDC->SelectObject(&backBrush);
      CRect rect;
      pDC->GetClipBox(&rect);   // Erase the area needed.
      pDC->PatBlt(rect.left, rect.top, rect.Width(), 
      rect.Height(), PATCOPY);
      pDC->SelectObject(pOldBrush);
      return TRUE;
    }


    I solved the problem like this:

    HBRUSH dlgtest::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
    {
      switch (nCtlColor)
      {
        case CTLCOLOR_BTN:
        case CTLCOLOR_STATIC:
        {
          pDC->SetBkMode(TRANSPARENT);
        }
        case CTLCOLOR_DLG:
        {
          CBrush*   back_brush;
          COLORREF  color;
          color = (COLORREF) GetSysColor(COLOR_BTNFACE);
          back_brush = new CBrush(color);
          return (HBRUSH) (back_brush->m_hObject);
        }
      }
      return(CFormView::OnCtlColor(pDC, pWnd, nCtlColor));
    }
    

    76. 如何实现点击对话框外的地方使对话框到主窗口的后面
    只能将桌面做为父窗口

    pMDlg = new CMDlg;
    pMDlg->Create(IDD_M_DIALOG,CWnd::GetDesktopWindow()/* 设置父窗口 */);
    pMDlg->ShowWindow(SW_SHOW); 
    然后在任务栏里隐藏对话框程序
    如何让对话框应用程序在在任务栏上不出现,并且不隐藏窗口。
    [解决方法]
      把对话框的扩展属性修改成为WS_EX_TOOLWINDOW。
    [程序实现]
      把对话框的属性设置成为toolwindow,然后在需要的地方执行本代码。
    {  
       DWORD Style = ::GetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE);
      Style = WS_EX_TOOLWINDOW ;
      AfxGetMainWnd()->ShowWindow(FALSE);
      ::SetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE,Style); 
      AfxGetMainWnd()->ShowWindow(TRUE);
    }

    77. 想在程序一启动时就自动关闭窗口,不在任务栏里显示
    用CTRL+W打开ClassWizard;
    点击Class Info页,类名是工程名Dlg,
    再在左下方的"Filter"中选择"Windows";
    回到Message Maps页,就可以看到消息中有WM_WINDOWPOSCHANGING,
    加入代码,如上所示.
    这样运行*.EXE,不但看不到主界面,任务栏也没有,就是任务管理器中的"应用程序"中也不列出,那该如何关闭它?
    在任务管理器的"进程"中可以找到它,这是黑客程序常用的方法.
    如果需要的话,连"进程"中也看不到.这样要终止它就是问题了.
    78.修改打印预览的ToolBar
    为AFX_IDD_PREVIEW_TOOLBAR这个ID创建一个DialogBar。则系统就会用新创建的DialogBar代替系统默认的那个
    79. 如何实现SDI与MDI的转换?
    我想将一个编好的SDI应用程序转换为MDI,很明显要有多处的改变。
    你可以这样做:建立一个继承于CMDIChidWnd的类,不防设为CChldFrm.在CWinApp中作如下变化。

    InitInstance()
    {
    . ...
      //instead of adding CSingleDocTemplate
      // Add CMultiDocTemplate.
      pDocTemplate = new CMultiDocTemplate(
          IDR_MAINFRAME,
          RUNTIME_CLASS(CSDIDoc),
          RUNTIME_CLASS(CChldFrm),
    // For Main MDI Frame change this frame window from
    // CFrameWnd derivative ( i.e. CMainFrame )
    // to your CMDIChildWnd derived CChldFrm.
          RUNTIME_CLASS(CSDIView));
    /// After this it is required to create the main frame window
    // which will contain all the child windows. Now this window is
    // what was initially frame window for SDI.
      CMainFrame* pMainFrame = new CMainFrame;
      if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
          return FALSE;
       m_pMainWnd = pMainFrame;
    .....
    }

    在从CMDIFrameWnd中继承的类CMainFrame代替CFramWnd后,所有的类都将从CMDIFrame继承,而不是CFrameWnd,编译运行后你就会发现程序已经从SDI变换到MDI。
    注意:在CMainFram中必须将构造函数从private改为public.否则会出错。

    80. CDC中的竖排文本?
    在OnDraw成员函数中我想让文本竖直对齐,但CDC类似乎不支持该处理
    方法一:如果你的竖直对齐是指旋转文本的话,下面的代码会对你有帮助:该代码检查一个Check box控制,查看文本是否需要旋转.

    // m_pcfYTitle is a CFont* to the selected font.
    // m_bTotateYTitle is a bool (==TRUE if rotated)
    void CPage1::OnRotateytitle()
    {
    LOGFONT lgf;
    m_pcfYTitle->GetLogFont(&lgf);
    m_bRotateYTitle=
        ((CButton*)GetDlgItem(IDC_ROTATEYTITLE))->GetCheck()>0;
    // escapement is reckoned clockwise in 1/10ths of a degree:
    lgf.lfEscapement=-(m_bRotateYTitle*900);
    m_pcfYTitle->DeleteObject();
    m_pcfYTitle->CreateFontIndirect(&lgf);
    DrawSampleChart();
    }


    注意如果你从CFontDialog中选择了不同的字体,你应该自己设定LOGFONT的lfEscapement成员.将初始化后的lfEscapement值传到CFontDialog中.
    方法二:还有一段代码可参考:

    LOGFONT LocalLogFont;
    strcpy(LocalLogFont.lfFaceName, TypeFace);
    LocalLogFont.lfWeight = fWeight;
    LocalLogFont.lfEscapement = Orient;
    LocalLogFont.lfOrientation = Orient;
    if (MyFont.CreateFontIndirect(&LocalLogFont))
      {
      cMyOldFont = cdc->SelectObject(&MyFont);
      }

     

    81. 如何用键盘滚动分割的视口?
    我的问题是当我用鼠标滚动分割窗口时,视口滚动都很正常,但用键盘时,却什么也没有发生.
    在你的视图继承类中加入如下两个函数,假定该类为CScrollerView:

    void CScrollerView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
    {
        BOOL processed;
        for (unsigned int i=0;i< nRepCnt&&processed;i++)
            processed=KeyScroll(nChar);
        if (!processed)
          CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
    }
    BOOL CScrollerView::KeyScroll(UINT nChar)
    {
        switch (nChar)
            {
            case VK_UP:
                OnVScroll(SB_LINEUP,0,NULL);
                break;
            case VK_DOWN:
                OnVScroll(SB_LINEDOWN,0,NULL);
                break;
            case VK_LEFT:
                OnHScroll(SB_LINELEFT,0,NULL);
                break;
            case VK_RIGHT:
                OnHScroll(SB_LINERIGHT,0,NULL);
                break;
            case VK_HOME:
                OnHScroll(SB_LEFT,0,NULL);
                break;
            case VK_END:
                OnHScroll(SB_RIGHT,0,NULL);
                break;
            case VK_PRIOR:
                OnVScroll(SB_PAGEUP,0,NULL);
                break;
            case VK_NEXT:
                OnVScroll(SB_PAGEDOWN,0,NULL);
                break;
            default:
                return FALSE; // not for us
                   // and let the default class
                   // process it.
            }
      return TRUE;
    }
    

    82. 如何改变默认的光标形状?
    我试着将光标改变为其它的形状和颜色,但却没有变化.
    在对话框/窗口/你需要的地方加上对WM_SETCURSOR消息的处理.

    BOOL MyDialog::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
    {
      // TOD Add your message handler code here and/or call default
      ::SetCursor(AfxGetApp()->LoadCursor(IDC_MYCURSOR));
      return TRUE;
      //return CDialog::OnSetCursor(pWnd, nHitTest, message);
    }

    你没有成功的原因是因为窗口类光标风格不能为NULL.

    83. 如何选择CTreeCtrl中的节点文本进行编辑?
    在向CTreeCtrl中加入一项后,有什么方法可以编辑该节点的文本呢?
    首先设置你的CcompTreeCtrl具有TVS_EDITLABELS属性.在设计时用控件属性来设置在运行时用GetStyle()/SetStyle()成员函数来设置.然后请看下述代码:

    HTREEITEM CCompTreeCtrl::AddSet()
    {
    static int setCnt =3D 1;
    HTREEITEM hItem;
    CString csSet;
    //create text for new note: New Set 1, New Set 2 ...
    csSet.Format( _T( "New Set %d" ), setCnt++ );
    hItem =3D InsertItem( csSet, IMG_CLOSEDFOLDER, IMG_CLOSEDFOLDER );
    if( hItem !=3D NULL )
          EditLabel( hItem );
    return hItem;
    }


    84. CListCtrl中选择变化时如何获得通知?
    我在Report View中使用了一个CListCtrl(自绘制类型),我想知道什么时候选择项发生了改变.
    在选择项变化时,可以使用按钮有效或失效,按如下操作:
     加入LVN_ITEMCHANGED消息处理.

    void CYourClassNameHere::OnItemchangedEventList(NMHDR* pNMHDR, LRESULT* pResult)
    {
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
    *pResult = 0;
    if (pNMListView->uChanged == LVIF_STATE)
    {
     if (pNMListView->uNewState)
      GetDlgItem(IDC_DELETE)->EnableWindow(TRUE);
     else
      GetDlgItem(IDC_DELETE)->EnableWindow(FALSE);
    }
    }


    85. List控件中整栏选择?
    我在处理List控件时碰到了麻烦,我想创建一个ListView,来依据Tree控件的选择同时在ListView和ReportView中显示列表的信息.以下是相关的代码:

    // Set full line select
    ListView_SetExtendedListViewStyle(m_plstCustomers->GetSafeHwnd(),LVS_EX_FULLROWSELECT);


    按如下方法处理:

    // -------------------- begin of snippet --------------------------------
    bool CCommCtrlUtil32::ListCtrl_ModifyExtendedStyle(CListCtrl& p_rListCtrl,
                      const DWORD p_dwStyleEx,
                      const bool p_bAdd)
    {
      HWND t_hWnd = p_rListCtrl.GetSafeHwnd();
      DWORD t_dwStyleEx = ListView_GetExtendedListViewStyle(t_hWnd);
      if(p_bAdd)
      {
        if(0 == (p_dwStyleEx & t_dwStyleEx))
        {
          // add style
          t_dwStyleEx |= p_dwStyleEx;
        }
      }
      else
      {
        if(0 != (p_dwStyleEx & t_dwStyleEx))
        {
          // remove style
          t_dwStyleEx &= ~p_dwStyleEx;
        }
      }
      ListView_SetExtendedListViewStyle(t_hWnd, t_dwStyleEx);
      return true;
    }
    

    86. 如何限制mdi子框架最大化时的大小?
    用ptMaxTrackSize代替prMaxSize,如下所示:

    void CChildFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
    {
      // TOD Add your message handler code here and/or call default
      CChildFrame::OnGetMinMaxInfo(lpMMI);
      lpMMI->ptMaxTrackSize.x = 300;
      lpMMI->ptMaxTrackSize.y = 400;
    }


    87. 怎样实现3D效果?
    在对话框中怎样实现Edit和Listboxes控件的3D效果?(环境95/NT VC5.0)
    1). 使用带WS_EX_CLIENTEDGE标志的::CreateWindowEx来替换::CreateWindow 或者用CWnd::CreateEx替换CWnd::Create.
    2).在建立控件之后,调用ModifyStyleEx(0, WS_EX_CLIENTEDGE).


    88. How do I update the text of a pane in a status bar?
    By default, a CStatusBar pane is not enabled when the pane is created. To activate a pane, you must call the ON_UPDATE_COMMAND_UI() macro for each pane on the status bar and update the panes. Because panes do not send WM_COMMAND messages, you cannot use ClassWizard to activate panes; you must type the code manually. For example, suppose one pane has ID_INDICATOR_PAGE as its identifier and that it contains the current page number in a document. To make the ID_INDICATOR_PAGE pane display text, add the following to a header file (probably the MAINFRM.H file):
    afx_msg void OnUpdatePage(CCmdUI *pCmdUI);
    Add the following to the application message map:
    ON_UPDATE_COMMAND_UI(ID_INDICATOR_PAGE, OnUpdatePage)
    Add the following to a source code file (probably MAINFRM.CPP):

    void CMainFrame::OnUpdatePage(CCmdUI *pCmdUI)
    {
      pCmdUI->Enable();
    }
    

    To display text in the panes, either call SetPaneText() or call CCmdUI::SetText() in the OnUpdate() function. For example, you might want to set up an integer variable m_nPage that contains the current page number. Then, the OnUpdatePage() function might read as follows:

    void CMainFrame::OnUpdatePage(CCmdUI *pCmdUI)
    {
      pCmdUI->Enable();
      char szPage[16];
      wsprintf((LPSTR)szPage, "Page %d", m_nPage);
      pCmdUI->SetText((LPSTR)szPage);
    }

    This technique causes the page number to appear in the pane during idle processing in the same manner that the application updates other indicators.

    89. 动态修改对话框的大小
     [问题提出]
      关于如何动态改变对话框的大小,我做了个Demo,大家看看.
     [程序实现]
       //本函数使用方法:
       //第一个参数:如果是TRUE表示显示扩展的对话框,如果是FALSE,表示缩小对话框。
       //第二个参数:表示本对话框的HWND,
       //第三个参数:表示缩小后大小的控件的ID
      

    void COptionDlg::ExpandBox(BOOL fExpand, HWND hwnd, int nIDDefaultBox)
      {
         CWnd *pWndBox=GetDlgItem(nIDDefaultBox);
         RECT rcDefaultBox,rcChild,rcIntersection,rcWnd;
         pWndBox->GetWindowRect(&rcDefaultBox);
         HWND hwndChild = ::GetTopWindow(hwnd);
         for (; hwndChild != NULL; hwndChild = ::GetNextWindow(hwndChild,GW_HWNDNEXT)) 
         {
             ::GetWindowRect(hwndChild, &rcChild);
             if (!IntersectRect(&rcIntersection, &rcChild, &rcDefaultBox))
                  ::EnableWindow(hwndChild, fExpand);
         }
         ::GetWindowRect(hwnd, &rcWnd);
         if (GetWindowLong(hwnd, GWL_USERDATA) == 0)
         {
             SetWindowLong(hwnd, GWL_USERDATA,
                  MAKELONG(rcWnd.right - rcWnd.left, 
                  rcWnd.bottom - rcWnd.top));
             ::ShowWindow(pWndBox->m_hWnd, SW_HIDE);
         }
         ::SetWindowPos(hwnd, NULL, 0, 0,
             rcDefaultBox.right - rcWnd.left,
             rcDefaultBox.bottom - rcWnd.top,
             SWP_NOZORDER | SWP_NOMOVE);
         if(fExpand)
         {
             DWORD dwDims = GetWindowLong(hwnd, GWL_USERDATA);
             ::SetWindowPos(hwnd, NULL, 0, 0,
                  LOWORD(dwDims), HIWORD(dwDims), SWP_NOZORDER | SWP_NOMOVE);
             ::SendMessage(hwnd, DM_REPOSITION, 0, 0);
         }
      }
    

    90. 用DoModal()调用模态对话框,总是显示在正中,我重载了它,并添加了MoveWindow(),可是其m_hWnd是一串零,调用失败。

          请问有何方法可使调用的模态对话框显示于自定义位置?
      我不清楚你把MoveWindow()加在什么地方了,正确的方法是在OnInitDialog中添加MoveWindow,如:
       MoveWindow(0, 1, 300, 200);
      需要注意的是前两个参数不能都为0。如果你确实希望把窗口放在(0, 0)处,可以在对话框设计窗口的属性中选中Absolute Align,然后再加入
       MoveWindow(0, 0, 300, 200);
      为什么会是这样?你看了MFC的源程序就会明白。原来MFC在调用你的OnInitDialog之后,会调用CDialog::CheckAutoCenter()(在dlgcore.cpp中)检查是否需要将窗口居中,你看了这个函数后就明白为什么需要上面那么做了。

  • 相关阅读:
    BZOJ4503 两个串
    【挖坟】HDU3205 Factorization
    webpack打包 The 'mode' option has not been set, webpack will fallback to
    echarts js报错 Cannot read property 'getAttribute' of null
    微信支付 get_brand_wcpay_request fail,Undefined variable: openid
    layui动态设置checbox选中状态
    layui 获取radio单选框选中的值
    js 获取数组最后一个元素
    js生成指定范围内的随机数
    layer重复弹出(layui弹层同时存在多个)的解决方法
  • 原文地址:https://www.cnblogs.com/leven20061001/p/2728201.html
Copyright © 2011-2022 走看看