【发布时间】:2010-11-04 21:04:33
【问题描述】:
开始这个问题的 V 2.0。
我的 VC++ MFC 应用程序编译并运行良好。也就是说,直到我切换到另一个窗口。一旦我的程序失去焦点,它就会冻结;我无法切换回它,如果我移动它前面的窗口,我的应用程序窗口在另一个窗口覆盖的空间中显示为白色。
自从我第一次发布这个问题以来,我已经能够查明我的程序的哪个部分导致了这种行为,但我仍然不知道哪些代码行是错误的或为什么。
我的 MFC 应用程序的主对话框包含一个名为 m_MainTabControl 的 CTabCtrl。这个主选项卡控件包含两个标记为“基本设计”和“高级设计”的选项卡,每个选项卡都与它们自己的对话框相关联。两个对话框都包含一个带有多个选项卡的 CTabCtrl。于是我的问题就诞生了。
当我第一次创建这个 tab-within-tab 结构时,当我尝试在内部选项卡之间切换时,我遇到了我的程序冻结的问题。不用说我对此感到困惑,直到我注意到如果我首先单击一个内部选项卡上的控件,我就可以很好地切换选项卡。因此,在没有完全理解问题所在的情况下,我将焦点设置在程序启动时第一个内部选项卡的第一个内部选项卡上。问题解决了一半。当我运行程序时,我可以点击第一组内部选项卡。如果我切换到第二个外部选项卡并尝试单击其内部选项卡而不首先单击对话框控件,它将再次冻结。所以我做了一个 Focus 函数来聚焦当前选定的外部选项卡的当前选定的内部选项卡,并在我的选项卡更改事件中调用它(当您单击另一个选项卡时会关闭)。
这就是我第一次提出这个问题时的目的。我以为我的程序运行得很好,直到我多玩了一会儿,发现当我在它和另一个窗口或程序之间来回切换时它玩得不好。更具体地说,一旦我的程序失去焦点,某些进程就会失控并占用整个 CPU 的处理价值。
现在,我如此详细地解释了我的小标签结构和焦点问题的原因:经过大量实验,我发现如果我注释掉外部标签结构上的第二个标签(即“高级设计”对话框和它所有的小子标签)我的程序的其余部分运行良好,我可以毫不费力地切换到另一个窗口并返回。 “太好了,”我想,“这只是我刚刚注释掉的程序的大约 90% 以使其正常工作。让我们尝试进一步削减它。”我将“高级设计”选项卡式对话框放回原处,但注释掉了由“高级设计”中的选项卡控件创建的选项卡式对话框,一切仍然正常。我一一放回属于“高级设计”选项卡控件的选项卡式对话框,每次我重新引入错误时,无论我取消注释哪个选项卡。我还应该指出,我尝试放回的第一个选项卡(当然是单独的)是我的“边距”选项卡,它是一个 MarginDlg 类,我也可以在我的“基本设计”选项卡下毫无问题地使用它。这让我相信,在选项卡式对话框中创建选项卡式对话框时,我必须做一些我没有做或做错的事情,就像我一开始必须搞乱焦点以使其工作一样。
我将非常感谢任何可以阐明这种情况的信息。我包括了我认为相关的sn-ps代码;与往常一样,如果需要更多信息,请告诉我。
来自主对话框的 .h 文件的变量声明:
//tab stuff
CTabCtrl m_MainTabControl;
vector<CDialog*> m_tabPages;
SimpDesDlg* simpDesDlg;
AdvDesDlg* advDesDlg;
当我的应用程序启动时,它会创建我的主对话框,并调用 OnInitDialog(): (TODO 上面的所有内容:comment 是默认的 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;
}
【问题讨论】:
-
当你启动你的程序时,在你做任何事情之前,它是否会占用 CPU?在我看来,您有一个失控的进程,阻止了消息的处理。在此调用堆栈和您在下面的评论(关于 OnInitDialog 中的焦点)之间,这绝对是对话框上所有控件之间的交互。如果您不知道哪些可能有隐藏的处理循环,请开始将它们注释掉,直到行为消失。当我在应该在线程中的主窗口循环中进行处理时,我肯定会得到你描述的情况(没有油漆,没有分钟)。
-
对不起,但我不明白你所说的“在主窗口循环中处理应该在一个线程中”是什么意思。我正在上大学,所以还有一些东西我还没有学到,线程就是其中之一。我需要了解多少才能了解如何线程化一个进程,在这种情况下,我假设它与我的对话框上的控件有关?抱歉这里一无所知...
-
另外,我只是在任务管理器打开的情况下运行我的程序,这样我就可以观察我的进程。当我第一次打开程序时,它占用了大约 5400K 的内存和 00 个 CPU。由于我只是单击浏览器窗口输入这些数字,因此程序进入冻结状态并增加了 25 个 CPU(周期?)。我不知道你认为什么会占用 CPU,但我猜它开始占用 0 的事实意味着它最初并没有占用它。
-
最后,我会尝试注释掉控件。我想我应该一次只注释掉一个控件,然后看看当我移动到另一个窗口时程序是否仍然冻结,但是如果我可以隔离哪些控件正在造成混乱,你对我有什么建议吗?应该对它/他们做些什么来让它/他们表现出来,还是你需要看代码才能说?
-
我实际上完全被你的描述弄糊涂了(什么都不做,当你点击离开时,它们会跳跃 25%)。一些控制变得疯狂。
标签: c++ visual-studio visual-studio-2008 visual-c++ mfc