zoukankan      html  css  js  c++  java
  • MFC 常用功能总结

    目录

    ◆ 获取启动参数◆ 调整窗体大小◆ 关闭Dialog窗体◆ Dialog启动时指定控件为焦点◆ Dialog中禁止ESC回车关闭窗体◆ 回车后焦点自动跳到下一个控件◆ 窗体中某个控件捕获右键菜单◆ 获取指定窗体hWnd下的所有子窗体◆ MainFrame启动时居中◆ 非Dialog结构, 初始化时隐藏主窗口避免发生闪烁◆ 设置MainFrame标题栏, 不显示文档名称◆ CListCtrl 的使用1. Item失去焦点时也处于选中状态◆ CRichEditCtrl 的使用1. 设置字体格式◆ CComboBox 的使用1. CComboBox 为焦点时获取其ID2. 输入自动匹配功能的实现◆ CTreeCtrl 的使用1. 初始化时SetCheck无效2. 双击不展开或收缩节点的办法。3. 实现CTreeCtrl父子节点的联动选择◆ CMFCStatusBar 的使用◆ CDockablePane 的使用1. CDockablePane 的布局2. CDockablePane 的显示与隐藏3. 背景刷新问题.4. 如何自定义左右两个并列CDockablePane的大小

    ◆ 获取启动参数

    在 XXXApp 类的 InitInstance 函数中通过宏 __argc 与 __targv 即可获取到程序的启动参数. 代码如下:

    BOOL XXXApp::InitInstance()
    {
    for (int i = 0; i < __argc; i++)
    {
    AfxMessageBox(__targv[i]);
    }

    ...

    return FALSE;
    }

    ◆ 调整窗体大小

    使用 SetWindowPos 或 GetWindowRect 均可实现. 代码如下:

        // SetWindowPos 实现
    CRect rc1(0, 0, 800, 600);
    SetWindowPos(NULL, 0, 0, rc1.Width(), rc1.Height(), SWP_NOZORDER | SWP_NOMOVE);

    // MoveWindow 实现
    CRect rc2;
    GetWindowRect(&rc2);
    rc2.bottom += 100;
    rc2.right += 100;
    MoveWindow(&rc2);

    ◆ 关闭Dialog窗体

    通过 PostMessage 函数发送消息实现. 代码如下:

    // close dialog
    ::PostMessage(pDlg->GetSafeHwnd(), WM_CLOSE, 0, 0);

    // end dialog with idok
    ::PostMessage(pDlg->GetSafeHwnd(), WM_COMMAND, IDOK, 0);

    ◆ Dialog启动时指定控件为焦点

    在 OnInitDialog() 中调用 BringWindowToTop(). 代码如下:

    GetDlgItem(IDC_EDIT_XXX)->BringWindowToTop();

    ◆ Dialog中禁止ESC回车关闭窗体

    通过在 PreTranslateMessage(…) 中屏蔽对 VK_ESCAPE, VK_RETURN 的处理即可. 代码如下:

    BOOL CDlgXXX::PreTranslateMessage(MSG* pMsg)
    {
    if (VK_RETURN == pMsg->wParam || VK_ESCAPE == pMsg->wParam)
    {
    return TRUE;
    }

    return CDialogEx::PreTranslateMessage(pMsg);
    }

    ◆ 回车后焦点自动跳到下一个控件

    通过在 PreTranslateMessage(…) 中对 WM_KEYDOWN, VK_RETURN 的处理来实现. 代码如下:

    BOOL CDlgXXX::PreTranslateMessage(MSG* pMsg)
    {
    if (WM_KEYDOWN == pMsg->message && VK_RETURN == pMsg->wParam)
    {
    int id = GetFocus()->GetDlgCtrlID();
    if (id == IDC_EDIT_X1)
    {
    // 两种方法都可以重置焦点
    GotoDlgCtrl(GetDlgItem(IDC_EDIT_X2));
    // GetDlgItem(IDC_EDIT_X2)->SetFocus();
    }
    else if (id == IDC_EDIT_X2)
    {
    OnBnClickedBtn();
    }

    return TRUE;
    }

    return CDialogEx::PreTranslateMessage(pMsg);
    }

    ◆ 窗体中某个控件捕获右键菜单

    处理消息 WM_CONTEXTMENU 来实现. 代码如下:

    void CDlgXXX::OnContextMenu(CWnd* pWnd, CPoint point)
    {
    if (pWnd->m_hWnd == 控件.m_hWnd)
    {
    CMenu m;
    m.LoadMenu(IDR_MENU);

    CMenu* pPopMenu = menu.GetSubMenu(0);
    if (!pPopMenu)
    {
    return ;
    }

    pPopMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y);
    }
    }

    ◆ 获取指定窗体hWnd下的所有子窗体

    通过 GetWindow 可以实现, 代码如下:

    HWND hwndChild = ::GetWindow(hWnd, GW_CHILD);    //列出所有控件
    while (hwndChild)
    {
    hwndChild = ::GetWindow(hwndChild, GW_HWNDNEXT);
    }

    ◆ MainFrame启动时居中

    在 OnCreate 中调用 CenterWindow();

    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    ...

    CenterWindow()

    ...
    }

    ◆ 非Dialog结构, 初始化时隐藏主窗口避免发生闪烁

    • 在应用程序构造函数 CxxxApp::CxxxApp(){} 中添加代码:
    CXXXApp::CXXXApp()
    {
    EnableLoadWindowPlacement(FALSE);

    ...
    }

    • 应用程序初始化 CETSPApp::InitInstance() 中设置
    BOOL CMFCApplication1App::InitInstance()
    {
    ...

    // The one and only window has been initialized, so show and update it
    // m_pMainWnd->ShowWindow(SW_SHOW);
    m_pMainWnd->ShowWindow(SW_HIDE);

    ....

    m_pMainWnd->UpdateWindow();
    return TRUE;
    }

    • 重载 CMainFrame 的 ActivateFrame 函数.
    void CMainFrame::ActivateFrame(int nCmdShow)
    {
    nCmdShow = SW_HIDE;

    CFrameWndEx::ActivateFrame(nCmdShow);
    }


    • 要显示 MainFrame 时调用
    ShowWindow(SW_SHOW)

    ◆ 设置MainFrame标题栏, 不显示文档名称

    BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
    {
    if( !CFrameWndEx::PreCreateWindow(cs) )
    return FALSE;

    cs.style &= ~(LONG)FWS_ADDTOTITLE;

    return TRUE;
    }

    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    ...

    SetWindowText(_T("xxx"));

    ...
    }

    ◆ CListCtrl 的使用

    1. Item失去焦点时也处于选中状态

    设置 LVS_SHOWSELALWAYS. 代码如下:

    m_ctrlList.ModifyStyle(0, LVS_SHOWSELALWAYS | LVS_XXX(其它需要的选项));

    ◆ CRichEditCtrl 的使用

    要使用 CRichEditCtrl, 需要在 App 的 InitInstance 中调用 AfxInitRichEdit2 . 代码如下:

    BOOL CXXXApp::InitInstance()
    {
    AfxInitRichEdit2();

    ...

    return FALSE;
    }

    1. 设置字体格式

    通过 GetDefaultCharFormat, SetDefaultCharFormat, SetWordCharFormat, SetSelectionCharFormat 这四个函数即可实现对 CRichEditCtrl 的字体设置(函数的功能与用法查询MSDN即可).

    说明:
    1.同一个函数中 SetSelectionCharFormat 之前一定要有一次 SetWordCharFormat, 否则第一次 SetSelectionCharFormat 不生效.
    2.设置颜色时,CHARFORMAT2 结构中的 dwMask 要具有 CFM_COLOR 标志,dwEffects 要清除 CFE_AUTOCOLOR 标志(设置为0即可),crTextColor 指定颜色.

    ◆ CComboBox 的使用

    1. CComboBox 为焦点时获取其ID

    问题: 通过 GetFocus() 获取 CComboBox 的焦点时, 当焦点在编辑框和按钮上时没有问题,一旦焦点在 CComboBox 框上, GetFocus() 的返回就有问题,用 UINT ID = GetFocus()-> GetDlgCtrlID(); 得到的返回值始终是 1001.

    原因: MSDN 上的解释 A combo box consists of a list box combined with either a static control or edit control. 所以上面问题中的第2种情况实际上获取到的是 static control 的 ID.

    解决:

    UINT ID = GetFocus()->GetParent()->GetDlgCtrlID();

    2. 输入自动匹配功能的实现

    请参考 MFC Combobox 实现输入自动匹配

    ◆ CTreeCtrl 的使用

    1. 初始化时SetCheck无效

    对于对话框中的TreeView控件,如果想在初始化(OnInitDialog)中SetCheck,必须:

    m_tree.ModifyStyle( TVS_CHECKBOXES, 0 );
    m_tree.ModifyStyle( 0, TVS_CHECKBOXES );
    m_tree.SetCheck(hItem, TRUE);

    即即使在对话框编辑器中为 TreeView 增加了 Check Boxes 属性,也必须重新设一次 TVS_CHECKBOXES,SetCheck 才能起作用, 而对于非初始化中的SetCheck,则不受影响.

    2. 双击不展开或收缩节点的办法。

    void CTreeView::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)
    {
    *pResult = TRUE;
    }

    3. 实现CTreeCtrl父子节点的联动选择

    请参考 实现CTreeCtrl父子节点的联动选择

    ◆ CMFCStatusBar 的使用

    … 这个不得不吐槽下, 非常难用.

    CMFCStatusBar m_wndStatusBar;

    // 注意, 这些ID必须在资源的字符表里设置值, 要不然展现出来的效果是状态栏上对应的panel的背景色为黑色
    static UNIT indicators[] =
    {
    IDS_STATUS_0,
    IDS_STATUS_1,
    IDS_STATUS_2,
    IDS_STATUS_3,
    IDS_STATUS_4,
    };

    // 创建
    m_wndStatusBar.Create(this);
    m_wndStatusBar.SetIndicators(indicators, sizeof(indicators) / sizeof(UNIT));

    // 设置样式, 这里如果使用CStatusBar能实现相同效果的函数, 达不到预期效果
    m_wndStatusBar.SetPanelStyle(0, SBPS_STRETCH);
    m_wndStatusBar.SetPanelWidth(1, 80);

    // 设置文字
    m_wndStatusBar.SetPanelText
    m_wndStatusBar.SetPanelTextColor
    m_wndStatusBar.SetPanelBackgroundColor

    // ... 最最重要的. 自定义的状态栏字体为灰色的问题
    // 按网上的添加映射 ON_COMMAND(IDS_STATUS_0, NULL) 这样根本不能解决问题(第一个Panel始终为灰色, 后面的Panel可以解决)
    // 方法如下:

    // 通过更新UI的方式来解决
    // IDS_STATUS_0 到 IDS_STATUS_4 不连续, 使用ON_UPDATE_COMMAND_UI分开实现即可
    ON_UPDATE_COMMAND_UI_RANGE(IDS_STATUS_0, IDS_STATUS_4, &CMainFrame::OnUpdateStatusBar)

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

    // 事件, 进度条, 图标 ... 暂时未使用, 遇到时添加

    ◆ CDockablePane 的使用

    1. CDockablePane 的布局

    请参考 CDockablePane使用心得

    2. CDockablePane 的显示与隐藏

    m_wndXXXPane.ShowPane(TRUE,FALSE,TRUE);     // 显示
    m_wndXXXPane.ShowPane(FALSE,FALSE,FALSE); // 隐藏

    3. 背景刷新问题.

    在框架的 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)中创建了几个CDockablePane,里面是空的,运行,改变大小就会看到这些 CDockablePane 出现背景不会自动刷新.

    重写 OnPanit()

    void CPropertyPane::OnPaint()
    {
    CPaintDC dc(this); // device context for painting

    CRect rc;
    GetClientRect(rc);
    CBrush brush;
    brush.CreateSolidBrush(RGB(255, 255, 255));
    dc.FillRect(&rc,&brush);

    // Do not call CDockablePane::OnPaint() for painting messages
    }

    4. 如何自定义左右两个并列CDockablePane的大小

    注:

    1. 本方法仅是通过重置窗体的属性来实现的, 如果您有好的方法请告知, 谢谢.
    2. 本方法同样适合设置上下两个并列CDockablePane的大小.

    按系统默认的实现方式, 左右两个并列 CDockablePane 的布局会如下:

    |------------|------------|
    | | |
    | pane1 | pane2 |
    | | |
    |------------|------------|
    为了实现下图的样式
    |-------|-----------------|
    | | |
    | pane1 | pane2 |
    | | |
    |------ |-----------------|

    请参考如下代码:

    BOOL CMainFrame::CreateDockingWindows()
    {
    BOOL bNameValid;

    ...

    // Create pane1 window
    CString strPane1;
    bNameValid = strPane1.LoadString(ID_PANE_1);
    ASSERT(bNameValid);
    if (!m_wndPane1.Create(strPane1, this, CRect(0, 0, 100, 100), TRUE, ID_PANE_1, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_BOTTOM | CBRS_FLOAT_MULTI))
    {
    TRACE0("Failed to create pane1 window ");
    return FALSE; // failed to create
    }

    // Create pane2 window
    CString strPane2;
    bNameValid = strPane2.LoadString(ID_PANE_2);
    ASSERT(bNameValid);
    if (!m_wndPane2.Create(strPane2, this, CRect(0, 0, 200, 200), TRUE, ID_PANE_2, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_BOTTOM | CBRS_FLOAT_MULTI))
    {
    TRACE0("Failed to create pane2 window ");
    return FALSE; // failed to create
    }

    ...

    return TRUE;
    }

    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    // TRUE : 允许加载上次的docking状态
    // FALSE: 不允许加载上次的docking状态
    EnableLoadDockState(FALSE);

    ...

    // create docking windows
    if (!CreateDockingWindows())
    {
    TRACE0("Failed to create docking windows ");
    return -1;
    }

    // 记住 Dock 前 m_wndPane1 的位置与大小
    CRect r1;
    m_wndPane1.GetWindowRect(&r1);

    // DockPane
    DockPane(&m_wndPane1);
    DockPane(&m_wndPane2);

    // 让 m_wndPane1 在 m_wndPane2 的左边, 函数中会改变两个Pane的大小, 使其大小一致, 各占 CMainFrame 宽度的一半
    m_wndPane1.DockToWindow(&m_wndPane2, CBRS_LEFT);

    // 还原 m_wndPane1 的位置与大小
    m_wndPane1.SetWindowPos(NULL, r1.left, r1.top, r1.Width(), r1.Height(), SWP_NOZORDER | SWP_NOMOVE);

    ...

    return 0;
    }

    void CMainFrame::OnSize(UINT nType, int cx, int cy)
    {
    CRect r1;

    if (m_wndPane1.GetSafeHwnd())
    {
    // 获取 Pane1 改变前的位置与大小
    m_wndPane1.GetWindowRect(&r1);
    }

    // 会触发所有 Pane 的 WM_SIZE 消息, 将所有 Pane 的大小重置
    // 还会调用 AdjustDockingLayout 重新计算停靠到框架窗口的所有窗格的布局
    CFrameWndEx::OnSize(nType, cx, cy);

    if (m_wndPane1.GetSafeHwnd())
    {
    // 获取 Pane2 的位置与大小, 使 Pane1 的 top, bottom 与 Pane2的一致
    CRect r2;
    m_wndPane2.GetWindowRect(&r2);
    r1.top = r2.left;
    r1.bottom = r2.bottom;

    // 还原 m_wndPane1 的位置与大小
    m_wndPane1.SetWindowPos(NULL, r1.left, r1.top, r1.Width(), r1.Height(), SWP_NOZORDER | SWP_NOMOVE);

    // 重新计算停靠到框架窗口的所有窗格的布局
    AdjustDockingLayout();
    }
    }

    本文持续更新中...

  • 相关阅读:
    数据库锁机制
    spring的事务传播行为与隔离级别
    Logback+ELK+SpringMVC搭建日志收集服务器
    提高mysql千万级大数据SQL查询优化30条经验(Mysql索引优化注意)
    有状态的bean和无状态的bean的区别
    浅谈Spring解决循环依赖的三种方式
    某类继承thread,同时实现runnable
    java动态代理
    缓存一致性
    Elasticsearch系列(一)--入门
  • 原文地址:https://www.cnblogs.com/zxsh/p/8623069.html
Copyright © 2011-2022 走看看