Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > Рисование поверх других окон


Автор: murod 14.7.2007, 13:37
Всем Привет! 
Такая вот задача:
Надо сделать програмку типа Paint. Но он будет рисовать на рабочем столе или поверх других окон. 
Сама Программа занимает верхную область рабочего стола. Там будет только панель инструментов(тип линии, цвет заливки, Ластик, квадрат...).
Рисовать получается. Но вот, как очистить определенную область, например маленкий квадрат? Как сделать Ластик как на Paint. Ясно что на Paint нету заднего фона там можно просто очишать белым или рисовать белый квадрат. А как поступить в моем случаи? Ведь у меня задний фон не белый а там стоит рабочий стол. Первое в голову приходит как то обновить маленький регион рабочего стола. Но не получается. Когда обнавляю регион вместо него рисуется белый квадрат. 
Здесь запутался, дальше не идет. Посоветуйте хоть что.

рисую примерно так:
Код

dc:=GetDC(0);
canv:=TCanvas.Create; 
canv.Handle:=dc;
canv.Ellipse(Mouse.CursorPos.X,Mouse.CursorPos.Y,Mouse.CursorPos.X+20,Mouse.CursorPos.Y+20);

стираю так:
Код

var r:Prect;
-------------------------------------------
r.Left:=Mouse.CursorPos.X;
r.Top:=Mouse.CursorPos.Y;
r.Right:=Mouse.CursorPos.X+10;
r.Bottom:=Mouse.CursorPos.Y+10;
  InvalidateRect(dc,r,true);


Заранее всем спасибо.

Автор: Alexeis 14.7.2007, 23:54
  А почему бы не стирать просто рисуя белый квадратик?

Автор: nmn 15.7.2007, 00:22
а как ты собираешься стирать? восстанавливать то что было раньше? тогда можешь сделать себе фотографию экрана и потом из нее восстанавливать "испорченный" участок

Добавлено через 1 минуту и 49 секунд
и еще IvalidateRect необходимо передавать не дескриптор контекста а дескриптор окна

Автор: murod 15.7.2007, 19:51
Alexeis, если буду стирать белым квадратиком то у меня задний фоном является рабочий стол, мне надо очистить только то что нарисовал. И при этом задним фоном должно быть рабочий стол. По проше у меня как бы два слоя. 1-слой это рабочий стол. 2-слой это то что я рисую. Если смогу обновить прямоугольную область экрана то у меня 2-слой отстирается а 1-слой обновится(windows автоматически перерисует прямоугольную область экрана) вот тогда бы получился ластик.


nmn, 
Цитата

а как ты собираешься стирать? восстанавливать то что было раньше? тогда можешь сделать себе фотографию экрана и потом из нее восстанавливать "испорченный" участок

Это для частных случаев может подойдет, когда у меня статический обычны рабочий стол. Если на рабочем столе будет проигрыватся видео файл(Media player) то тогда я не смогу правильно обновить экран.  

Мне просто нужна функция обновления указанной области экрана, типа IvalidateRect().

Цитата

и еще IvalidateRect необходимо передавать не дескриптор контекста а дескриптор окна

это действительно может помочь. я не правильно обновлял. Попробую IvalidateRect() передать  хендл окна под указателем мышки а не контекст устройства.  

Автор: murod 15.7.2007, 20:14
нет неработает, не обновляется.
Я поставил ловушку на мыш. обрабатываю события мыши и поним рисую, стираю.
вот код ловушки и как стираю. 
Код

function MouseProc(nCode: Integer; wParam, lParam: Longint): Longint; stdcall;
var dc:THandle;r:Prect;
begin
 dc:=GetDC(0);
r.Left:=Mouse.CursorPos.X;
r.Top:=Mouse.CursorPos.Y;
r.Right:=Mouse.CursorPos.X+10;
r.Bottom:=Mouse.CursorPos.Y+10;
 InvalidateRect(WindowFromPoint(Mouse.CursorPos),r,true);
 result := CallNextHookEx(ourHook, nCode, wParam, lParam);
end;

Посмотрите может еще где делаю не правильно,

Автор: nmn 17.7.2007, 03:17
вроде InvalidateRect не вызывает перерисовки, а только при добавляет  к перерисовываемой области прямоугольник

Добавлено через 5 минут и 14 секунд
а если окно не перекрывается другими окнами и не выходит за пределы экрана то и сообщение WM_PAINT не присылается, отсюда вывод - шли сам или вызывай UpdateWindow. Может проще сделать фотографию и рисовать на ней?

Автор: bems 17.7.2007, 17:46
попробуй рисовать на прозрачном слоистом окне во весь экран

Автор: murod 17.7.2007, 20:43
bems, можно подробней ? если не трудно, приведи маленький пример.

Автор: bems 18.7.2007, 11:43
вот примерчик
Код

program DesktopPaint;

uses
  windows,messages;

const sWndClassName='TransparentDrawingSurface';
      sWndName='DesktopPaint';
      TransparentColor=$00010101;
      PictureColor=$0000FF00;
      WH_MOUSE_LL=14;

type MSLLHOOKSTRUCT=record
                    pt:TPoint;
                    mouseData,
                    flags,
                    time:DWORD;
                    dwExtraInfo:pointer;
                    end;

var hHook:THANDLE;SurfaseWnd:HWND;

procedure Paint(wnd:HWND;color:COLORREF;pt:TSmallPoint);
var dc:HDC;OriginalPen:HPEN;OriginalBrush:HBRUSH;
begin
dc:=GetDC(wnd);
OriginalPen:=SelectObject(dc,GetStockObject(NULL_PEN));
OriginalBrush:=SelectObject(dc,CreateSolidBrush(color));
ellipse(dc,pt.x-10,pt.y-10,pt.x+10,pt.y+10);
SelectObject(dc,OriginalPen);
DeleteObject(SelectObject(dc,OriginalBrush));
ReleaseDC(wnd,dc);
end;

function MouseHook(nCode:integer;msg:cardinal;var info:MSLLHOOKSTRUCT):integer;stdcall;
var buttons:integer;pt:TSmallPoint;
begin
result:=CallNextHookEx(0,nCode,integer(msg),integer(@info));
if nCode=HC_ACTION
   then begin
        buttons:=0;
        if Hi(GetAsyncKeyState(VK_LBUTTON))<>0
           then buttons:=MK_LBUTTON;
        if Hi(GetAsyncKeyState(VK_RBUTTON))<>0
           then buttons:=buttons or MK_RBUTTON;
        pt.x:=info.pt.X;
        pt.y:=info.pt.Y;
        SendMessage(SurfaseWnd,WM_MOUSEMOVE,buttons,integer(pt));
        end;
end;

procedure Hook;
begin
hHook:=SetWindowsHookEx(WH_MOUSE_LL,@MouseHook,hInstance,0);
end;

procedure Unhook;
begin
UnhookWindowsHookEx(hHook);
end;

function WndProc(wnd:HWND;msg:cardinal;wParam,lParam:integer):integer;stdcall;
begin
result:=DefWindowProc(wnd,msg,wParam,lParam);
case msg of
  WM_NCCREATE:begin
              SurfaseWnd:=wnd;
              SetLayeredWindowAttributes(wnd,TransparentColor,0,LWA_COLORKEY);
              Hook;
              end;
 WM_NCDESTROY:begin
              Unhook;
              PostQuitMessage(0);
              end;
 WM_MOUSEMOVE:if (wParam and MK_LBUTTON)=0
                 then if (wParam and MK_RBUTTON)<>0
                         then Paint(wnd,TransparentColor,TSmallPoint(lParam))
                         else 
                 else Paint(wnd,PictureColor,TSmallPoint(lParam));
end;
end;

function CreateSurfaceWnd:boolean;
var cls:WNDCLASS;
begin
ZeroMemory(@cls,SizeOf(cls));
with cls do begin
            lpfnWndProc:=@WndProc;
            lpszClassName:=sWndClassName;
            hbrBackground:=CreateSolidBrush(TransparentColor);
            hCursor:=LoadCursor(0,IDC_ARROW);
            end;
result:=(RegisterClass(cls)<>0) and
        (CreateWindowEx(WS_EX_LAYERED or WS_EX_TOPMOST,
                        sWndClassName,sWndName,
                        WS_POPUP or WS_MAXIMIZE or WS_VISIBLE,
                        0,0,0,0,0,0,0,nil)<>0)
end;

var msg:TMSG;
begin
if CreateSurfaceWnd
  then while GetMessage(msg,0,0,0) do
        DispatchMessage(msg);
end.
Левая кнопка мышки рисует, правая стирает

Добавлено через 4 минуты и 2 секунды
недостатки:
- окно иногда "проваливается" под панель задач (но в большей части экрана все в порядке)
- рисовать можно не всеми цветами (т. к. один зарезервирован под прозрачность)

Автор: murod 19.7.2007, 06:39
bems, Спасибо большое. Так и буду делать. Только как то мне надо будет чтобы этот окно стояла поверх Панели задач, что бы не проваливался. Этим думаю можно разобратся.

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