Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate

Drawing a rectangle


  • Please log in to reply
10 replies to this topic
hauss
  • Guests
  • Last active:
  • Joined: --
hello i've found this code
it works but i want to modify it a bit

1) can i make it to unfilled rectangle rather than filled?
currently it's filled with white.

2) it behave something weird when i resize the rectangle from larger to smaller size
it look like i drawing several rectangles at same time

can anyone enlighten me plz
;http://www.autohotkey.com/forum/topic31064.html

coordmode, mouse, screen

lbutton::
mousegetpos,x1,y1
settimer, rectangle, 100
return

lbutton UP::
DllCall("ReleaseDC", UInt, 0, UInt, hDrwArea)
DllCall("FreeLibrary", "UInt", hDrwArea)
DllCall("RedrawWindow", "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0x81)
settimer, rectangle, off
return

rectangle:
mousegetpos,x2,y2,win
winset,redraw,,ahk_id %win%
drawrect(x1,y1,x2,y2)
return


drawrect(x1,y1,x2,y2,color=0x0000ff)
{

   guiID := WinExist()
   hdc := DllCall("GetDC", "UInt", guiID, "UInt")
   ps_Dash:=0
   hPen := DllCall("CreatePen", "Int",PS_DASH, "Int", 4, "Int", color, "UInt")
   objB := DllCall("SelectObject", "UInt", hdc, "UInt", brush, "UInt")
   objP := DllCall("SelectObject", "UInt", hdc, "UInt", hPen, "UInt")
   DllCall("Rectangle", "UInt", hdc, "Int", x1, "Int", y1, "Int", x2, "Int", y2)
}

escape::
exitapp
return


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
You could try drawing with a hollow brush.
brush := DllCall("GetStockObject", "int", HOLLOW_BRUSH:=0x5)
The rest is related to your request "can anyone enlighten me plz" ;):

Device contexts retrieved via GetDC must be released via ReleaseDC, or your script will leak resources. Similarly, GDI objects which you create (such as pens) must also be deleted manually, after reselecting the original object of the relevant type in the device context:
; after calling Rectangle():

; Reselect the original pen so hPen can be deleted:
DllCall("SelectObject", "uint", hdc, "uint", objP)
; Delete hPen:
DllCall("DeleteObject", "uint", hPen)

; This may or may not be necessary if you don't need to delete 'brush':
DllCall("SelectObject", "uint", hdc, "uint", objB)

; Release the device context returned by GetDC:
DllCall("ReleaseDC", "uint", guiID, "uint", hdc)
It is not necessary (but is not harmful) to delete objects returned by GetStockObject.

Since PS_DASH has not been assigned a value, it is interpreted as 0, which is PS_SOLID. Substitute PS_DASH in your code for the value 1, or assign PS_DASH:=1 before calling CreatePen.

DllCall("ReleaseDC", UInt, 0, UInt, hDrwArea)
DllCall("FreeLibrary", "UInt", hDrwArea)

I'm guessing these are copy-paste remnants, since your script doesn't seem to assign hDrwArea a value. ReleaseDC expects a handle to a device context, whereas FreeLibrary expects a handle to a module (DLL). One, the other, or both are sure to fail. In this case it is probably best to delete both lines.


(I may re-post some of this in the other thread.)

BoBo²
  • Guests
  • Last active:
  • Joined: --
MSN: "The Rectangle function draws a rectangle. The rectangle is outlined by using the current pen and filled by using the current brush."

hauss
  • Guests
  • Last active:
  • Joined: --
Thank you Lexikos! you've fully enlighten me :)
i'm having fun with gdi now it's really great that i can use win32 api without learning C language
thank for all the helpers out there i like this community much!

hauss
  • Guests
  • Last active:
  • Joined: --
wait..still weird :(
i've modified to like this as you adviced me it doesn't draw several rectangles now but it redraw each time instead.
i know it's because of me. i just can't think of anything else to solve this. is there any other method to prevent blinking?
i'm close to completion. need a little more help please

;http://www.autohotkey.com/forum/topic31064.html

coordmode, mouse, screen

lbutton::
mousegetpos,x1,y1
settimer, rectangle, 100
return

lbutton UP::
DllCall("ReleaseDC", UInt, 0, UInt, hdc)
DllCall("DeleteObject", "uint", hPen)
DllCall("FreeLibrary", "UInt", hdc)
DllCall("RedrawWindow", "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0x81)
settimer, rectangle, off
return

rectangle:
mousegetpos,x2,y2,win
winset,redraw,,ahk_id %win%
drawrect(x1,y1,x2,y2)
DllCall("RedrawWindow", "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0x81)
return


drawrect(x1,y1,x2,y2,color=0x0000ff)
{
   guiID := WinExist()
   hdc := DllCall("GetDC", "UInt", guiID, "UInt")
   ps_Dash:=0
   hPen := DllCall("CreatePen", "Int",PS_DASH, "Int", 4, "Int", color, "UInt")
   brush := DllCall("GetStockObject", "int", HOLLOW_BRUSH:=0x5)
   objB := DllCall("SelectObject", "UInt", hdc, "UInt", brush, "UInt")
   objP := DllCall("SelectObject", "UInt", hdc, "UInt", hPen, "UInt")
   DllCall("Rectangle", "UInt", hdc, "Int", x1, "Int", y1, "Int", x2, "Int", y2)
}

escape::
exitapp
return


hauss
  • Guests
  • Last active:
  • Joined: --
i fixed redraw part to like this it doesn't redraw anymore if i don't resize but still redrawing while resizing the rectangle. i'm still looking for better way to prevent blinking

rectangle:
mousegetpos,x2,y2,win
drawrect(x1,y1,x2,y2)
if (oldx!=x2 || oldy!=y2)
  DllCall("RedrawWindow", "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0x81)
oldx:=x2, oldy:=y2
return


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
I would not recommend drawing directly to the screen, since to "move" or "erase" what you draw, you need to redraw the window under it. There are a number of ways to show a frame on the screen; I favour the following method:
OnMessage(0x14, "WM_ERASEBKGND")
Gui, -Caption +ToolWindow
Gui, +LastFound
WinSet, TransColor, Black
; Create the pen here so we don't need to create/delete it every time.
RedPen := DllCall("CreatePen", "int", PS_SOLID:=0, "int", 5, "uint", 0xff)
return

WM_ERASEBKGND(wParam, lParam)
{
    global x1, y1, x2, y2, RedPen
    Critical 50
    if A_Gui = 1
    {
        ; Retrieve stock brush.
        blackBrush := DllCall("GetStockObject", "int", BLACK_BRUSH:=0x4)
        ; Select pen and brush.
        oldPen := DllCall("SelectObject", "uint", wParam, "uint", RedPen)
        oldBrush := DllCall("SelectObject", "uint", wParam, "uint", blackBrush)
        ; Draw rectangle.
        DllCall("Rectangle", "uint", wParam, "int", 0, "int", 0, "int", x2-x1, "int", y2-y1)
        ; Reselect original pen and brush (recommended by MS).
        DllCall("SelectObject", "uint", wParam, "uint", oldPen)
        DllCall("SelectObject", "uint", wParam, "uint", oldBrush)
        return 1
    }
}

+LButton::
    MouseGetPos, xorigin, yorigin
    SetTimer, rectangle, 10
return

rectangle:
    MouseGetPos, x2, y2
    
    ; Has the mouse moved?
    if (x1 y1) = (x2 y2)
        return
    
    ; Allow dragging to the left of the click point.
    if (x2 < xorigin) {
        x1 := x2
        x2 := xorigin
    } else
        x1 := xorigin
    
    ; Allow dragging above the click point.
    if (y2 < yorigin) {
        y1 := y2
        y2 := yorigin
    } else
        y1 := yorigin
    
    Gui, Show, % "NA X" x1 " Y" y1 " W" x2-x1 " H" y2-y1
    Gui, +LastFound
    DllCall("RedrawWindow", "uint", WinExist(), "uint", 0, "uint", 0, "uint", 5)
return

+LButton Up::
    SetTimer, rectangle, Off
    Gui, Cancel
return
(Use Shift+LButton or edit before running.)

hauss
  • Guests
  • Last active:
  • Joined: --
what a clever method thanks for teaching such technique it solved all!!
much appreciated Lexikos

rani
  • Members
  • 217 posts
  • Last active: Jul 21 2016 12:53 PM
  • Joined: 18 Mar 2008
rectangles save
now on mouse up the rectangel disapear.

1.
how I can save on screen,after mouse up the rectangles,
so it will be shown on screen, (ant drawn rectangles, after mouse up)
ans save them in some inner array ?

2.
how I take the 'imgae' inside this rectangle ?
for future save ?
3.
how I can set 'my text' ,let sy on border of the rectangle

vik.vega
  • Members
  • 8 posts
  • Last active: Oct 11 2009 09:24 PM
  • Joined: 27 Sep 2009
hi
is it possible to turn this script into a function, so that when i call it, i can draw a single rectangle, and save its coordinates into a ini ?
(i managed the second part, what i can't figure out, is how to "avoid it looping"

thanks :)

Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
I would like the opinions of the pros on this one as well.


To Rani,

The idea of the borders being 4 GUIs was from Lexikos from this thread. It runs a lot smoother then your DLL examples above (On my machine at least which is a gaming PC).

This following code requires ScreenCapture.AHK which can be found here. To be honest, I can't be annoyed to do #Include so I just pasted this into Sean's ScreenCapture.AHK. :p

Hold shift and click and drag to draw the rectangle. Releasing LButton will hide the borders and save a screenshot in the same folder as the script named 'Screen.BMP'.

CoordMode, Mouse, Screen
SetBatchLines, -1

LButton_Held = 0

Loop, 4
{
	Gui, %A_Index%: -Caption +ToolWindow +ToolWindow +AlwaysOnTOp
	Gui, %A_Index%: Color, Red
}
Return

+LButton::
If (LButton_Held == 0)
{
	LButton_Held = 1
	MouseGetPos, Mouse_X, Mouse_Y
	Loop
	{
		MouseGetPos, Mouse_X_2, Mouse_Y_2
		If (Mouse_X_2 > Mouse_X)
		{
			Gui, 1: Show, % "x" Mouse_X " y" Mouse_Y " w" Mouse_X_2 - Mouse_X " h1 NoActivate"
			Gui, 4: Show, % "x" Mouse_X " y" Mouse_Y_2 " w" Mouse_X_2 - Mouse_X " h1 NoActivate"
		}	
		Else
		{
			Gui, 1: Show, % "x" Mouse_X_2 " y" Mouse_Y " w" Mouse_X - Mouse_X_2 " h1 NoActivate"
			Gui, 4: Show, % "x" Mouse_X_2 " y" Mouse_Y_2 " w" Mouse_X - Mouse_X_2 " h1 NoActivate"
		}
		If (Mouse_Y_2 > Mouse_Y)
		{
			Gui, 2: Show, % "x" Mouse_X " y" Mouse_Y " w1 h" Mouse_Y_2 - Mouse_Y " NoActivate"
			Gui, 3: Show, % "x" Mouse_X_2 " y" Mouse_Y " w1 h" Mouse_Y_2 - Mouse_Y " NoActivate"
		}
		Else
		{
			Gui, 2: Show, % "x" Mouse_X_2 " y" Mouse_Y_2 " w1 h" Mouse_Y - Mouse_Y_2 " NoActivate" 
			Gui, 3: Show, % "x" Mouse_X " y" Mouse_Y_2 " w1 h" Mouse_Y - Mouse_Y_2 " NoActivate"
		}
		ToolTip, % "Width: " Mouse_X_2 - Mouse_X " - Height: " Mouse_Y_2 - Mouse_Y 
		If (LButton_Held == 0)
			Break
	}
	Loop, 4
		Gui, %A_Index%: Hide
	ToolTip
	Final_Width := Mouse_X_2 - Mouse_X
	Final_Height := Mouse_Y_2 - Mouse_Y
	If (Final_Width > 0)
		X_Coordinate := Mouse_X
	Else
	{
		Final_Width *= -1
		X_Coordinate := Mouse_X_2
	}
	If (Final_Height > 0)
		Y_Coordinate := Mouse_Y
	Else
	{
		Final_Height *= -1
		Y_Coordinate := Mouse_Y_2
	}
	CaptureScreen(X_Coordinate ",  " Y_Coordinate ", " X_Coordinate + Final_Width ", " Y_Coordinate + Final_Height)
}
Return

+LButton Up::
LButton_Held = 0
Return

Cheers.