Рисование от руки на весь экран - PullRequest
4 голосов
/ 30 сентября 2011

Я пытаюсь создать простой маленький инструмент, который позволил бы пользователю переключаться из обычной работы в режим, в котором все сообщения приложения отключены, и они могут использовать мышь для рисования от руки, а затем снова переключать режимы, чтобы сохранитьих рисование на экране, в то время как они делают любые другие нормальные вещи, которые они хотят.Это может, если я решу, превратиться в приятную вещь, которую вы можете использовать для использования декорированного экрана, сохранив сделанные вами декорации и загрузив их позже.

Когда я начал это (что было более полугода назад,вскоре после обнаружения Windows API) я просто сделал глобальное отслеживание мыши и нарисовал круг, где бы он ни был, для GetDC (NULL) HDC.Проблемы, конечно, заключались в том, что оно исчезало, когда что-либо под ним обновлялось, и по-прежнему пропускались сообщения мыши, поэтому, если бы я, например, удерживал кнопку на рабочем столе, это повлияло бы на прямоугольники с изменяющимися размерами.

Сегодня, после того, как у меня наконец-то появилось свободное время, прошедшее после последней крупной работы над этим большую часть того, что было 6 месяцев назад, я решил переделать его и посмотреть, смогу ли я достичь того, чего хотел.Я сделал прозрачное, самое верхнее, многоуровневое, многоуровневое окно WS_CHILD (в основном экран не меняется, но есть окно поверх всего, что пропускает сообщения).Затем я сделал так, чтобы в режиме рисования значение альфа-канала было установлено равным 1, и пользователь мог рисовать.Пока я этого не осознал, я понял, что, поскольку альфа-значение окна равно 1, рисование не будет видно.

Затем я попытался использовать GetDC (NULL), но вспомнил, чтостирается, когда что-то обновляется.

Теперь я просто подумал об использовании растровых изображений и dcs для многократного сохранения экрана в dc, рисования на другом dc, а затем копирования его обратно на тот, на котором сохранен экран с прозрачностью длячасти, которые не нарисованы, и скопируйте их обратно на экран, но я отчаиваюсь.Вот мой исходный код для этого (функция маски взята из этого урока ).Пожалуйста, скажите мне, если что-то из этого не нужно.Я использовал точечные рисунки для двойной буферизации, но я не совсем уверен, где они мне нужны.

//Global mask since it takes longer to make
HBITMAP mask;

//Window Procedure Start
HDC screenDC; //hdc for entire screen
screenDC = GetDC (NULL); //get DC for screen

HDC memDC = CreateCompatibleDC (screenDC); //create DC for holding the screen+paint
HBITMAP bm = CreateCompatibleBitmap (screenDC, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN)); //create bitmap for memDC

HDC paintDC = CreateCompatibleDC (screenDC); //create DC to paint on
HBITMAP paintBM = CreateCompatibleBitmap (screenDC, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN)); //create bitmap for paintDC

SelectObject (memDC, bm); //select bitmap into memDC
SelectObject (paintDC, paintBM); //select painting bitmap into paintDC
BitBlt (memDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), screenDC, 0, 0, SRCCOPY); //copy screen to memDC
SetBkColor (paintDC, RGB(0,0,0)); //set background of paintDC to black so it's all transparent to start

//WM_CREATE
mask = CreateBitmapMask (bm, RGB(0,0,0)); //create black mask (paint colours are limited 1-255 now)

//painting is done into paintDC

//at end of Window Procedure
SelectObject (paintDC, mask); //select mask into paintDC
BitBlt (memDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), paintDC, 0, 0, SRCAND); //this in combination with the next should make it bitblt with all of the black taken out I thought
SelectObject (paintDC, paintBM); //select bitmaps into DCs
SelectObject (memDC, bm);
BitBlt (memDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), paintDC, 0, 0, SRCPAINT); //second part of transparent bitblt
BitBlt (screenDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), paintDC, 0, 0, SRCCOPY); //copy memDC back to screen

DeleteObject (paintBM); //delete stuff
DeleteObject (mask);
DeleteDC (memDC);
DeleteDC (paintDC);
ReleaseDC (hwnd, screenDC);

//CreateBitmapMask() (taken directly from http://www.winprog.org/tutorial/transparency.html
HBITMAP CreateBitmapMask(HBITMAP hbmColour, COLORREF crTransparent)
{
HDC hdcMem, hdcMem2;
HBITMAP hbmMask;
BITMAP bm;

// Create monochrome (1 bit) mask bitmap.

GetObject(hbmColour, sizeof(BITMAP), &bm);
hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);

// Get some HDCs that are compatible with the display driver

hdcMem = CreateCompatibleDC(0);
hdcMem2 = CreateCompatibleDC(0);

SelectObject(hdcMem, hbmColour);
SelectObject(hdcMem2, hbmMask);

// Set the background colour of the colour image to the colour
// you want to be transparent.
SetBkColor(hdcMem, crTransparent);

// Copy the bits from the colour image to the B+W mask... everything
// with the background colour ends up white while everythig else ends up
// black...Just what we wanted.

BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);

// Take our new mask and use it to turn the transparent colour in our
// original colour image to black so the transparency effect will
// work right.
BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem2, 0, 0, SRCINVERT);

// Clean up.

DeleteDC(hdcMem);
DeleteDC(hdcMem2);

return hbmMask;
}

Я знаю, что код вполне может быть ужасным.Я принимаю во внимание все предложения, просто я не слишком разбираюсь в этом вопросе и не понимаю всего, что происходит, что затрудняет исправление.Этот код запускается для меня тем, что я очень часто ставлю полноэкранный черный прямоугольник.

Мой главный вопрос: есть ли способ рисовать на экране, не стирая его при обновлении окон?Единственная реальная вещь, о которой я могу думать сейчас, - это хранить все местоположений крошечных отрезков, которые рисует пользователь, и продолжать перерисовывать их в верхней части экрана.На первый взгляд это кажется очень неэффективным и расточительным в памяти.

Кроме того, я был совершенно уверен, когда писал это, что мне не нужны были примеры кода для теоретических вещей до поставляемых фрагментов кода.Большая часть этого уже исчезла, но на самом деле это больше теоретический вопрос.

РЕДАКТИРОВАТЬ: я только что узнал о функции TransparentBlt, которая казалась идеальной для ситуации, поэтому я попытался использовать ее вместо SRCPAINT иSRCAND BitBlts, и он дал тот же результат: черный прямоугольник, закрывающий экран, иногда исчезают части, когда моя мышь перемещается по вещам.

Ответы [ 2 ]

3 голосов
/ 01 октября 2011

Самый простой способ, возможно:

В режиме без рисования используйте SetLayeredWindowAttributes , чтобы установить цвет «ключа прозрачности» для прозрачного окна. Сделайте альфа-окно полностью непрозрачным, но залейте окно (FillRect или подобное) этим ключевым цветом, и оно будет выглядеть прозрачным. Тогда все, что вы рисуете в неключевом цвете, будет выглядеть сплошным поверх всех окон под прозрачным слоистым окном.

Чтобы перейти в режим рисования, одним из подходов является создание нового окна с захваченным растровым изображением рабочего стола непосредственно под прозрачным слоем. Или избегайте растрового изображения и сделайте его немного непрозрачным и сделайте его сплошным цветом - например, чтобы рабочий стол выглядел «серым». Ключевым моментом является то, что это окно не является полностью прозрачным, поэтому оно сможет получать данные мыши, которые затем можно использовать для рисования на реальном прозрачном слое.

0 голосов
/ 30 сентября 2011

Я думаю, что вам лучше всего создать снимок экрана и сохранить его в растровом изображении (в виде DC памяти), ДО того, как вы покажете окно, которое отображает содержимое DC памяти в полноэкранном режиме.Таким образом, вы на самом деле извлекаете сообщения, вызванные щелчками и т. Д., В собственном окне и обрабатываете их как обычно.

  1. Захват содержимого экрана
  2. Создание окна (полный экран) и использование захваченного содержимого
  3. Сделать рисунок
  4. Сохранить содержимое (как bmp или что-нибудь необычное)
  5. Закрыть окно и вернуться на обычный рабочий стол

Хорошая идея?

...