Jump to content

Dashed/Dotted line with width>1


Zedna
 Share

Recommended Posts

I need to draw dashed/dotted line with width=2 pixels

MSDN: LineTo/CreatePen

http://msdn.microsoft.com/en-us/library/dd145029%28v=vs.85%29.aspx

http://msdn.microsoft.com/en-us/library/dd183509%28v=vs.85%29.aspx

According to MSDN LineTo uses current pen

and at CreatePen there is mentioned when style is PS_DASH or PS_DOT:

This style is valid only when the pen width is one or less in device units.

So how can I achieve dashed/dotted line with width=2 using Windows API/GDI?

Note: I would like to use GDI (not GDI+) but I will be glad for any help.

Here is simple testing script:

#include <WindowsConstants.au3>
#include <WinAPI.au3>

ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, 200, 1, 0xFF, 3000) ; width 1
Sleep(100)
ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, 200, 2, 0xFF, 3000) ; width 2

Func ShowCross($start_x, $start_y, $length, $width, $color, $time)
    Local $hDC, $hPen, $obj_orig

    $hDC = _WinAPI_GetWindowDC(0) ; DC of entire screen (desktop)
;~  $hPen = _WinAPI_CreatePen($PS_SOLID, $width, $color) ; OK
    $hPen = _WinAPI_CreatePen($PS_DOT, $width, $color) ; not OK
    $obj_orig = _WinAPI_SelectObject($hDC, $hPen)
    
    _WinAPI_MoveTo($hDC, $start_x, $start_y + $length)
    _WinAPI_LineTo($hDC, $start_x, $start_y + 5)
    
; test: draw two 1 pixel lines next to them
;~  _WinAPI_MoveTo($hDC, $start_x + 1, $start_y + $length)
;~  _WinAPI_LineTo($hDC, $start_x + 1, $start_y + 5)

    Sleep($time) ; show cross over screen for defined seconds

    ; refresh desktop (clear cross)
    _WinAPI_RedrawWindow(_WinAPI_GetDesktopWindow(), 0, 0, $RDW_INVALIDATE + $RDW_ALLCHILDREN)

    ; clear resources
    _WinAPI_SelectObject($hDC, $obj_orig)
    _WinAPI_DeleteObject($hPen)
    _WinAPI_ReleaseDC(0, $hDC)
EndFunc   ;==>ShowCross
Link to comment
Share on other sites

This mod worked to draw two one-pixel dashed lines next to each other:

#include <WindowsConstants.au3>
#include <WinAPI.au3>

For $w = 1 To 5
    ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, 100, $w, 0xFF, 3000) ; width 1
Next

Func ShowCross($start_x, $start_y, $length, $width, $color, $time)
    Local $hDC, $hPen, $obj_orig

    $hDC = _WinAPI_GetWindowDC(0) ; DC of entire screen (desktop)
    $hPen = _WinAPI_CreatePen($PS_DOT, 1, $color) ; not OK
    $obj_orig = _WinAPI_SelectObject($hDC, $hPen)

    For $n = 0 To $width - 1
        _WinAPI_MoveTo($hDC, $start_x + $n, $start_y + $length)
        _WinAPI_LineTo($hDC, $start_x + $n, $start_y + 5)
    Next

    Sleep($time) ; show cross over screen for defined seconds

    _WinAPI_RedrawWindow(_WinAPI_GetDesktopWindow(), 0, 0, $RDW_INVALIDATE + $RDW_ALLCHILDREN)

    _WinAPI_SelectObject($hDC, $obj_orig)
    _WinAPI_DeleteObject($hPen)
    _WinAPI_ReleaseDC(0, $hDC)
EndFunc   ;==>ShowCross

Didn't attempt the logic to handle horizontal as well as a vertical line, but that should be simple.

:unsure:

Edited by PsaltyDS
Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

I've been playing with it for a few minutes. This isn't working perfectly, but maybe it will get you moving in the right direction:

#include <WindowsConstants.au3>
#include <WinAPI.au3>

ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, 200, 1, 0xFF, 3000) ; width 1
Sleep(100)
ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, 200, 2, 0xFF, 3000) ; width 2

Func ShowCross($start_x, $start_y, $length, $width, $color, $time)
    Local $hDC, $hPen, $obj_orig

    $hDC = _WinAPI_GetWindowDC(0) ; DC of entire screen (desktop)
;~  $hPen = _WinAPI_CreatePen($PS_SOLID, $width, $color) ; OK
    $hPen = _WinAPI_CreatePen($PS_DOT, $width, $color) ; not OK

    $x_coord = $start_x          ;Added this to go back to the original value. Apparently, the $start_x gets modified somewhere. 

    $obj_orig = _WinAPI_SelectObject($hDC, $hPen)

    _WinAPI_MoveTo($hDC, $start_x, $start_y + $length)
    _WinAPI_LineTo($hDC, $start_x, $start_y + 5)
    _WinAPI_MoveTo($hDC, $x_coord +1, $start_y + $length)
    _WinAPI_LineTo($hDC, $x_coord +1, $start_y + 5)

; test: draw two 1 pixel lines next to them
;~  _WinAPI_MoveTo($hDC, $start_x + 1, $start_y + $length)
;~  _WinAPI_LineTo($hDC, $start_x + 1, $start_y + 5)

    Sleep($time) ; show cross over screen for defined seconds

    ; refresh desktop (clear cross)
    _WinAPI_RedrawWindow(_WinAPI_GetDesktopWindow(), 0, 0, $RDW_INVALIDATE + $RDW_ALLCHILDREN)

    ; clear resources
    _WinAPI_SelectObject($hDC, $obj_orig)
    _WinAPI_DeleteObject($hPen)
    _WinAPI_ReleaseDC(0, $hDC)
EndFunc   ;==>ShowCross

#include <ByteMe.au3>

Link to comment
Share on other sites

entering 'Draw dotted line win32' on MSDN search, turned this up:

http://stackoverflow.com/questions/541166/winapi-how-to-draw-dotted-line

Creating a true dotted pen

http://www.codeproject.com/KB/GDI/DOTTED_PEN.aspx

problem is, it's also limited to one pixel

but $PS_GEOMETRIC, $PS_DASH allow a sizeable dashed line, but...

Problem using ExtCreatePen

http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/7e1f58be-d534-48e2-83e5-2d2300077a8a

possibly LineDDA() ?

http://msdn.microsoft.com/en-us/library/dd145025(VS.85).aspx

2 pixel wide dashed line

#include <WindowsConstants.au3>
#include <WinAPI.au3>
Global Const $PS_COSMETIC = 0x0
Global Const $PS_ALTERNATE = 8
Global Const $PS_GEOMETRIC = 0x10000

ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, 400, 2, 0xFF0000, 8000)

Func ShowCross($start_x, $start_y, $length, $width, $color, $time)
    Local $hDC, $hPen, $obj_orig

    $hDC = _WinAPI_GetWindowDC(0) ; DC of entire screen (desktop)

    ;$hPen = _WinAPI_CreatePen($PS_DOT, 1, $color);actually a dashed line, not a dotted line
    ;$hPen = _WinAPI_ExtCreatePen(BitOR($PS_COSMETIC, $PS_ALTERNATE), 1, 0xFF0000);true dotted line, but single pixel...
    $hPen = _WinAPI_ExtCreatePen(BitOR($PS_GEOMETRIC, $PS_DASH), $width, $Color);allows large dashed line

    $obj_orig = _WinAPI_SelectObject($hDC, $hPen)

    _WinAPI_DrawLine($hDC, $start_x - $length, $start_y, $start_x - 5, $start_y) ; horizontal left
    _WinAPI_DrawLine($hDC, $start_x + $length, $start_y, $start_x + 5, $start_y) ; horizontal right
    _WinAPI_DrawLine($hDC, $start_x, $start_y - $length, $start_x, $start_y - 5) ; vertical up
    ;   _WinAPI_DrawLine($hDC, $start_x, $start_y + $length, $start_x, $start_y + 5) ; vertical down
    _WinAPI_MoveTo($hDC, $start_x, $start_y + $length)
    _WinAPI_LineTo($hDC, $start_x, $start_y + 5)

    Sleep($time) ; show cross over screen for defined seconds

    ; refresh desktop (clear cross)
    _WinAPI_RedrawWindow(_WinAPI_GetDesktopWindow(), 0, 0, $RDW_INVALIDATE + $RDW_ALLCHILDREN)

    ; clear resources
    _WinAPI_SelectObject($hDC, $obj_orig)
    _WinAPI_DeleteObject($hPen)
    _WinAPI_ReleaseDC(0, $hDC)
EndFunc   ;==>ShowCross




Func _WinAPI_ExtCreatePen($iPenStyle, $iWidth, $nColor, $dwStyleCount = 0, $pStyle = 0)
    ;coded by rover 2k11: tagLOGBRUSH and _WinAPI_SwitchColor() from Yashied's WinAPIEx
    Local Const $tagLOGBRUSH = 'uint Style;dword Color;ulong_ptr Hatch;' ;from WinAPIEx
    Local Const $BS_SOLID = 0
    Local $tLOGBRUSH = DllStructCreate($tagLOGBRUSH)
    DllStructSetData($tLOGBRUSH, 1, $BS_SOLID)
    DllStructSetData($tLOGBRUSH, 2, _WinAPI_SwitchColor($nColor))
    DllStructSetData($tLOGBRUSH, 3, 0)
    Local $pLOGBRUSH = DllStructGetPtr($tLOGBRUSH)
    Local $aResult = DllCall("gdi32.dll", "handle", "ExtCreatePen", "dword", $iPenStyle, _
    "dword", $iWidth, "ptr", $pLOGBRUSH, "dword", $dwStyleCount, "ptr", $pStyle)
    If @error Then Return SetError(@error, @extended, 0)

    Return $aResult[0]
EndFunc   ;==>_WinAPI_ExtCreatePen

;from WinAPIEx
Func _WinAPI_SwitchColor($iColor)
    Return BitOR(BitAND($iColor, 0x00FF00), BitShift(BitAND($iColor, 0x0000FF), -16), BitShift(BitAND($iColor, 0xFF0000), 16))
EndFunc   ;==>_WinAPI_SwitchColor

I see fascists...

Link to comment
Share on other sites

even better: user style pens

;even better: user style pens

#include <WindowsConstants.au3>
#include <WinAPI.au3>
Global Const $PS_COSMETIC = 0x0
Global Const $PS_ALTERNATE = 8
Global Const $PS_GEOMETRIC = 0x10000
Global Const $PS_USERSTYLE = 7
Global Const $PS_ENDCAP_ROUND = 0x0

ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, 400, 2, 0xFF0000, 2000);dashed
ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, 400, 2, 0xFF0000, 3000, 2, 4);dotted
ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, 400, 8, 0xFF0000, 2000, 2, 15);dotted
ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, 400, 12, 0xFF0000, 2000, 2, 30);dotted

Func ShowCross($start_x, $start_y, $length, $width, $color, $time, $iElement1 = 0, $iElement2 = 0)
    Local $hDC, $hPen, $obj_orig

    $hDC = _WinAPI_GetWindowDC(0) ; DC of entire screen (desktop)

    ;$hPen = _WinAPI_CreatePen($PS_DOT, 1, $color);actually a dashed line, not a dotted line
    ;$hPen = _WinAPI_ExtCreatePen(BitOR($PS_COSMETIC, $PS_ALTERNATE), 1, 0xFF0000);true dotted line, but single pixel...
    If $iElement1 > 0 And $iElement1 > 0 Then
        $hPen = _WinAPI_ExtCreatePen(BitOR($PS_GEOMETRIC, $PS_USERSTYLE), $width, $Color, $iElement1, $iElement2);allows large dotted line
    Else
        $hPen = _WinAPI_ExtCreatePen(BitOR($PS_GEOMETRIC, $PS_DASH), $width, $Color);allows large dashed line
    EndIf
    $obj_orig = _WinAPI_SelectObject($hDC, $hPen)

    _WinAPI_DrawLine($hDC, $start_x - $length, $start_y, $start_x - 5, $start_y) ; horizontal left
    _WinAPI_DrawLine($hDC, $start_x + $length, $start_y, $start_x + 5, $start_y) ; horizontal right
    _WinAPI_DrawLine($hDC, $start_x, $start_y - $length, $start_x, $start_y - 5) ; vertical up
    ;   _WinAPI_DrawLine($hDC, $start_x, $start_y + $length, $start_x, $start_y + 5) ; vertical down
    _WinAPI_MoveTo($hDC, $start_x, $start_y + $length)
    _WinAPI_LineTo($hDC, $start_x, $start_y + 5)

    Sleep($time) ; show cross over screen for defined seconds

    ; refresh desktop (clear cross)
    _WinAPI_RedrawWindow(_WinAPI_GetDesktopWindow(), 0, 0, $RDW_INVALIDATE + $RDW_ALLCHILDREN)

    ; clear resources
    _WinAPI_SelectObject($hDC, $obj_orig)
    _WinAPI_DeleteObject($hPen)
    _WinAPI_ReleaseDC(0, $hDC)
EndFunc   ;==>ShowCross




Func _WinAPI_ExtCreatePen($iPenStyle, $iWidth, $nColor, $iStyle1 = 0, $iStyle2 = 0)
    ;coded by rover 2k11: tagLOGBRUSH and _WinAPI_SwitchColor() from Yashied's WinAPIEx
    Local Const $tagLOGBRUSH = 'uint Style;dword Color;ulong_ptr Hatch;' ;from WinAPIEx
    Local Const $BS_SOLID = 0
    Local $tLOGBRUSH = DllStructCreate($tagLOGBRUSH)
    DllStructSetData($tLOGBRUSH, 1, $BS_SOLID)
    DllStructSetData($tLOGBRUSH, 2, _WinAPI_SwitchColor($nColor))
    DllStructSetData($tLOGBRUSH, 3, 0);can be 0 for solid brush
    Local $pLOGBRUSH = DllStructGetPtr($tLOGBRUSH)
    If $iStyle1 > 0 And $iStyle2 > 0 Then
        Local $tUserStyle = DllStructCreate("dword;dword")
        DllStructSetData($tUserStyle, 1, $iStyle1)
        DllStructSetData($tUserStyle, 2, $iStyle2)
        $pStyle = DllStructGetPtr($tUserStyle)
        $dwStyleCount = DllStructGetSize($tUserStyle)/4
    Else
        $pStyle = 0
        $dwStyleCount = 0
    EndIf
    Local $aResult = DllCall("gdi32.dll", "handle", "ExtCreatePen", "dword", $iPenStyle, _
    "dword", $iWidth, "ptr", $pLOGBRUSH, "dword", $dwStyleCount, "ptr", $pStyle)
    If @error Then Return SetError(@error, @extended, 0)

    Return $aResult[0]
EndFunc   ;==>_WinAPI_ExtCreatePen

;from WinAPIEx
Func _WinAPI_SwitchColor($iColor)
    Return BitOR(BitAND($iColor, 0x00FF00), BitShift(BitAND($iColor, 0x0000FF), -16), BitShift(BitAND($iColor, 0xFF0000), 16))
EndFunc   ;==>_WinAPI_SwitchColor

I see fascists...

Link to comment
Share on other sites

I know you don't want to use GDI+ but here my solution with GDI and GDI+:

#Include <GDIPlus.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>

ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, @DesktopWidth / 2, @DesktopHeight / 2 + 200, 2, 0xFFFF0000)
ShowCross(@DesktopWidth / 2 + 200, @DesktopHeight / 2, @DesktopWidth / 2 + 200, @DesktopHeight / 2 + 200, 2, 0xFFFF0000)
ShowCross(@DesktopWidth / 2, @DesktopHeight / 2, @DesktopWidth / 2 + 200, @DesktopHeight / 2, 2, 0xFFFF0000)
ShowCross(@DesktopWidth / 2, @DesktopHeight / 2 + 200, @DesktopWidth / 2 + 200, @DesktopHeight / 2 + 200, 2, 0xFFFF0000)

ShowCross(@DesktopWidth / 3, @DesktopHeight / 3, @DesktopWidth / 3, @DesktopHeight / 3 + 200, 1, 0xFFFF0000)
ShowCross(@DesktopWidth / 3 + 200, @DesktopHeight / 3, @DesktopWidth / 3 + 200, @DesktopHeight / 3 + 200, 1, 0xFFFF0000)
ShowCross(@DesktopWidth / 3, @DesktopHeight / 3, @DesktopWidth / 3 + 200, @DesktopHeight / 3, 1, 0xFFFF0000)
ShowCross(@DesktopWidth / 3, @DesktopHeight / 3 + 200, @DesktopWidth / 3 + 200, @DesktopHeight / 3 + 200, 1, 0xFFFF0000)

Sleep(3000)
;~    refresh desktop (clear cross)

_WinAPI_RedrawWindow(_WinAPI_GetDesktopWindow(), 0, 0, $RDW_INVALIDATE + $RDW_ALLCHILDREN)
Exit

Func ShowCross($start_x, $start_y, $end_x, $end_y, $width, $color)
    Local $hDC, $hPen, $obj_orig
    _GDIPlus_Startup()
    $hDC = _WinAPI_GetWindowDC(0) ; DC of entire screen (desktop)
    Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC)
    Local $hPen = _GDIPlus_PenCreate($color, $width)
    Local $aDashes[3]  = [2, 2 * $width, 1]
    _GDIPlus_PenSetDashArray($hPen, $aDashes)
    _GDIPlus_GraphicsDrawLine($hGraphics, $start_x, $start_y, $end_x, $end_y, $hPen)
    _WinAPI_BitBlt($hDC, $start_x, $start_y, $end_x - $start_x, $end_y - $start_x, $hGraphics, 0, 0, $SRCCOPY)

    ; clear resources
    _GDIPlus_GraphicsDispose($hGraphics)
    _WinAPI_ReleaseDC(0, $hDC)
    _GDIPlus_PenDispose($hPen)
    _GDIPlus_Shutdown()
EndFunc   ;==>ShowCross

Func _GDIPlus_PenSetDashArray($hPen, $aDashes)
    Local $iI, $iCount, $tDashes, $pDashes, $aResult
    $iCount = $aDashes[0]
    $tDashes = DllStructCreate("float[" & $iCount & "]")
    $pDashes = DllStructGetPtr($tDashes)
    For $iI = 1 To $iCount
        DllStructSetData($tDashes, 1, $aDashes[$iI], $iI)
    Next
    $aResult = DllCall($ghGDIPDll, "uint", "GdipSetPenDashArray", "handle", $hPen, "ptr", $pDashes, "int", $iCount)
    If @error Then Return SetError(@error, @extended, False)
    Return $aResult[0] = 0
EndFunc

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...