Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > Позиционирование элементов


Автор: Coocky 5.7.2006, 17:01
Хех. Столкнулся с проблемой.
У меня есть диалог с битмапами на морде.
Диалог имеет свойство resaizing- таскал я его туда-сюда до посинения.
Все было хорошо пока таскал за правый край.
Но стоило потащить за левый...как битмапы стали прыгать smile 
Да, именно прыгать  smile  Такое ощущение, что они идут за окном влево, но лишь на миг,потом кто-то дает им команду, и они возвращаются в исходное положение smile . Короче эффект еще хуже чем от мерцания.
А вот правый край радует сердце. Все Ок и влево и вправо..
Вот примерный код позиционирования битмапов в прорисовке окна.
Код

..................................
  GetClientRect(&rect);

  pDC1.BitBlt(0,0,bitmapinfo2.bmWidth,bitmapinfo2.bmHeight,&memDC2,0,0,SRCCOPY);

  pDC1.StretchBlt(bitmapinfo2.bmWidth,0,rect.Width()-bitmapinfo2.bmWidth-  bitmapinfo4.bmWidth,bitmapinfo2.bmHeight,&memDC3,0,0,bitmapinfo3.bmWidth,bitmapinfo3.bmHeight,SRCCOPY);

  pDC1.BitBlt(rect.right-bitmapinfo4.bmWidth,0,bitmapinfo4.bmWidth,bitmapinfo4.bmHeight,&memDC4,0,0,SRCCOPY);
..............................
 
 dc.BitBlt(0,0,rect.Width(),rect.Height(),&pDC1,0,0,SRCCOPY);

Может поможет кто.. smile  

Автор: SergeCpp 6.7.2006, 07:30
Приведите весь код, связанный с bitmapinfo2, bitmapinfo3 и bitmapinfo4

А также memdc2, 3, 4
 

Автор: Coocky 6.7.2006, 09:48
SergeCpp
Не вижу смысла, но привожу smile 
Код

bmp2.LoadBitmap(IDB_BITMAP17);
bmp3.LoadBitmap(IDB_BITMAP18);
bmp4.LoadBitmap(IDB_BITMAP19);
......................................................
bmp2.GetBitmap(&bitmapinfo2);
bmp3.GetBitmap(&bitmapinfo3);
bmp4.GetBitmap(&bitmapinfo4);
.......................................................
memDC2.CreateCompatibleDC(&dc);
memDC2.SelectObject(&bmp2);
memDC3.CreateCompatibleDC(&dc);
memDC3.SelectObject(&bmp3);
memDC4.CreateCompatibleDC(&dc);


Все smile 
Это все происходит в OnInitDialog smile

Добавлено @ 09:54 
Хех. Это баг похоже от Мелких (никогда не сомневался в своем прфессионализме smile  smile )..
Откройте проводник в Винде (или любое окно).  Таскайте за правый край smile .
Теперь за левый smile . Обратите внимание на поведение флажка в правом верхнем углу smile 
Теперь вопрос- почему это происходит и как же все таки от этого избавится? 

Автор: Dart 6.7.2006, 11:16
Цитата(Coocky @  6.7.2006,  09:48 Найти цитируемый пост)
Теперь вопрос- почему это происходит и как же все таки от этого избавится? 

Переписать OnSize в CWnd smile  smile 
А если серьезно, то проблема эта происходит по-моему от того, что в стандарте мелкомягкие, похоже, не утруждают себя стиранием бэкграунда перед рисованием при ресайзе. По-моему, так.
Если я прав, тогда достаточно переопределить OnEraseBkgnd в твоем классе и ручками стирать бэкграунд под всеми битмапами перед вызовом OnSize родителя. Правда, при этом эта зараза может начать мерцать, но как ты заметил,
Цитата(Coocky @  5.7.2006,  17:01 Найти цитируемый пост)
эффект еще хуже чем от мерцания

это все таки лучше, чем прыгание 

Автор: SergeCpp 6.7.2006, 11:21
Рисуйте на контексте памяти, стирая bitmap в нём при изменении размеров и копируйте в контекст устройства целиком — мерцания не будет.
Правда, размер контекста памяти (и bitmap в нём) придётся выбирать с запасом — по максимальному размеру Вашего окна. 

Вот примерчик... Смотрите файл Interface\LifeView.cpp, BOOL LifeView::OnEraseBkgnd( CDC* ) и далее...

Запустите ту программу и поменяйте размер окна — примерчик в действии... 

Автор: Coocky 6.7.2006, 11:55
SergeCpp
Dart
http://forum.vingrad.ru/index.php?showtopic=99226
 smile 
Или я что-то не так понял? smile 
Да помоему из кода видно
Код

  GetClientRect(&rect);

  pDC1.BitBlt(0,0,bitmapinfo2.bmWidth,bitmapinfo2.bmHeight,&memDC2,0,0,SRCCOPY);

  pDC1.StretchBlt(bitmapinfo2.bmWidth,0,rect.Width()-bitmapinfo2.bmWidth-  bitmapinfo4.bmWidth,bitmapinfo2.bmHeight,&memDC3,0,0,bitmapinfo3.bmWidth,bitmapinfo3.bmHeight,SRCCOPY);

  pDC1.BitBlt(rect.right-bitmapinfo4.bmWidth,0,bitmapinfo4.bmWidth,bitmapinfo4.bmHeight,&memDC4,0,0,SRCCOPY);
..............................
 
 dc.BitBlt(0,0,rect.Width(),rect.Height(),&pDC1,0,0,SRCCOPY);

Что рисую я на контексте памяти

Цитата(Dart @  6.7.2006,  11:16 Найти цитируемый пост)
А если серьезно, то проблема эта происходит по-моему от того, что в стандарте мелкомягкие, похоже, не утруждают себя стиранием бэкграунда перед рисованием при ресайзе. По-моему, так.


Цитата(SergeCpp @  6.7.2006,  11:21 Найти цитируемый пост)
Рисуйте на контексте памяти, стирая bitmap в нём при изменении размеров и копируйте в контекст устройства целиком — мерцания не будет.
Правда, размер контекста памяти (и bitmap в нём) придётся выбирать с запасом — по максимальному размеру Вашего окна. 


Цитата(Coocky @  5.7.2006,  17:01 Найти цитируемый пост)
Все было хорошо пока таскал за правый край.


Цитата(Coocky @  5.7.2006,  17:01 Найти цитируемый пост)
Но стоило потащить за левый...как битмапы стали прыгать 


Цитата(Coocky @  6.7.2006,  09:48 Найти цитируемый пост)
Откройте проводник в Винде (или любое окно).  Таскайте за правый край


Цитата(Coocky @  6.7.2006,  09:48 Найти цитируемый пост)
Теперь за левый  . Обратите внимание на поведение флажка в правом верхнем углу 

 

Автор: SergeCpp 6.7.2006, 11:58
OnEraseBkgnd у Вас переопределена? 

Автор: vvpC 6.7.2006, 12:16
Можно запретить прорисовку в процессе ресайзинга настройкой винды.

А можно и програмно - повесив флаг в начале ресайзинга(WM_SIZING) контролировать его в WM_SIZE, если TRUE -перерисовывать по минимуму или вообще ничего не рисовать. Конец ресайзинга контролировать в WM_NCHITTEST, висит флаг - полная перерисовка и снятие флага  

Автор: Dart 6.7.2006, 12:32
Цитата(Coocky @  6.7.2006,  11:55 Найти цитируемый пост)
Что рисую я на контексте памяти

Да, но перед этим рисованием занимается стандартный обработчик Windows. А он-то похоже сначала сдвидает всё окно в новые координаты, а только потом отдает обработку в OnPaint
Я-то как раз про это говорил. 

Автор: Coocky 6.7.2006, 12:46
Цитата(SergeCpp @  6.7.2006,  11:58 Найти цитируемый пост)
OnEraseBkgnd у Вас переопределена?

Ну это как отче наш.. smile 
Ребята, поймите -у меня НЕТ мигания . У меня "прыганье кнопок". Т.е вроде как отрисовываются с одними координатами, а потом сразу же отрисовываются с другими smile 
vvpC
Dart
насколько я понял нажно поставить флаг разрешения моей отрисовки FALSE  в обработчике MyDlg::OnSize() ПЕРЕД CDialog::OnSize и TRUE ПОСЛЕ него сразу? 

Автор: takedo 6.7.2006, 13:03
так то понять не могу как за левый - ок, а за правый - нет, но попробуй для ясности не рисовать битмап, а поставь dc.Rectangle, и по трасе смотри координаты. Если координаты реально прыгают - тогда пока хз, а если нет - то тоже хз, но все таки понятней будет.
PS.: а микрософт конечно имеет косяки, но все на них валить не стоит. А при передвигании проводника я ничего подозрительного с флагом не заметил smile  

Автор: vvpC 6.7.2006, 13:13
Цитата(Coocky @  6.7.2006,  12:46 Найти цитируемый пост)
насколько я понял нажно поставить флаг разрешения моей отрисовки FALSE  в обработчике MyDlg::OnSize() ПЕРЕД CDialog::OnSize и TRUE ПОСЛЕ него сразу?  
 Вот мои обработчики изменяющие состояние флага, но у меня несколько другой случай - я перепозиционирую контролы, а не просто рисую битмапы в нужном месте. Поэтому я проверяю флаг в OnSize, а тебе похоже это надо делать в OnPaint(). Но идея думаю понятна - исключить рисование не слишком важных(или громоздких) элементов в процессе изменения размеров окна.
Код

void CCalculatorDlg::OnSizing(UINT fwSide, LPRECT pRect)
{
    m_SizingFlag=TRUE;
    CDialog::OnSizing(fwSide, pRect);
}

UINT CCalculatorDlg::OnNcHitTest(CPoint point)
{
    if(m_SizingFlag)
    {
        m_SizingFlag=FALSE;
        Invalidate();
    }
    return CDialog::OnNcHitTest(point);
}


  

Автор: takedo 6.7.2006, 13:44
Coocky, да, проводник с флагом ведет себя именно так как ты и говорил. И это косяк микрософт (****). Получается видимо вот что: при резицинге приходит новый прямоугольник, они ему MoveWindow, а в этот момент довыполняется код OnPaint но со старыми координатами прямоугольника. Попробуй(я конечно не уверен, но могу предполагать) перехватить на родителе в PreTranslateMessage сообщение WM_Paint и посылай его по SendMessage - у нее приоритет выше PostMessage, что делает Invalidate().

Модератор: просьба не аппелировать к национальности, расе и т.д.   

Автор: takedo 6.7.2006, 17:18
подумал ещё и понял, что так как я предложил неполучится. А не получится потому, что в PreTranslateMessage приходит уже сообщение из очереди(WM_PAINT из очереди асинхронных сообщений). Я предполагаю, что WM_SIZE посылается синхронно, то есть выполнение WM_PAINT в это время прерывается и продолжается дальше при новых размерах окна, но со старыми параметрами.
Делать надо видимо так: 
1)ловить начало и конец резицинга как советовал vvpC
2)в PreTranslateMessage ловить WM_SIZE и посылать WM_SIZE+WM_PAINT(но для всех необходимых контролов подряд, неудобно, но другого я не придумал) синхронно; также надо ловить и WM_PAINT, который игнорировать в случае, когда идет резицинг.
3)по окончанию резицинга надо бы очистить очередь с WM_PAINT - как это сделать не знаю(надо Рихтера почитать), а возможно будет достаточно для очистки послать всем окнам WM_PAINT?

Думаю, что суть проблемы мне удалось ухватить smile , если это так, то решение должно со временем прийти(если моё кривое smile ).
напиши когда поборешь, плз.

Добавлено @ 17:20 
Earnest, так я просто немного зол на программистов микрософт за входящую очередь в com порте при асинхронной передаче, там также рассинхронизация действий!!! Пришлось самому писать свою очередь rx!!! Оно мне очень надо? smile  

Автор: Coocky 7.7.2006, 12:03
Ничего не выходит  smile  

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)