Начало V 2.0 этого вопроса.
Мое приложение VC ++ MFC компилируется и работает просто отлично. То есть, пока я не переключусь на другое окно. Как только моя программа теряет фокус, она зависает; Я не могу переключиться обратно на него, и если я переместлю окно, которое находится перед ним, мое окно приложения будет отображаться белым в пространстве, которое закрывало другое окно.
С тех пор, как я впервые опубликовал этот вопрос, я смог определить, какая часть моей программы вызывает такое поведение, но я до сих пор не знаю, какие строки кода неправильные или почему.
Основной диалог моего приложения MFC содержит CTabCtrl с именем m_MainTabControl. Этот основной элемент управления вкладками содержит две вкладки с надписью «Базовый дизайн» и «Расширенный дизайн», каждая из которых связана со своими собственными диалоговыми окнами. Оба диалоговых окна содержат CTabCtrl с несколькими вкладками. И таким образом моя проблема рождается.
Когда я впервые создал эту структуру вкладок внутри вкладок, у меня были проблемы с зависанием моей программы, когда я пытался переключаться между внутренними вкладками. Само собой разумеется, я был озадачен этим, пока не заметил, что, если я сначала нажму на элемент управления на одной из внутренних вкладок, то смогу переключать вкладки очень хорошо. Поэтому, не понимая полностью, в чем проблема, я установил фокус на первую внутреннюю вкладку первой внутренней вкладки при запуске программы. Проблема наполовину решена. Когда я запустил программу, я мог просто щелкнуть по первому набору внутренних вкладок; если бы я переключился на вторую внешнюю вкладку и попытался щелкнуть по ее внутренним вкладкам, не щелкая сначала по диалоговому элементу управления, он бы снова завис Поэтому я сделал функцию «Фокус», чтобы сфокусировать текущую выбранную внутреннюю вкладку выбранной в данный момент внешней вкладки, и вызвал ее в событии изменения вкладки (то, которое срабатывает при нажатии на другую вкладку).
Так я дошел до того момента, когда впервые задал этот вопрос. Я думал, что моя программа работает просто отлично, пока я не поиграл с ней немного больше и не заметил, что она играет не очень хорошо, когда я переключался между ним и другим окном или программой. Точнее говоря, как только моя программа выходит из фокуса, некоторые процессы теряют свою актуальность и занимают весь процессорный процесс.
А теперь, причина, по которой я так подробно объяснил свою маленькую структуру вкладок и проблемы с фокусировкой: после долгих экспериментов я обнаружил, что, если я закомментировал вторую вкладку в моей внешней структуре вкладок (то есть диалоговое окно «Расширенный дизайн» и все его дочерние вкладки) остальная часть моей программы работает нормально, и я могу переключиться на другое окно и вернуться без боя. «Отлично, - подумал я, - это всего лишь около 90% моей программы, которую я только что прокомментировал, чтобы это заработало. Давайте попробуем и дальше урезать». Я вернул диалоговое окно с вкладками «Advanced Design» обратно, но прокомментировал диалоги с вкладками, созданные элементом управления вкладками в «Advanced Design», и все по-прежнему работало нормально. Один за другим я возвращал диалоги с вкладками, принадлежащие элементу управления вкладками «Advanced Design», и каждый раз снова вводил «Ошибка» независимо от того, какую вкладку я раскомментировал. Я также должен отметить, что одной из первых вкладок, которые я попытался вернуть (конечно, в одиночку), была моя вкладка «Margins», которая является классом MarginDlg, который я также использую под вкладкой «Базовый дизайн» без проблем. Это заставляет меня верить, что есть что-то конкретное, что я должен делать при создании диалогов с вкладками в диалогах с вкладками, которые я не делаю или делаю неправильно, вроде того, как мне пришлось возиться с фокусировкой, чтобы сначала это работало.
Я был бы чрезвычайно благодарен за любой свет, который можно пролить на ситуацию. Я включаю то, что я считаю релевантными фрагментами кода; как всегда, дайте мне знать, если потребуется больше.
объявления переменных из файла .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);
}
}
А Фокус () и изменение вкладки:
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;
}