Track Graphic Line Measurement Segments Using AutoHotkey Arrays

When Refreshing the MouseMeasure.ahk Invisible GUI Graphics Layer, AutoHotkey Uses a Simple Array of Associative Arrays to Track the Data

In my last blog (“Measure Multiple Line Segments with an AutoHotkey On-Screen Ruler“), I introduced multi-segment lines for estimating distances of non-linear routes. When refreshing the graphics to animate the moving line, all previously fixed segments need redrawing. Objects-based arrays provide the best method for tracking and regenerating these lines.

Each leg of the journey corresponds to a simple array element containing an associative array of data. The white box displays the key:value data saved in MyArray[4].

The difference between pseudo-arrays, simple arrays, and associative arrays can get confusing. For the novice AutoHotkey scriptwriter, unfamiliar Object-Oriented Programming (OOP) notation can make understanding the code even more difficult—especially if you attempt to learn OOP from online documentation.

You may think you need to choose between the traditional AutoHotkey syntax and OOP coding, but you don’t! AutoHotkey allows you to mix-and-match most OOP and classic AutoHotkey syntax—as long as you understand how they integrate.

As for myself, I locate functioning AutoHotkey examples, then figure out how they work. The arrays in MouseMeasureMultiLine.ahk script get the job done while using mixed types of syntax—including OOP notation. You might say that the script uses a simple array (or indexed array) of associative arrays to create a table of graphic line properties. The OOP notation makes it easier to manipulate the array data.

A Multitude of AutoHotkey Tips and Tricks

See “Using Associative Arrays to Solve the Instant Hotkey Data Recall Problem” for explanations of pseudo-arrays, simple arrays, and associative arrays—plus, how to set them up (updated and included in Chapter 12.1 of the book Jack’s Motley Assortment of AutoHotkey Tips).

I only introduce a little of the OOP notation in this blog—providing a look into how to use the array objects and properties in the MouseMeasureMultiLine.ahk script. In my next blog, I plan to offer more insight into elementary OOP array techniques. Anything I know about OOP comes from doing it. I find most OOP documentation mystifying. While it would probably help, happily, you don’t need to completely understand OOP to include it in your AutoHotkey scripting.

An Array of Arrays for Saving Graphic Line Data

The MouseMeasureMultiLine.ahk script uses a simple indexed array (MyArray[]) to save each sequential line description and the associated calculated values in the form of an associative array. That array of data both describes the line and saves pertinent information. But, before saving any data, we must initiate the Array Object.

Global MyArray := Array()
Array_count := 0
totdist := 0

The array definition (or object creation) serves two purposes:

  1. On the first run, the code initializes the array object MyArray and sets the values for the number of legs (Array_count) and the total calculated distance (totdist) to zero.
  2. Whenever beginning a new measurement or restarting the current one, the code resets both the array object and all initial values to zero.

The line-counting simple array takes the form of:

MyArray[Array_count]

While not an absolute rule, using the square brackets […] usually denotes a simple indexed array.

The following defines the line-data associative array:

MyArray[Array_count] := {sx:sx, sy:sy, ex:ex,ey:ey
     , pixellength:dist
     , length:distCalibrated
     , total:legtotCalibrated}

AutoHotkey uses curly brackets {…} to define associative arrays. They must contain key:value pairs separated by commas. In an associative array, the key acts like a variable name, and the value represents the contents of the key.

The start coordinates (sx,sy) and endpoints (ex,ey) describe the position and length of the measuring line. Saving this data makes possible the continuous refreshing of each graphic line. Other pertinent information includes the calculated length of the line in pixels (pixellength:dist—the span of the hypotenuse between the two points), the converted distance (length:distCalibrated) in calibrated units (inches, miles, etc.), and the total distance of all legs (total:legtotCalibrated) from the first start point to the endpoint of the current leg.

The expression assigns an associative array in the key:value format to a member variable of the simple indexed array MyArray[Array_count]—tracking values with consecutive numbers (e.g. 1, 2, 3, …). This allows AutoHotkey to save associative array segment data for each line in order as the user pins each with a click of the left mouse button:

LButton::
	Array_count++
	totdist := totdist + dist
	MyArray[Array_count] := {sx:sx, sy:sy, ex:ex, ey:ey, pixellength:dist, length:distCalibrated, total:legtotCalibrated}
	MouseGetPos,sx,sy
	ToolTip, %distCalibrated% %units%, %ex%, %ey%, % Array_count + 1
Return
Library Benefits

First, the script jumps to the next array element by incrementing the leg number by one (Array_count++). Next, the total saved distance in pixels adds the new pixel length (totdist := totdist + dist).

The leg ToolTip sets to a new ToolTip number (Array_count + 1). The script uses the incremented number for the ToolTip because the original tracking ToolTip defaults to 1. (AutoHotkey limits the maximum number of ToolTips to 20.)

Note: I needed to add a new CoordMode command line to the beginning of the script:

CoordMode, ToolTip, Screen

since, by default, non-maximized windows set the new ToolTips relative to the current active window rather than the screen.

Refreshing Graphic Lines on the Invisible GUI

After adding each new graphic line segment, we use Array_count to increment a Loop for refreshing each line on the invisible graphics GUI.

Loop, % Array_count	{
	Gdip_DrawLine(GdipOBJ.G, myPen
            , MyArray[A_Index].sx, MyArray[A_Index].sy
            , MyArray[A_Index].ex, MyArray[A_Index].ey)
	}

(AutoHotkey line-continuation techniques used to wrap lines of code for display purposes. )

This must occur each time the DrawStuff subroutine refreshes the GUI graphics—every 50 milliseconds. Otherwise, the lines would disappear. The graphics redraw so smoothly that it seems the lines never disappear.

Object Oriented Programming Notation

While I plan a mini-tutorial on how to use associative arrays for my next blog, I mix simple array notation with object notation in the MouseMeasureMultiLine.ahk script. To recall the line data for a particular segment, we must use the simple array notation which includes the index number inside the square bracket […]. By adding a dot ( . ) and the key for a property in the associative array, we retrieve the corresponding value:

LegLength := MyArray[A_Index].length
TotalLength := MyArray[A_Index].total

The key name appearing after the dot makes properties of the MyArray object immediately accessible. You only need to append a dot and the key name to the object name to retrieve that value.

Note: Object properties can also include more properties. For example, if defining a new associative array key:value with a variable rather than a value (length) and defining that variable as an associative array:

MyArray := Array()
MyArray[Array_count] := {sx:sx, sy:sy, ex:ex, ey:ey
        ,  pixellength:dist
        , length: length
        , total:legtotCalibrated}
MyArray[Array_count].length := {value: distCalibrated
        , units: units}

you can recall properties such as:

LegDistance := MyArray[A_Index].length.value
LegUnits := MyArray[A_Index].length.units

I’ll discuss more about this object notation works in my next blog.

Loop to Setup Hotkeys

Pressing the Shift key to finalize a distance-measuring session when running the MouseMeasureMultiLine.ahk script, causes AutoHotkey to save data for the last line and display a list of all the legs while setting up Hotkeys for inserting data into other documents or editing fields. The script both captures the needed text and adds the number keys (1-9) as instant-insertion Hotkeys using the standard Loop command.

As the Loop increments through Array_count, the built-in variable A_Index identifies the respective properties for writing to the MsgLine variable. The script employs the same Object.Property notation discussed above:

loop, % Array_count {
     MsgLine := MsgLine . "Leg " . A_Index ": " 
     . MyArray[A_Index].length . " Total: " . MyArray[A_Index].total
     . " " . units . "`n"
     If A_Index < 10
          Hotkey, % "$" A_Index , DistanceSend, On
}
MsgBox, 4096, Multi-Leg Mouse Measure, % MsgLine

Once understood, associative array objects provides a method for tracking diverse data in a readable form. Toward a goal of increased insight, next time, I plan a short tutorial on how to build object data array structures for saving related information.

The current version of the MouseMeasureMultiLine.ahk script now uses the Delete key to remove the last pinned line in the middle of a measuring session and Ctrl+Delete clears the invisible graphics cover and resets the values for a new session.

Click the Follow button at the top of the sidebar on the right of this page for e-mail notification of new blogs. (If you’re reading this on a tablet or your phone, then you must scroll all the way to the end of the blog—pass any comments—to find the Follow button.)

jack

This post was proofread by Grammarly
(Any other mistakes are all mine.)

(Full disclosure: If you sign up for a free Grammarly account, I get 20¢. I use the spelling/grammar checking service all the time, but, then again, I write a lot more than most people. I recommend Grammarly because it works and it’s free.)

Find my AutoHotkey books at ComputorEdge E-Books!

Find quick-start AutoHotkey classes at “Robotic Desktop Automation with AutoHotkey“!

One thought on “Track Graphic Line Measurement Segments Using AutoHotkey Arrays

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s