Здравствуйте, Marty, Вы писали:
И еще одно замечание. Если вам нужно точно прорисовывать 30 раз в секунду, то лучше использовать мультимедийный таймер и рисовать в фоновом потоке, чем использовать системный таймер и сообщения WM_TIMER по двум причинам:
1. Сообщение WM_TIMER имеет наименьший приоритет.
2. Если я правильно помню, его минимальная разрешающая способность чуть больше 18 миллисекунд, а 30 раз в секунду — это 33,3 миллисекунд. Павда эта информация, может быть, устарела так как относилась к Windows 95/98. Для более поздних Windows я такой информации не видел M>Здравствуйте! M>Есть следующая логика. M>Раз в 30 в секунду файрится OnTimer, который делает Invalidate для всей клиентской части. В OnPaint рисуется сцена, с дабл буфферингом: M>
DoPaint
M>
M> void DoPaint(CDCHandle dc)
M> {
M> CPoint clientSize = getClientSizePoint();
M> cachedBitmapSize = clientSize;
M> CDC memDc = ::CreateCompatibleDC(dc.m_hDC);
M> HBITMAP hMemBmp = ::CreateCompatibleBitmap ( dc.m_hDC, clientSize.x, clientSize.y );
M> HBITMAP hOldBmp = memDc.SelectBitmap(hMemBmp);
M> RECT clRect;
M> clRect.left = 0;
M> clRect.top = 0;
M> clRect.right = clientSize.x;
M> clRect.bottom = clientSize.y;
M> //::FillRect(memDc, &clRect, (HBRUSH)COLOR_WINDOW);
M> memDc.FillRect(&clRect, (HBRUSH)COLOR_WINDOW);
M> //memDc.FillRect(&clRect, (HBRUSH)COLOR_HOTLIGHT);
M> auto idc = makeMultiDc(memDc.m_hDC, marty_draw_context::HdcReleaseMode::doNothing, m_hWnd);
M> IDrawContext *pDc = &idc;
M> DoPaintImpl(pDc);
M> ::BitBlt( dc.m_hDC // A handle to the destination device context.
M> , 0, 0 //dstX, dstY // The x/y-coordinates, in logical units, of the upper-left corner of the destination rectangle.
M> , clientSize.x, clientSize.y // The width/height, in logical units, of the source and destination rectangles.
M> , memDc.m_hDC // hdcCopyFrom // A handle to the source device context.
M> , 0, 0 // The x/y-coordinate, in logical units, of the upper-left corner of the source rectangle.
M> , SRCCOPY // A raster-operation code - Copies the source rectangle directly to the destination rectangle.
M> );
M> ::SelectObject(memDc, hOldBmp);
M> if (hbitmapCached)
M> {
M> ::DeleteObject(hbitmapCached);
M> }
M> hbitmapCached = hMemBmp;
M> }
M>
M>Отрисованную тут сцену я сохраняю в hbitmapCached. M>Далее. Есть события мыши. Я не хочу перерисовывать сцену по событиям мыши, хочу рисовать допустим только какой-то rect, от нажатия кнопки мыши до текущего положения, или, даже, просто циркуль-кругляшик на месте курсора, если ничего не нажато на мышке. M>Для этого я по событиям мыши делаю GetDC(), создаю компат MemDc, копирую туда закешированную картинку, и вызываю событие мыши M>
M>Я проверял, таймерное событие перестаёт обрабатываться. Никакой onUpdate не вызывается — он бы мог перетирать то, что рисуется по мышахиным событиям. По идее, остаются только события мыши. Они происходят, тоже проверил. Все координаты и все события отдаются в обработики. Всё нормас. Только отрисовка поверх кешированного битмапа в обработчике мыши не работает. DC и копирование кеша картинки делаю так: M>
M> marty_draw_context::MultiDrawContext makeMultiDc(HDC hdc, marty_draw_context::HdcReleaseMode hdcReleaseMode, HWND hwnd)
M> {
M> #ifdef TEST_DC_USE_GDIPLUS
M> return marty_draw_context::makeMultiDrawContext(hdc, true/* prefferGdiPlus */, hdcReleaseMode, hwnd);
M> #else
M> return marty_draw_context::makeMultiDrawContext(hdc, false/* prefferGdiPlus */, hdcReleaseMode, hwnd);
M> #endif
M> }
M> void copyCachedBitmapToHdc(HDC hdc)
M> {
M> if (!hbitmapCached)
M> {
M> #if defined(VIEW04_LOG_SQUIRREL_CALLS)
M> using umba::lout;
M> lout << "copyCachedBitmapToHdc, !hbitmapCached\n";
M> umba::lout.flush();
M> #endif
M> return;
M> }
M> CDC memDc = ::CreateCompatibleDC(hdc);
M> HBITMAP hOldBmp = memDc.SelectBitmap(hbitmapCached);
M> ::BitBlt( hdc // A handle to the destination device context.
M> , 0, 0 //dstX, dstY // The x/y-coordinates, in logical units, of the upper-left corner of the destination rectangle.
M> , cachedBitmapSize.x, cachedBitmapSize.y // The width/height, in logical units, of the source and destination rectangles.
M> , memDc.m_hDC // hdcCopyFrom // A handle to the source device context.
M> , 0, 0 // The x/y-coordinate, in logical units, of the upper-left corner of the source rectangle.
M> , SRCCOPY // A raster-operation code - Copies the source rectangle directly to the destination rectangle.
M> );
M> ::SelectObject(memDc, hOldBmp);
M> }
M> void prepareDrawContext( marty_draw_context::IDrawContext *pDc )
M> {
pDc->>setStringEncoding("UTF-8");
pDc->>setBkMode( BkMode::transparent );
pDc->>setSmoothingMode(SmoothingMode::antiAlias); // highSpeed highQuality antiAlias defMode none
M> }
M> marty_draw_context::MultiDrawContext makeDcForMouseHandler()
M> {
M> HDC hdc = ::GetDC(m_hWnd);
M> copyCachedBitmapToHdc(hdc);
M> marty_draw_context::MultiDrawContext mdc = makeMultiDc(hdc, marty_draw_context::HdcReleaseMode::releaseDc, m_hWnd);
M> return mdc;
M> }
M>
M>Вроде логика продумана нормас, реализация вроде тоже без косяков, но мышахины события не работают, как задумано — по нажатию ЛКМ не рисуется условный rect мышахиного выделения. Сцена есть, никуда не пропадает, координаты мыши, состояние кнопок и тп — исправно передаются в обработчики, но долбаного rect'а мышахиного выделения поверх сцены не происходит. M>Что я тут не так сделал, где косяк? M>Проект сам тут, кому интересно поковырять — https://github.com/al-martyn1/marty_dc_impl_win32 M>Надо зайти в tests/_libs и запустить clone_libs_http.bat M>Проект сам — tests/tests-msvc2019.sln M>Используется WTL, путь к WTL должен быть задан через переменную среды %WTL% M>Версия WTL плюс-минус насрать, у меня 10ая, но ничего особого нового не используется, думаю, и седьмая сойдёт — там после седьмой версии кроме собственно номера версии ничего особо и не менялось
Re[2]: Где проджоб? Логика или накосячил с WinAPI?
Здравствуйте, Melamed, Вы писали:
M>И еще одно замечание. Если вам нужно точно прорисовывать 30 раз в секунду, то лучше использовать мультимедийный таймер и рисовать в фоновом потоке, чем использовать системный таймер и сообщения WM_TIMER по двум причинам: M>1. Сообщение WM_TIMER имеет наименьший приоритет. M>2. Если я правильно помню, его минимальная разрешающая способность чуть больше 18 миллисекунд, а 30 раз в секунду — это 33,3 миллисекунд. Павда эта информация, может быть, устарела так как относилась к Windows 95/98. Для более поздних Windows я такой информации не видел
Спасибо, я в курсе, мне наплевать на точность таймера
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, Melamed, Вы писали:
M>>И еще одно замечание.
M>Ну и извини. Может, тебе стоит сосредоточится на своей курсовой?
Спасибо. Все курсовые мною написаны. А сейчас пишу большой проект.