Имеется такой вот простенький код:
void CBimapsView::OnButton32774()
{
CRgn rg;
//запомнили первоначальный
GetWindowRgn(oldRegion);
rg.CreateEllipticRgn(10,10,200,200);
//установили эллипсовидный
SetWindowRgn(rg,TRUE);
}
void CBimapsView::OnButton32776()
{
//восстановили первоначальный
SetWindowRgn(oldRegion,TRUE);
}
Смысл — по щелчку одной кнопки окно становится круглым, а по щелчку на другой — восстанавливает свою форму. И не работает. А вот если пользоваться аналогичными функциями API и сохранять состояние не в переменной-члене класса C*View, а C*App то работает. Почему?
Здравствуйте Xenia, Вы писали:
X>Имеется такой вот простенький код:
X>void CBimapsView::OnButton32774()
X>{
X> CRgn rg;
X>//запомнили первоначальный
X> GetWindowRgn(oldRegion);
X> rg.CreateEllipticRgn(10,10,200,200);
X>//установили эллипсовидный
X> SetWindowRgn(rg,TRUE);
Не работает, потому что вот в этот момент переменная rg
уничтожается, а вместе с ней и регион, назначенный окну.
Очевидно, нужно сделать rg членом класса, как и oldRegion.
X>}
X>void CBimapsView::OnButton32776()
X>{
X> //восстановили первоначальный
X> SetWindowRgn(oldRegion,TRUE);
X>}
Здравствуйте Alex Fedotov, Вы писали:
AF>Здравствуйте Xenia, Вы писали:
X>>Имеется такой вот простенький код:
AF>X>>void CBimapsView::OnButton32774()
X>>{
X>> CRgn rg;
X>>//запомнили первоначальный
X>> GetWindowRgn(oldRegion);
X>> rg.CreateEllipticRgn(10,10,200,200);
X>>//установили эллипсовидный
X>> SetWindowRgn(rg,TRUE);
AF>Не работает, потому что вот в этот момент переменная rg
AF>уничтожается, а вместе с ней и регион, назначенный окну.
AF>Очевидно, нужно сделать rg членом класса, как и oldRegion.
AF>
Делаю rg членом класса и все равно не работает, а вот между прочим если написать
AF>X>>void CBimapsView::OnButton32774()
X>>{
X>> CRgn rg;
X>>//запомнили первоначальный
X>> GetWindowRgn(oldRegion);
X>> rg.CreateEllipticRgn(10,10,200,200);
X>>//установили эллипсовидный
X>> ::SetWindowRgn(AfxGetMainWnd()->m_hWnd,rg,TRUE); т.е. используем API, то работает, хотя rg по прежнему локальная переменная. Но вот обратно окно все равно не восстанавливает
AF>
Здравствуйте Xenia, Вы писали:
X>>>Имеется такой вот простенький код:
X>>>void CBimapsView::OnButton32774()
X>>>{
X>>> CRgn rg;
X>>>//запомнили первоначальный
X>>> GetWindowRgn(oldRegion);
X>>> rg.CreateEllipticRgn(10,10,200,200);
X>>>//установили эллипсовидный
X>>> SetWindowRgn(rg,TRUE);
AF>>Не работает, потому что вот в этот момент переменная rg
AF>>уничтожается, а вместе с ней и регион, назначенный окну.
AF>>Очевидно, нужно сделать rg членом класса, как и oldRegion.
X>Делаю rg членом класса и все равно не работает, а вот между прочим если написать
X>>>void CBimapsView::OnButton32774()
X>>>{
X>>> CRgn rg;
X>>>//запомнили первоначальный
X>>> GetWindowRgn(oldRegion);
X>>> rg.CreateEllipticRgn(10,10,200,200);
X>>>//установили эллипсовидный
X>>> ::SetWindowRgn(AfxGetMainWnd()->m_hWnd,rg,TRUE); т.е. используем API, то работает, хотя rg по прежнему локальная переменная. Но вот обратно окно все равно не восстанавливает
Так это разные окна. Одно окно, судя по названию — view, а другое — главное окно программы, m.е. frame.
Это MDI, SDI-программа или нечто другое?
Согласна, стормозила. Это не то окно. (Само приложени SDI)
Ну вот я это исправляю таким образом:
void CBimapsView::OnButton32774()
{
CRgn rg;
//запомнили первоначальный
AfxGetMainWnd()->GetWindowRgn(oldRegion);
rg.CreateEllipticRgn(10,10,200,200);
//установили эллипсовидный
//::SetWindowRgn(AfxGetMainWnd()->m_hWnd,rg,TRUE);
AfxGetMainWnd()->SetWindowRgn(rg,TRUE);
}
void CBimapsView::OnButton32776()
{
//восстановили первоначальный
AfxGetMainWnd()->SetWindowRgn(oldRegion,TRUE);
}
И окно таки сворачивается, но обратно не восстаналивается. Вот почему оно не восстанавливается, меня очень интересует. Ведь если запомнтиь первоначальный регион в функции C*App.InitInstance() то оно восстанавливается. Какая разница где его запоминать?
Здравствуйте Xenia, Вы писали:
X>X>void CBimapsView::OnButton32774()
X>{
X>
X> CRgn rg;
X>//запомнили первоначальный
X> AfxGetMainWnd()->GetWindowRgn(oldRegion);
X> rg.CreateEllipticRgn(10,10,200,200);
X>//установили эллипсовидный
//::SetWindowRgn(AfxGetMainWnd()->>m_hWnd,rg,TRUE);
X> AfxGetMainWnd()->SetWindowRgn(rg,TRUE);
X>
X>}
X>void CBimapsView::OnButton32776()
X>{
X> //восстановили первоначальный
X> AfxGetMainWnd()->SetWindowRgn(oldRegion,TRUE);
X>}
X>
X>Смысл — по щелчку одной кнопки окно становится круглым, а по щелчку на другой — восстанавливает свою форму. И не работает. А вот если пользоваться аналогичными функциями API и сохранять состояние не в переменной-члене класса C*View, а C*App то работает. Почему?
Я набросал примерчик, лежит на
http://www.alexfedotov.com/samples/winrgn.zip
Вот замечания:
1. У меня сложилось впечатление, что ты пытаешься отлаживать программу в Release-конфигурации. Во всяком случае, ты ничего не говорила про debug assertions, а они должны быть
2. Команды установки и снятия региона относятся к главному окну, так почему бы их туда и не поместить? В моем примере они находятся в классе CMainFrame.
Теперь по существу:
void CMainFrame::OnSetRgn()
{
RECT rcWindow;
GetWindowRect(&rcWindow);
rcWindow.right -= rcWindow.left;
rcWindow.bottom -= rcWindow.top;
CRgn rgn;
VERIFY(rgn.CreateRoundRectRgn(0, 0, rcWindow.right, rcWindow.bottom, 80, 80));
m_OldRgn.CreateRectRgn(0, 0, 0, 0);
if (!GetWindowRgn(m_OldRgn))
m_OldRgn.DeleteObject();
VERIFY(SetWindowRgn((HRGN)rgn.Detach(), TRUE));
}
3. Функция GetWindowRgn ожидает на вход действительный HRGN, поэтому прежде чем давать m_OldRgn на вход этой функции, его надо инициализировать. В показанном тобой коде непонятно, где это происходит, и происходит ли вообще.
4. Нормальные прямоугольные окна не имеют региона. Если вызвать GetWindowRgn для такого окна, она просто возвращает FALSE (а ведь в книжках учат — проверяйте возвращаемое значение функций, хотя бы с помощью VERIFY). Поэтому логика такая: a) создаем регион, б) вызываем GetWindowRgn; в) теперь если функция завершилась успешно, мы получили регион окна, в противном случае г) уничтожаем регион. В результате мы имеет m_OldRgn.m_hObject != NULL, если у окна есть регион, и m_OldRgn.m_hObject == NULL, если его нет.
5. Документация на функцию SetWindowRgn гласит:
<!-- msdn -->
After a successful call to SetWindowRgn, the system owns the region specified by the region handle hRgn. The system does not make a copy of the region. Thus, you should not make any further function calls with this region handle. In particular, do not delete this region handle. The system deletes the region handle when it no longer needed.
<!-- /msdn -->
Поэтому ни сохранять этот регион (как я изначально советовал), ни удалять его (что произойдет в деструкторе CRgn, если не предпринять дополнительных действий) нельзя. Чтобы HRGN не удалился в деструкторе CRgn, его нужно отсоединить от объекта с помощью метода Detach(), как показано в примере.
void CMainFrame::OnRestoreRgn()
{
SetWindowRgn((HRGN)m_OldRgn.Detach(), TRUE);
}
6. Восстановление региона просто: если у нас есть сохраненный регион, мы отсоединяем его от объекта и назначаем окну. В противном случае мы вызываем SetWindowRgn c HRGN, равным NULL, что приводит к восстановлению нормальной прямоугольной формы окна.
Большое спасибо за подробные разъяснения и пример!
Кстати, работала я в Debug версии и никаких assert' ов не было