OK, so I have been tinkering with the OOP version of GDI some more, and here is where I am at so far.
You will need the class wrapped version of GDip_all from
this post and call it CGdip.ahk
The new class - CGDipHelper.ahk:
Note: This class is in no way complete. It is just a proof-of-concept
I really like how it simplifies working with GDI - the function chaining is really handy, and having the destructors do the garbage collection for you is nice too.
The problem is, I don't really know GDI, so I am kind of stabbing in the dark as to what a lot of things are and whether or not to wrap them in classes (or which class to wrap them in). I have to return to working on UCR at some point, but this is an interesting distraction for now.
Code: Select all
#Include, CGdip.ahk
Class CGDipHelper {
__New(){
; Start gdi+
If !pToken := CGDip.Gdip_Startup()
{
;MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
OutputDebug % "AHK| gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system"
return 0
}
this.ptr := pToken
OutputDebug % "AHK| GDI+ started."
}
__Delete(){
OutputDebug % "AHK| Shutting down GDI+"
CGDip.Gdip_Shutdown(this.ptr)
}
SetImage(hwnd, HBitmap){
return CGDip.SetImage(hwnd, HBitmap.ptr)
}
CreateBitmap(Width, Height, Format=0x26200A){
return new this.Bitmap(Width, Height, Format)
}
CreateBrush(){
return new this.Brush()
}
CreateCompatibleDC(hdc=0){
return new this.CompatibleDC(hdc)
}
CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0){
hBitmap := CGDip.CreateDIBSection(w, h, hdc, bpp, ppvBits)
return new this.HBitmap(hBitmap)
}
CreatePen(ARGB, w){
return new this.Pen(ARGB, w)
}
DrawEllipse(Graphics, Pen, x, y, w, h){
return CGDip.Gdip_DrawEllipse(Graphics.ptr, Pen.ptr, x, y, w, h)
}
DrawRectangle(Graphics, Pen, x, y, w, h){
return CGDip.Gdip_DrawRectangle(Graphics.ptr, Pen.ptr, x, y, w, h)
}
SelectObject(DC, hgdiobj){
return CGDip.SelectObject(DC.ptr, hgdiobj)
}
Class Bitmap {
__New(Width, Height, Format=0x26200A){
OutputDebug % "AHK| Creating Bitmap"
this.ptr := CGDip.Gdip_CreateBitmap(Width, Height, Format)
}
__Delete(){
OutputDebug % "AHK| Deleting Bitmap"
CGDip.Gdip_DisposeImage(this.ptr)
}
GetGraphics(){
pGraphics := CGDip.Gdip_GraphicsFromImage(this.ptr)
return new CGDipHelper.Graphics(pGraphics)
}
CreateHBITMAP(Background=0xffffffff){
hBitmap := CGDip.Gdip_CreateHBITMAPFromBitmap(this.ptr, Background)
return new CGDipHelper.HBitmap(hBitmap)
}
}
Class HBitmap {
__New(hBitmap){
OutputDebug % "AHK| Creating HBitmap"
this.ptr := hBitmap
}
__Delete(){
OutputDebug % "AHK| Deleting HBitmap"
CGDip.DeleteObject(this.ptr)
}
}
Class Graphics {
__New(pGraphics){
OutputDebug % "AHK| Creating Graphics"
this.ptr := pGraphics
}
__Delete(){
OutputDebug % "AHK| Deleting Graphics"
CGDip.Gdip_DeleteGraphics(this.ptr)
}
SetSmoothingMode(SmoothingMode)
{
ret := CGDip.Gdip_SetSmoothingMode(this.ptr, SmoothingMode)
return this
}
FillRectangle(Brush, x, y, w, h){
CGDip.Gdip_FillRectangle(this.ptr, Brush.ptr, x, y, w, h)
return this
}
FillEllipse(Brush, x, y, w, h){
CGDip.Gdip_FillEllipse(this.ptr, Brush.ptr, x, y, w, h)
return this
}
}
Class Brush {
ptr := 0
__New(){
}
__Delete(){
this.Delete()
}
Delete(){
if (this.ptr){
OutputDebug % "AHK| Deleting Brush"
CGDip.Gdip_DeleteBrush(this.ptr)
return 1
}
return 0
}
CreateSolid(ARGB=0xff000000){
this.Delete()
this.ptr := CGDip.Gdip_BrushCreateSolid(ARGB)
OutputDebug % "AHK| Creating Brush"
return this
}
FillRectangle(Graphics, x, y, w, h){
if (this.ptr){
CGDip.Gdip_FillRectangle(Graphics.ptr, this.ptr, x, y, w, h)
return this
}
return 0
}
FillEllipse(Graphics, x, y, w, h){
if (this.ptr){
CGDip.Gdip_FillEllipse(Graphics.ptr, this.ptr, x, y, w, h)
return this
}
return 0
}
}
Class Pen {
__New(ARGB, w){
this.Create(ARGB, w)
}
Create(ARGB, w){
this.Delete()
OutputDebug % "AHK| Creating Pen"
this.ptr := CGDip.Gdip_CreatePen(ARGB, w)
return this
}
__Delete(){
this.Delete()
}
Delete(){
if (this.ptr){
OutputDebug % "AHK| Deleting Pen"
CGDip.Gdip_DeletePen(this.ptr)
}
}
}
class CompatibleDC {
__New(hdc){
OutputDebug % "AHK| Creating Compatible DC"
hDC := CGDip.CreateCompatibleDC(hdc)
this.ptr := hDC
}
__Delete(){
OutputDebug % "AHK| Deleting Compatible DC"
CGDip.DeleteDC(this.ptr)
}
GetGraphics(){
pGraphics := CGDip.Gdip_GraphicsFromHDC(this.ptr)
return new CGDipHelper.Graphics(pGraphics)
}
UpdateLayeredWindow(hwnd, x="", y="", w="", h="", Alpha=255){
CGDip.UpdateLayeredWindow(hwnd, this.ptr, x, y, w, h, Alpha)
}
}
}
Example #1 from the tutorial re-written to use this class:
Code: Select all
; gdi+ ahk tutorial 1 written by tic (Tariq Porter)
; Requires Gdip.ahk either in your Lib folder as standard library or using #Include
;
; Tutorial to draw a single ellipse and rectangle to the screen
#SingleInstance, Force
#NoEnv
SetBatchLines, -1
; Uncomment if Gdip.ahk is not in your standard library
#Include, CGDipHelper.ahk
OutputDebug DBGVIEWCLEAR
global GDI := new CGDipHelper()
; Set the width and height we want as our drawing area, to draw everything in. This will be the dimensions of our bitmap
Width :=1400, Height := 1050
; Create a layered window (+E0x80000 : must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption
Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
; Show the window
Gui, 1: Show, NA
; Get a handle to this window we have created in order to update it later
hwnd1 := WinExist()
; Create a gdi bitmap with width and height of what we are going to draw into it. This is the entire drawing area for everything
;hbm := CreateDIBSection(Width, Height)
HBitmap := GDI.CreateDIBSection(Width, Height)
; Get a device context compatible with the screen
;hdc := CreateCompatibleDC()
DC := GDI.CreateCompatibleDC()
; Select the bitmap into the device context
obm := GDI.SelectObject(DC, HBitmap.ptr)
; Get a pointer to the graphics of the bitmap, for use with drawing functions
; Set the smoothing mode to antialias = 4 to make shapes appear smother (only used for vector drawing and filling)
G := DC.GetGraphics().SetSmoothingMode(4)
; Create a fully opaque red brush (ARGB = Transparency, red, green, blue) to draw a circle
Brush := GDI.CreateBrush()
; Fill the graphics of the bitmap with an ellipse using the brush created
; Filling from coordinates (100,50) an ellipse of 200x300
Brush.CreateSolid(0xffff0000).FillEllipse(G, 100, 500, 200, 300)
; Create a slightly transparent (66) blue brush (ARGB = Transparency, red, green, blue) to draw a rectangle
; Fill the graphics of the bitmap with a rectangle using the brush created
; Filling from coordinates (250,80) a rectangle of 300x200
Brush.CreateSolid(0x660000ff).FillRectangle(G, 250, 80, 300, 200)
; Update the specified window we have created (hwnd1) with a handle to our bitmap (hdc), specifying the x,y,w,h we want it positioned on our screen
; So this will position our gui at (0,0) with the Width and Height specified earlier
DC.UpdateLayeredWindow(hwnd1, 0, 0, Width, Height)
; Select the object back into the hdc
GDI.SelectObject(DC, obm)
Return
;#######################################################################
Esc::ExitApp
Some code I wrote to draw a circle with optional border - sort of based on example 9:
Code: Select all
#SingleInstance, Force
#NoEnv
SetBatchLines, -1
#Include, CGDipHelper.ahk
OutputDebug DBGVIEWCLEAR
global GDI := new CGDipHelper()
;Gui, 1: +ToolWindow -Caption +AlwaysOnTop
Gui, 1: +HwndhGui
Gui, 1: Margin, 0, 0
Gui, 1: Add, Picture, w400 h400 0xE hwndhImage
DrawCircle(hImage, 0xFF0000FF, 0xFFFFFFFF, 0xFF000000, 3)
Gui, 1: Show
;WinSet,TransColor, FFFFFF, % "ahk_id " hGUI
Return
DrawCircle(hwnd, Foreground, Background, Border := -1, BorderWidth := 0)
{
; We also want to width and height (posw and Posh)
GuiControlGet, Pos, Pos, % hwnd
bm := GDI.CreateBitmap(PosW, PosH)
G := bm.GetGraphics().SetSmoothingMode(4)
x := 0, y := 0
Brush := GDI.CreateBrush()
G.FillRectangle(Brush.CreateSolid(Background), x, y, Posw, Posh)
if (Border != -1){
G.FillEllipse(Brush.CreateSolid(Border), x, y, PosW, PosH)
PosW -= BorderWidth*2, PosH -= BorderWidth*2, x += BorderWidth, y += BorderWidth
}
G.FillEllipse(Brush.CreateSolid(Foreground), x, y, PosW, PosH)
GDI.SetImage(hwnd, bm.CreateHBITMAP())
Return, 0
}
;#######################################################################
Esc::
GuiClose:
ExitApp
Return
Example #2
Code: Select all
; gdi+ ahk tutorial 2 written by tic (Tariq Porter)
; Requires Gdip.ahk either in your Lib folder as standard library or using #Include
;
; Tutorial to draw a single ellipse and rectangle to the screen, but just the outlines of these shapes
#SingleInstance, Force
#NoEnv
SetBatchLines, -1
#Include, CGDipHelper.ahk
OutputDebug DBGVIEWCLEAR
global GDI := new CGDipHelper()
; Set the width and height we want as our drawing area, to draw everything in. This will be the dimensions of our bitmap
Width := 600, Height := 400
; Create a layered window (+E0x80000 : must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption
Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
; Show the window
Gui, 1: Show, NA
; Get a handle to this window we have created in order to update it later
hwnd1 := WinExist()
; Create a gdi bitmap with width and height of what we are going to draw into it. This is the entire drawing area for everything
;hbm := CreateDIBSection(Width, Height)
HBitmap := GDI.CreateDIBSection(Width, Height)
; Get a device context compatible with the screen
DC := GDI.CreateCompatibleDC()
; Select the bitmap into the device context
obm := GDI.SelectObject(DC, HBitmap.ptr)
; Get a pointer to the graphics of the bitmap, for use with drawing functions
; Set the smoothing mode to antialias = 4 to make shapes appear smother (only used for vector drawing and filling)
G := DC.GetGraphics().SetSmoothingMode(4)
; Create a fully opaque red pen (ARGB = Transparency, red, green, blue) of width 3 (the thickness the pen will draw at) to draw a circle
Pen := GDI.CreatePen(0xffff0000, 3)
; Draw an ellipse into the graphics of the bitmap (this being only the outline of the shape) using the pen created
; This pen has a width of 3, and is drawing from coordinates (100,50) an ellipse of 200x300
GDI.DrawEllipse(G, Pen, 100, 50, 200, 300)
; Create a slightly transparent (66) blue pen (ARGB = Transparency, red, green, blue) to draw a rectangle
; This pen is wider than the last one, with a thickness of 10
Pen.Create(0x660000ff, 10)
; Draw a rectangle onto the graphics of the bitmap using the pen just created
; Draws the rectangle from coordinates (250,80) a rectangle of 300x200 and outline width of 10 (specified when creating the pen)
GDI.DrawRectangle(G, Pen, 250, 80, 300, 200)
; Update the specified window we have created (hwnd1) with a handle to our bitmap (hdc), specifying the x,y,w,h we want it positioned on our screen
; So this will position our gui at (0,0) with the Width and Height specified earlier
DC.UpdateLayeredWindow(hwnd1, 0, 0, Width, Height)
; Select the object back into the hdc
GDI.SelectObject(DC, obm)
Return
;#######################################################################
Esc::
ExitApp