如果我切换到另一个应用程序我的MFC应用程序冻结

问题描述 投票:2回答:4

开始这个问题的V 2.0。

我的VC ++ MFC应用程序编译并运行得很好。也就是说,直到我切换到另一个窗口。一旦我的程序失去焦点,它就会冻结;我无法切换回它,如果我移动一个位于它前面的窗口,我的应用程序窗口会在另一个窗口覆盖的空间中显示白色。

自从我第一次发布这个问题以来,我已经能够确定我的程序的哪个部分导致了这种行为,但我仍然不知道哪些代码行是错误的或者为什么。

我的MFC应用程序的主对话框包含一个名为m_MainTabControl的CTabCtrl。此主选项卡控件保留在两个标签为“基本设计”和“高级设计”的选项卡上,每个选项卡都与其自己的对话框相关联。两个对话框都包含一个带有多个选项卡的CTabCtrl。因此我的问题就此诞生了。

当我第一次创建这个tab-tab-tab结构时,当我尝试在内部选项卡之间切换时,我遇到了程序冻结的问题。毋庸置疑,我对此感到困惑,直到我注意到如果我第一次点击其中一个内部标签上的控件,我就可以切换标签了。因此,如果没有完全理解问题是什么,我将焦点设置为程序启动时第一个内部选项卡的第一个内部选项卡。问题解决了一半。当我运行程序时,我可以点击第一组内部选项卡就好了;如果我切换到第二个外部选项卡并尝试单击其内部选项卡而不先单击对话框控件,它将再次冻结。所以我创建了一个Focus功能来聚焦当前所选外部选项卡的当前所选内部选项卡,并在我的选项卡更改事件(当您单击另一个选项卡时关闭的事件)中调用该选项卡。

这就是我在第一次提出这个问题时达到的目的。我认为我的程序运行得很好,直到我再玩了一遍,并注意到当它在它和另一个窗口或程序之间来回翻转时它不能很好地播放。更具体地说,一旦我的程序失去焦点,一些过程就会变得混乱并占用整个CPU的处理价值。

而现在,我解释了我的小标签结构并将问题集中在如此精细的细节上:经过多次实验,我发现如果我在外部标签结构上注释掉第二个标签(即“高级设计”对话框及其所有内容)小孩子标签)我的程序的剩余部分运行正常,我可以切换到另一个窗口,然后不打架。 “太棒了,”我想,“这只是我节目的90%左右,我只是为了让这个工作得以评论。让我们试着进一步削减它。”我重新插入了“高级设计”选项卡式对话框,但注释掉了“高级设计”中选项卡控件创建的选项卡式对话框,一切都运行正常。我一个接一个地放回属于“高级设计”选项卡控件的选项卡式对话框,每次重新引入错误时,无论我取消注释哪个选项卡。我还应该指出,我尝试重新插入的第一个选项卡之一(当然是单独的)是我的“边距”选项卡,这是一个MarginDlg类,我也可以使用我的“基本设计”TAB而不会有任何问题。这让我相信,当我在选项卡式对话框中创建标签式对话框时,我必须做一些具体的事情,我没有做,或者做得不正确,有点像我不得不把注意力集中在一起使其工作。

我会非常感激任何可以解决的情况。我包括我认为相关的代码片段;一如既往,如果需要更多,请告诉我。

主对话框的.h文件中的变量声明:

//tab stuff
CTabCtrl m_MainTabControl;
vector<CDialog*> m_tabPages;
SimpDesDlg* simpDesDlg;
AdvDesDlg* advDesDlg;

当我的应用程序启动时,它会创建我的主对话框,并调用OnInitDialog():( TODO上方的所有内容:注释是处理对话愚蠢的默认VS内容)

BOOL CspAceDlg::OnInitDialog()
{
    CDialog::OnInitDialog();


    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    // TODO: Add extra initialization here
    ///////////////////////////////////////

    DrawResultsArea();
    DrawTabs();
    theApp.Calculate();
    Focus();
    //simpDesDlg->Focus();
    //DrawToolbar();

    return FALSE;  // return TRUE  unless you set the focus to a control
}

DrawTabs()是我为外部选项卡控件创建选项卡的地方:

void CspAceDlg::DrawTabs()
{
    simpDesDlg = new SimpDesDlg;
    m_tabPages.push_back(simpDesDlg);
    advDesDlg = new AdvDesDlg;
    m_tabPages.push_back(advDesDlg);

    // create a tcItem to hold the name of each tab during creation
    // and then get inserted, and arrays holding the tab names and IDs of
    // the dialogs they refer to
    TC_ITEM tcItem;
    PSTR pszTabNames[] = {"Basic Design", "Advanced Design"};
    UINT pszTabItems[] = {IDD_SIMPLEDESIGNTAB, IDD_ADVANCEDDESIGNTAB};

    //every member of m_tabPages[] will become a tab
    for (int i = 0; i < int(m_tabPages.size()); i++)
    {
        //set up the tab name
        tcItem.mask = TCIF_TEXT;
        tcItem.pszText = pszTabNames[i];
        tcItem.cchTextMax = int(strlen(pszTabNames[i]));
        //insert the new tab into the tab control and create the dialog window
        m_MainTabControl.InsertItem(i, &tcItem);
        m_tabPages[i]->Create(pszTabItems[i], &m_MainTabControl);
    }

    //redraw so that the dialogs don't appear in upper left corner and cover the tabs
    CRect tabRect, itemRect;
    int nX, nY, nXc, nYc;

    m_MainTabControl.GetClientRect(&tabRect);
    m_MainTabControl.GetItemRect(0, &itemRect);

    nX=itemRect.left;
    nY=itemRect.bottom+1;
    nXc=tabRect.right-itemRect.left-1;
    nYc=tabRect.bottom-nY-1;

    m_tabPages[0]->SetWindowPos(&wndTop, nX, nY, nXc, nYc, SWP_SHOWWINDOW);
    for(int nCount=1; nCount < int(m_tabPages.size()); nCount++){
        m_tabPages[nCount]->SetWindowPos(&wndTop, nX, nY, nXc, nYc, SWP_HIDEWINDOW);
    }
}

主对话框的Focus()方法:

void CspAceDlg::Focus()
{
    int curSel = m_MainTabControl.GetCurSel();
    m_tabPages[curSel]->SetFocus();

    //if it's the basic design, we need to focus its first tab
    if (curSel == 0)
    {
        simpDesDlg->Focus();
    }
    //if it's the advanced design, we need to focus its first tab
    else if (curSel == 1)
    {
        advDesDlg->Focus();
    }
}

m_MainTabControl选项卡选择更改事件的代码:

void CspAceDlg::OnTcnSelchangeBuildtabs(NMHDR *pNMHDR, LRESULT *pResult)
{
    for (int i = 0; i < int(m_tabPages.size()); i++)
    {
        m_tabPages[i]->ShowWindow(m_MainTabControl.GetCurSel() == i ? SW_SHOW :
                                                   SW_HIDE);
    }

    Focus();

    *pResult = 0;
}

SimpDesDlg和AdvDesDlg的选项卡使用相同的代码,除了选项卡初始化(只为每个选项卡创建不同的选项卡)所以这里是AdvDesDlg的代码:

的OnInitDialog():

BOOL AdvDesDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    DrawTabs();

    return false;
}

在选项卡式对话框中添加:

void AdvDesDlg::DrawTabs()
{
    //Make the dialogs for the tabs
    antennaDlg = new AntennaDlg;
    commSEDlg = new CommSEDlg;
    encryptorDlg = new EncryptorDlg;
    marginDlg = new MarginDlg;
    miscDlg = new MiscDlg;
    transRecDlg = new TransRecDlg;

    //add them all to the tabPages vector
    m_tabPages.push_back(antennaDlg);
    m_tabPages.push_back(commSEDlg);
    m_tabPages.push_back(encryptorDlg);
    m_tabPages.push_back(marginDlg);
    m_tabPages.push_back(miscDlg);
    m_tabPages.push_back(transRecDlg);

    //m_tabPages[0] = new AntennaDlg;
    //m_tabPages[1] = new CommSEDlg;
    //m_tabPages[2] = new EncryptorDlg;
    //m_tabPages[3] = new MarginDlg;
    //m_tabPages[4] = new MiscDlg;
    //m_tabPages[5] = new TransRecDlg;

    //antennaDlg = (AntennaDlg*) m_tabPages[0];
    //commSEDlg = (CommSEDlg*) m_tabPages[1];
    //encryptorDlg = (EncryptorDlg*) m_tabPages[2];
    //marginDlg = (MarginDlg*) m_tabPages[3];
    //miscDlg = (MiscDlg*) m_tabPages[4];
    //transRecDlg = (TransRecDlg*) m_tabPages[5];

    // create a tcItem to hold the name of each tab during creation
    // and then get inserted, and arrays holding the tab names and IDs of
    // the dialogs they refer to
    TC_ITEM tcItem;
    PSTR pszTabNames[] = {"Antenna", "Comm Support", "Encryptor", "Margins", "Misc", "Trasmitter/Receiver"};
    UINT pszTabItems[] = {IDD_ANTENNATAB, IDD_COMMSETAB, IDD_ENCRYPTORTAB, IDD_MARGINTAB, IDD_MISCTAB, IDD_TRANSRECTAB};

    //every member of m_tabPages[] will become a tab
    for (int i = 0; i < int(m_tabPages.size())/*(sizeof(m_tabPages)/sizeof(m_tabPages[0]))*/; i++)
    {
        //set up the tab name
        tcItem.mask = TCIF_TEXT;
        tcItem.pszText = pszTabNames[i];
        tcItem.cchTextMax = int(strlen(pszTabNames[i]));
        //insert the new tab into the tab control and create the dialog window
        advTab.InsertItem(i, &tcItem);
        m_tabPages[i]->Create(pszTabItems[i], &advTab);
    }

    //redraw so that the dialogs don't appear in upper left corner and cover the tabs
    CRect tabRect, itemRect;
    int nX, nY, nXc, nYc;

    advTab.GetClientRect(&tabRect);
    advTab.GetItemRect(0, &itemRect);

    nX=itemRect.left;
    nY=itemRect.bottom+1;
    nXc=tabRect.right-itemRect.left-1;
    nYc=tabRect.bottom-nY-1;

    //m_tabPages[0]->SetWindowPos(&wndTop, nX, nY, nXc, nYc, SWP_SHOWWINDOW);
    for(int nCount=/*1*/0; nCount < int(m_tabPages.size())/*(sizeof(m_tabPages)/sizeof(m_tabPages[0]))*/; nCount++){
        m_tabPages[nCount]->SetWindowPos(&wndTop, nX, nY, nXc, nYc, SWP_HIDEWINDOW);
    }
}

并且Focus()和标签更改:

void AdvDesDlg::Focus()
{
    this->SetFocus();
    for (int i = 0; i < int(m_tabPages.size())/*(sizeof(m_tabPages)/sizeof(m_tabPages[0]))*/; i++)
    {
        m_tabPages[i]->ShowWindow(advTab.GetCurSel() == i ? SW_SHOW :
                                                   SW_HIDE);
    }

    int curSel = advTab.GetCurSel();
    m_tabPages[curSel]->SetFocus();
}

void AdvDesDlg::OnTcnSelchangeAdvDesign(NMHDR *pNMHDR, LRESULT *pResult)
{
    for (int i = 0; i < int(m_tabPages.size())/*(sizeof(m_tabPages)/sizeof(m_tabPages[0]))*/; i++)
    {
        m_tabPages[i]->ShowWindow(advTab.GetCurSel() == i ? SW_SHOW :
                                                   SW_HIDE);
    }

    int curSel = advTab.GetCurSel();
    m_tabPages[curSel]->SetFocus();

    *pResult = 0;
}
c++ visual-studio visual-studio-2008 visual-c++ mfc
4个回答
4
投票

调试您的应用程序,使其进入此状态,然后进入Debug / Break All。在Threads窗口中找到主线程,然后查看调用堆栈。调用堆栈中的某个位置将是导致挂起的代码。

请注意,为了获得合理的调用堆栈,您需要将Visual Studio指向Microsoft的符号服务器;见http://msdn.microsoft.com/en-us/library/b8ttk8zy.aspx


2
投票

当您运行某个进程而不允许消息泵运行时,通常会出现您描述的行为。

你的应用程序做什么?我假设你启动它,然后按一个按钮或选择一个菜单项来启动一些过程。

如果程序在您第一次启动时(在您单击开始处理之前)行为正常,但在开始该过程之后按照您的描述行事,则那就是您的问题。

您必须将该处理移动到另一个线程以允许MFC GUI保持响应。


0
投票

我只是偶然发现了一个非常相似的情况。我的设置:

  • 包含几种CPropertySheets的CPropertyPage
  • 一个CTabCtrl内的CPropertyPage
  • 几个CDialogs作为CTabCtrl的一部分
  • 在一个特定的CDialog中使用一个控件然后切换到另一个应用程序(例如,通过命中断点的Visual Studio)将停止我的应用程序(相应的CPU核心以100%负载结束)
  • 在相同的特定CDialog中使用控件但在切换到另一个应用程序之前切换到另一个CPropertyPage不会导致任何问题

经过一些研究,我发现了this Knowledge Base article,这暗示了我的解决方案。触发失速的特定CDialog在其资源定义中具有行EXSTYLE WS_EX_CONTROLPARENT。删除线解决了问题。

这可以防止能够插入CDialog,但这个问题稍微不那么严重,我可能会在另一天回到它。


0
投票

我有一个类似的问题。我有多个嵌套窗口,一些具有WS_EX_CONTROLPARENT样式,一些没有。问题是:所有内部窗户都必须具有这种风格,或者都没有(至少显然)。

© www.soinside.com 2019 - 2024. All rights reserved.