Board index » delphi » Win32 API Pen Creation.. Help Please

Win32 API Pen Creation.. Help Please

Hi - I am having a bit of trouble creating a nice looking pen style in win32
API. I wonder of anyone can help.

This is what I am using to create the pens:

Pen := Windows.CreatePen(PS_DOT, 1, ClBlack);

and then selecting it into a window's device context, and drawing with it.
However, the PS_DOT style looks to be about 4 pixels black, four white, and
so on. What I would like to do is draw 1 black, 1 white, 1 black, 1 white
... etc. Anybody know how this is achieved?

 

Re:Win32 API Pen Creation.. Help Please


"paul.dunn4" <paul.du...@ntlworld.com> skrev i melding
news:n5CF5.517$NQ4.7713@news2-win.server.ntlworld.com...

Quote
> Hi - I am having a bit of trouble creating a nice looking pen style in
win32
> API. I wonder of anyone can help.

> This is what I am using to create the pens:

> Pen := Windows.CreatePen(PS_DOT, 1, ClBlack);

> and then selecting it into a window's device context, and drawing with
it.
> However, the PS_DOT style looks to be about 4 pixels black, four
white, and
> so on. What I would like to do is draw 1 black, 1 white, 1 black, 1
white
> ... etc. Anybody know how this is achieved?

Can't be done. When you see this dotted line, it's actually done by
creating a brush from a bmp pattern (e.g. a 2x2 pix. bitmap with
white/black pixels), and drawing tiny rectangles.

--
Bjoerge Saether
Consultant / Developer
Asker, Norway
bsaether.removet...@online.no (remove the obvious)

Re:Win32 API Pen Creation.. Help Please


In article <n5CF5.517$NQ4.7...@news2-win.server.ntlworld.com>, "paul.dunn4"

Quote
<paul.du...@ntlworld.com> writes:
>Hi - I am having a bit of trouble creating a nice looking pen style in win32
>API. I wonder of anyone can help.

>This is what I am using to create the pens:

>Pen := Windows.CreatePen(PS_DOT, 1, ClBlack);

>and then selecting it into a window's device context, and drawing with it.
>However, the PS_DOT style looks to be about 4 pixels black, four white, and
>so on. What I would like to do is draw 1 black, 1 white, 1 black, 1 white
>... etc. Anybody know how this is achieved?

In article <HdDF5.5114$W31.77...@news1.online.no>, "Bj?rge S?ther"

Quote
<REMOVE_bsaether@THIS_online.no> writes:
>Can't be done.

The difficult we do at once, the impossible takes a little longer <gg>

Use LineDDA. You write a general procedure which is a callback. The call
triggers the callback for every pixel and you then can draw for the pixel
position passed in the callback.

In order to track the pixel "index" I use a typed constant in which I shift a
bit. I also use a mask against this typed constant to check whether the pixel
should be black or a colour. Obviously the mask defines the dot pattern, and
the size of the typed constant limits the size of the pattern. You could do any
other algorithm to control the line pattern, and (for example) draw small
circles.

procedure DottedLine(X,Y: Integer; ACanvas: TCanvas); stdcall;
const
  Mask = $AAAA;  // pattern is |@ @ @ @ @ @ @ @ | - alternate black &
background colour
  Counter : Word = $8000;
begin
  Counter := Counter shr 1;            // shift the bit right one
  if Counter = 0 then
    Counter := $8000;    // if it shifts off right, reset it
  if (Counter and Mask) > 0 then
    ACanvas.Pixels[X,Y] := clBlack    // black pixel
  else
    ACanvas.Pixels[X,Y] := Form1.Color; // background colour pixel
end;

You then draw the line by calling

  LineDDA(StartX, StartY, EndX, EndY, @DottedLine, LongInt(Canvas));

The last parameter of the LineDDA call is an application dependant value which
is passed unchanged to the callback (in the normal manner), and which I have
used as a reference to the canvas I am drawing on.

"the impossible takes a little longer" and so does this technique - so don't
use it very often.

Alan Lloyd
alangll...@aol.com

Re:Win32 API Pen Creation.. Help Please


Thanks... So if it does indeed take a little longer, I shan't use it :) It
was for drawing full screen crosshairs on the desktop that follow the mouse
every time the pointer moves. I don't want to slow it down at all if I can
help it.

However, as you seem to be knowledgable in this respect, maybe you can help
me out (or suggest I do it another way) - It's to do with drawing those damn
crosshairs. What I have done is this:

Call a procedure to create windows (one for each arm of the crosshair)

Procedure TForm1.CreateBigXHairs(X, Y: Integer);
Begin
  PenU := Windows.CreatePen(PS_DOT, 1, ClBlack);
  PenD := Windows.CreatePen(PS_DOT, 1, ClBlack);
  PenL := Windows.CreatePen(PS_DOT, 1, ClBlack);
  PenR := Windows.CreatePen(PS_DOT, 1, ClBlack);

  LeftHandle := CreateWindowEx(WS_EX_TOOLWINDOW,
'#32770','LeftXHair',(WS_VISIBLE or WS_POPUP) and not WS_DLGFRAME, 0, 0, 1,
1, 0, 0, hInstance, nil);
  SetWindowLong(LeftHandle, GWL_WNDPROC,Longint(@XhairsMainLeft));
  LeftDC := GetDC(LeftHandle);
  SelectObject(LeftDC, PenL);

  UpperHandle := CreateWindowEx(WS_EX_TOOLWINDOW,
'#32770','UpperXHair',(WS_VISIBLE or WS_POPUP) and not WS_DLGFRAME, 0, 0, 1,
1, 0, 0, hInstance, nil);
  SetWindowLong(UpperHandle, GWL_WNDPROC,Longint(@XhairsMainUpper));
  UpperDC := GetDC(UpperHandle);
  SelectObject(UpperDC, PenU);

  LowerHandle := CreateWindowEx(WS_EX_TOOLWINDOW,
'#32770','LowerXHair',(WS_VISIBLE or WS_POPUP) and not WS_DLGFRAME, 0, 0, 1,
1, 0, 0, hInstance, nil);
  SetWindowLong(LowerHandle, GWL_WNDPROC,Longint(@XhairsMainLower));
  LowerDC := GetDC(LowerHandle);
  SelectObject(LowerDC, PenD);

  RightHandle := CreateWindowEx(WS_EX_TOOLWINDOW,
'#32770','RightXHair',(WS_VISIBLE or WS_POPUP) and not WS_DLGFRAME, 0, 0, 1,
1, 0, 0, hInstance, nil);
  SetWindowLong(RightHandle, GWL_WNDPROC,Longint(@XhairsMainRight));
  RightDC := GetDC(RightHandle);
  SelectObject(RightDC, PenR);

  XHairDiff := 8; // the distance of the crosshair arms from the mouse
pointer position
  SetBigXHairs; // move the windows to the correct on screen coordinates
End;

{This one actually moves them}

Procedure TForm1.SetBigXHairs;
Begin
  GetCursorPos(Form1.XHairPos);
  UpHeight := XHairPos.Y - XHairDiff;
  LowHeight := Screen.Height - (XHairPos.Y + XHairDiff);
  LeftWidth := XHairPos.X - XHairDiff;
  RightWidth := Screen.Width - (XHairPos.X + XHairDiff);
  SetWindowPos(UpperHandle, HWND_Topmost, XHairPos.X, 0, 1, UpHeight,
SWP_NOACTIVATE);
  SetWindowPos(LowerHandle, HWND_Topmost, XHairPos.X, XHairPos.Y +
XHairDiff, 1, LowHeight, SWP_NOACTIVATE);
  SetWindowPos(LeftHandle, HWND_Topmost, 0, XHairPos.Y, LeftWidth, 1,
SWP_NOACTIVATE);
  SetWindowPos(RightHandle, HWND_Topmost, XHairPos.X + XHairDiff,
XhairPos.Y, RightWidth, 1, SWP_NOACTIVATE);
End;

{and these draw on them}

function XHairsMainUpper(hWnd,uMsg,wParam,lParam:Longint):Longint; stdcall;
var ps: TPaintStruct;
begin
  case uMsg of
     WM_DESTROY: Begin ReleaseDC(Form1.UpperHandle,Form1.UpperDC);
DeleteObject(Form1.PenU); End;
     WM_ERASEBKGND:;
     WM_PAINT: begin BeginPaint(hWnd,ps); Windows.MoveToEx(Form1.UpperDC, 0,
0, nil); Windows.LineTo(Form1.UpperDC, 0, Form1.UpHeight);
EndPaint(hWnd,ps); end;
  end;
  Result:=DefWindowProc(hWnd,uMsg,wParam,lParam);
end;

Whenever the mouse moves, the setBigXHairs routine is called.

There is four of the above paint routines, and they all do the same thing,
more or less.
Only they don't always work quite right. The crosshairs sometimes display
very well and smoothly follow the mouse around the screen. Other times,
although they follow the mouse around, they don't paint very well at all,
and display all sorts of garbage. I did try drawing directly to the desktop
using XOR lines, but that worked only until the display repainted a portion,
which wold leave XOR lines all over the place. I can only think of using
four windows to represent them.

Do you have ANY idea of why this corruption occurs? or any ideas on how I
can trap desktop painting messages, in order to remove my XOR crosshairs
(which I really like) so they don't corrupt the desktop display? Any help,
pointers to correct my god-awful code (I know it's bad) would be gratefully
received.

Sorry for the long post, but I'm at my wit's end. Bugs that are reproducable
are easy to fix :)

Paul.

Re:Win32 API Pen Creation.. Help Please


In article <VTEF5.771$NQ4.12...@news2-win.server.ntlworld.com>, "paul.dunn4"

Quote
<paul.du...@ntlworld.com> writes:
>Thanks... So if it does indeed take a little longer, I shan't use it :) It
>was for drawing full screen crosshairs on the desktop that follow the mouse
>every time the pointer moves. I don't want to slow it down at all if I can
>help it.

>However, as you seem to be knowledgable in this respect, maybe you can help
>me out (or suggest I do it another way) - It's to do with drawing those damn
>crosshairs. What I have done is this:

>Call a procedure to create windows (one for each arm of the crosshair)

I'm not sure that I really understand all that you are doing, but my
engineering soul cringes at the complexity of the program (do you get this is
or is it only aged engineers that get this sixth sense <gg>). _Four_ windows -
think of all those resources running away <gg>.

Anyway without knowing how to catch the WM_MouseMove messages, here are two
ideas for "drawing" the cross-hairs.

1 Get the Desktop Device Context, allocate it it to the handle of a TCanvas and
draw on that.

2 Make a form in the shape of a cross-hair (by using regions) and move that
about.

I have e-mailed Paul an example of using these techniques to draw on the
desktop.

BTW the LineDDA is useable, its just somewhat slower than normal line drawing,
you have to try it out to see if it is _too_ slow.

Alan Lloyd
alangll...@aol.com

Other Threads