Custom progress bar Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
colmik
Posts: 83
Joined: 11 Mar 2014, 18:21

Custom progress bar

19 Aug 2020, 19:09

My daughter has had ADHD all her life and struggles with time management at work, so she recently bought a set of glass egg-timers, that measure 3 min ... 30 min.
She says they help, but you don't notice an egg timer has timed out till you look at it, so I thought I'd write an on-screen egg timer for her, as the work she is timing is on a PC.
The app is profilable and can run for any amount of time.
The profiles are for period, colour, orientation (horizontal/vertical), and there are radio buttons to make the hourglass (progress bar) invisible until 50%, 70%, 80%, 90% of time has elapsed. There are check-boxes for audio warnings at 50%, 70%, 80%, 90% and "Time up". The selections are made when starting the app.
I made the GUI first, then the audio warnings, and that all works fine. Then I turned my attention to the progress bar that I had envisaged for the visual timer - but I can't find what I want, so any help to get me going would be appreciated.
I want the timer (progress bar) to be as unobtrusive as possible. As such, a simple wire-frame, black, horizontal oblong for the border of the progress bar would do fine, with a coloured in-fill to show the progress, and no Windows Title bar because that makes it bigger. However, if it is getting in the way of other things on the screen, then I'd like it to be movable - and there's a problem there.

I tried ...

Code: Select all

Progress, b1 m Zx5 Cbgreen w200 Zh8 h18
Progress, 50 ; Set the position
sleep 2000
... and it doesn't look bad - though it still has a Windows structure inside the border (rather than a simple line border) - but the big problem is that it's not movable.
The AHK manual says

M: The window will be movable by the user (except if borderless).
- so if I want to move it, I need a border.

B: Borderless: The window will have no border and no title bar. To have a border but no title bar, use B1 for a thin border or B2 for a dialog style border.
I find that B1 / B2 look the same, and neither gives a movable progress bar.

If I use ...

Code: Select all

Gui, Add, Progress, hwndProgress1 vProgress1 -Smooth w250 h18
; Gui, Add, Button, vChangeStyle w100 x75 y40, Change Style
Gui, Show ; , , Please wait...
GuiControl,, Progress1, 50
Return
... that gives a movable progress bar - but it also has a Windows Title bar, so it is a lot bigger

If I make a vertical bar, keeping it as small as possible ...

Code: Select all

Gui, Add, Progress, Vertical vMyProgress
Gui, Show
return

sleep 3000
GuiControl,, MyProgress, +10
... there is a Title bar, but I still can't move it because the title bar is full of buttons, so I can't click on the title bar itself.

Then I thought of having a wire frame, with a colour in-fill to show progress - both by using splashimage, suitably sized.
I drew a wire frame with MS_Paint and saved it as a .bmp, in the expectation of being able to display it with ...

Code: Select all

SplashImage, progress_frame.bmp, h40 w500
Sleep, 4000
SplashImage, Off
... It gives me a full, white screen, with my little wire frame in the middle - but I don't want to overlay everything on the screen.

I just don't know enough about this language without reading the manual enough times to memorise it, so please, somebody who has already done that, is what I want a viable thing to do?
If I manage to draw a custom progress bar, can I move it by detecting a left-click, then starting a timer to follow the mouse and keep erasing/redrawing the control?

Sorry this is all a bit rambling, but although I believe there is a way to do it, it's frustrating trying to find it.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Custom progress bar

19 Aug 2020, 20:54

Hello, try:

Code: Select all

Gui, -Caption +AlwaysOnTop +Owner
Gui, Margin, 0, 0
Gui, Add, Progress, vProgress1 -Smooth w250 h18 Disabled
Gui, Add, Text, xp wp hp BackgroundTrans gMoveGUI +HWNDhText
Gui, Show

GuiControl,, Progress1, 50
ChangeCursor(hText)
Return

MoveGUI() {
	; WM_NCLBUTTONDOWN := 0xA1, HT_CAPTION := 0x2
	PostMessage, 0xA1, 0x2,,, A
}

ChangeCursor(hWnd) {
	hCursor := DllCall("LoadCursor", "ptr", 0, "int", SizeAll := 32646, "ptr")
	DllCall("SetClassLong" (A_PtrSize=8 ? "ptr":""), "ptr", hWnd, "int", -12, "ptr", hCursor)
}
Let me know if you have any questions.
colmik
Posts: 83
Joined: 11 Mar 2014, 18:21

Re: Custom progress bar

20 Aug 2020, 06:23

Wow! What a guru you are! And such an elegant piece of code at that.
Thank you so much, tmplinshi - that's exactly what I wanted. I'll spend some time poring over the code to figure out how it works.
The capability of the language is amazing, but that sort of conversancy, I would guess, is the product of using it a lot.
One day ... one day.
colmik
Posts: 83
Joined: 11 Mar 2014, 18:21

Re: Custom progress bar

21 Aug 2020, 14:38

tmplinshi, This is really great. I can resize it and set the colour of the bar; and I can make it vertical, and as I said before, this is exactly what I wanted - or very nearly. I have spent a good deal of time trying to figure out how it all works, and I'm quite puzzled by some of it.

By deleting individual commands and parameters, and seeing what the changes are, I can see that
Gui, -Caption is what eliminates the title bar.

I have changed the values in "Gui, Margin, 0, 0" to "Gui, Margin, 5, 5" for example, so I see what that does and how it interacts with
Gui, Color, ppp, qqq - although Margin is different from what I understand from the manual. It says "number of pixels of space to leave at the left/right and top/bottom sides of the window when auto-positioning" That seems to me like the spacing between independent controls within a Gui - but clearly, it's not that.

Gui, Add, Text came as a surprise, as no text is involved - and I still don't fully understand it. I can see that xp wp hp make the text field the same size as the Progress bar, and in the same horizontal position. gMoveGUI is associated with the text command, so I suppose that the two controls - Progress and Text are stuck together, so that when the text moves, the progress bar moves with it? Is that how it works? Is that why you have Disabled on the Progress bar, to prevent interaction with it, and allow it to move with the text field? I know that if I delete the Disabled parameter, I can't move the Progress bar at all.
I had understood -Smooth to be for the appearance of the Progress bar - to make it segmented instead of continuous. In any case, when I delete it, I can't see any difference.

PostMessage goes completely over my head! I gather it's a shortcut for those who understand Windows internals, and know what they're doing.

The way I want to implement the control, it should show a diminishing amount of time remaining, so rather than the bar growing from the left, I want it to shrink towards the right (in other words, to be right-justified in its box). At the moment, the colours are ...

[[BLUE BAR] GREY BACKGROUND] so if I reversed the colours, I get
[[GREY BAR (looks like background)]BLUE BACKGROUND (looks like the bar)]. With the GREY advancing from the left, the BLUE appears to diminish to the right, and the following (copied from somebody else's query) demonstrates it.

Code: Select all

ProgressValue = 30
Gui Add, Text,, Standard
Gui Add, Progress, vProgress1
Gui Add, Text,, Inverted
Gui Add, Progress, cSilver backgroundNavy vProgress2

GuiControl ,, Progress1, %ProgressValue%
GuiControl ,, Progress2, % ( 100- ProgressValue )

Gui Show
It works, but it seems that Windows paints the background colour into the box, then paints the progress bar on top of it - but 1 pixel narrower all the way around, so that in the inverted one in the above example, there is a blue border around the "background" (actually the progress bar).
In fact, this happens on the "Standard" bar also, but it is not noticed because that border is the same colour as the background colour.

This effect also happens when I reverse the colours in the script you gave me.
It's a small thing, but is there a way of avoiding that - or is it just the way Windows does it? If it can't be solved, I guess we can live with it.

Oh - and that "ChangeCursor(hWnd)" was a nice touch. Thank you.
Aladin
Posts: 3
Joined: 13 Jun 2020, 06:06

Re: Custom progress bar

21 Aug 2020, 16:48

Code: Select all

Gui, -Caption +AlwaysOnTop 
Gui, Margin, 2, 2														; Randgröße, y-Wert "Progress" gleich
OnMessage(0x201, "LMaus")											; linken Maustaste - Fenster verschieben
 AnZahl   := 32														; Anzahl der Balken
 Farbwahl := "ff52,ff23,12ff00,75ff00,aaff00,d3ff00,fcff00,ffea00,ffd300,ffb600,ffb600,ff9300,ff6a00,ff3b00,ff1700,ff0000"
Loop, parse, Farbwahl, `,												; Farben von rot bis grün
   Farbe%A_Index%  = %A_LoopField%									; Farbwahl = Farben_1... Farben_16
Loop %AnZahl% { 													; Schleife
 Zustand%A_Index%  = True											; Zustand aktivieren
 Random, Balken%A_Index%, 1, 100 									; Startwert der Balken erzeugen
 SetTimer, Balken, 8													; Zeitintervall für die Balkenanzeige 
Gui, Add, Progress, vBalken%A_Index% h12 w260 						; aktualisiert den Fortschrittsbalken
}
Gui, Show, AutoSize													; Steuerelement zentriert anzeigen
Return

Balken:									
 Loop %AnZahl% {													; Schleife bis Anzahl
  If Zustand%A_Index%  = True											; wenn Zustand aktiv
	{
	Zähler%A_Index%   += 1											; Zähler hochzählen
	If Zähler%A_Index% = % Balken%A_Index%							; wenn Zähler = Zufallszahl Balken
	  {
	  Random, Balken%A_Index%	, 1, Balken%A_Index%				; Zufallszahl für Balken erzeugen
	  Balken%A_Index%  = % (Zähler%A_Index% - Balken%A_Index%)		; wenn Zufallszahl Balken = Zähler - Balken
	  Zustand%A_Index% = False										; Zustand deaktivieren
	  exit															; Subroutine verlassen
	} }
	Else If Zustand%A_Index% {										; wenn Zustand deaktiviert
	Zähler%A_Index%   -= 1											; Zähler runtererzählen
	if Zähler%A_Index% = % Balken%A_Index%							; wenn Zähler = Zufallszahl Balken
	  {
	  Random, Balken%A_Index%, 1, (100 - Zähler%A_Index%)			; Zufallszahlen der Balken erzeugen
	  Balken%A_Index%  = % (Zähler%A_Index% + Balken%A_Index%)		; wenn Zufallszahl Balken = Zähler - Balken
	  Zustand%A_Index% = True										; Zustand aktivieren
	  exit															; Subroutine verlassen
	} }
  Farbe := ("Farbe" + Ceil(Zähler%A_Index% / (100 / 16)))					; Farbwert in Farben umwandeln
  Farbe := %Farbe%													; Farbwert definieren
 GuiControl, +c%Farbe%, Balken%A_Index%								; Farbe für Balkenanzeige
 GuiControl, 		  , Balken%A_Index%, % Zähler%A_Index%				; Länge der Balkenanzeige
}
Return

LMaus() {
  PostMessage, 0xA1, 2 												; rahmenloses Fenster verschieben
}

ESC::ExitApp														; ESC unterbricht Makro
colmik
Posts: 83
Joined: 11 Mar 2014, 18:21

Re: Custom progress bar

21 Aug 2020, 18:07

Aladin,

Very pretty, but I'm really not sure why you posted it here instead of, perhaps, in the Scripts forum.
Unfortunately not what I'm looking for.
colmik
Posts: 83
Joined: 11 Mar 2014, 18:21

Re: Custom progress bar

21 Aug 2020, 18:40

tmplinshi, the bottom of my thread was kinda hijacked. If you could answer my question above (as you invited), I'd really appreciate your input. My issue isn't a show-stopper, and it's possible it can't be solved - but you're one of the few that would know.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Custom progress bar

22 Aug 2020, 01:13

although Margin is different from what I understand from the manual..
If you add more than 1 controls, you'll have a better understanding.
Spoiler

MoveGUI() function actually moves the whole window, not the text control. The function sends a WM_NCLBUTTONDOWN message to the title bar, as if you're really dragging the title bar.

It's not allowed to add gMoveGUI option to the progress control, so I added a transparent text control over it. However when the progress control repaints (e.g. value changes), it moves on top of the text control, and you can no longer click on the text control. Disabled option prevent this.

Instead of adding a text control, you can also monitor WM_LBUTTONDOWN (0x201) message using OnMessage command, like Aladin did.
To remove the progress border, you can place progress control at position -1,-1, so that the left/top border is invisible, and then display the GUI window two pixels smaller than the progress control, to hide the right/bottom border. Example:

Code: Select all

Gui, -Caption +AlwaysOnTop
Gui, Margin, 0, 0
Gui Add, Progress, cSilver backgroundNavy x-1 y-1 w200 h18 vProgress1, 70
Gui, Show, w198 h16 NoActivate
OnMessage(0x201, "WM_LBUTTONDOWN")
Return

WM_LBUTTONDOWN() {
	; WM_NCLBUTTONDOWN := 0xA1, HT_CAPTION := 0x2
	PostMessage, 0xA1, 0x2,,, A
}
But if you want the margin not to be "0,0", or need to add other controls:
Spoiler
colmik
Posts: 83
Joined: 11 Mar 2014, 18:21

Re: Custom progress bar

24 Aug 2020, 07:51

tmplinshi, the control you proposed looks very nice. Thank you.
The long delay in replying is not due to ingratitude or bad manners, but due to yet another problem I'm having - but I want to solve this one if I can. I'm feeling as if I have hardly contributed to this script.

In the past, I have written scripts of 500 lines or more, handling some quite complex (financial) tasks, so it's an irritation to my psyche that I'm having so much trouble with the triviality of putting a minute minder on the screen.
colmik
Posts: 83
Joined: 11 Mar 2014, 18:21

Re: Custom progress bar

25 Aug 2020, 18:51

After three days trying to solve this, I'm throwing my hands up. I've tried a lot of stuff, but clearly, not the right stuff.
Somebody please tell me what I'm doing wrong.
I have pared my script down to a much smaller script that still shows the issue.

When you run the script, just put a number 1 in the box (it represents 1 minute).
The script shows a progress bar, which is "full". It is supposed to start full and tick down to empty in 1 minute (if you entered a 1), but although the GuiControl line in the Timer loop gets executed as shown by the trace, it doesn't have any effect. If I replace it with

Code: Select all

GuiControl,, Progress1, 50
... the progress bar remains full.

Here's the slimmed-down script

Code: Select all

#SingleInstance force
#NoEnv
 
SetWorkingDir %A_ScriptDir%

Gui, Gui_1:Default 
Gui, Color, Silver, White
Gui, Add, GroupBox, x16 y7 w410 h110 , Timer Parameters
Gui, Add, Text, x26 y27 w100 h20 +Center, Period of timer  ; Number of minutes / Hours
Gui, Add, Edit, x116 y27 w60 h20 vPeriod, Number
Gui, Add, Text, x180 y27 w200 h20 , Enter number of minutes or 0:40 or 2:15
Gui, Add, Text, x26 y47 w300 h20 +Center, Other Controls deleted for this test

Gui, Add, GroupBox, x16 y122 w410 h80 , Timer Operations
Gui, Add, Text, x26 y142 w300 h20 +Center, Other controls deleted for this test
Gui, Add, Button, Default x316 y212 w50 h30 gSettingsAccepted Default, OK
Gui, Add, Button, x33 y212 w100 h30 gAssist, Help
Gui, Show, x131 y91 h252 w438, Minute Minder

st := 0        ; Show Timer
tt := 0        ; TenthTime - incremented every 10 ticks
Ticks := 100   ; Sets the length of the progress bar
OutputDebug DBGVIEWCLEAR

Return    ; end of gui declarations

GuiClose:
ExitApp

SettingsAccepted:
Gui Submit

; split number 0f minutes and hours, work out TimePeriod (total time) and TickPeriod (100th of total time)
StringSplit, Pd_, Period, :
If(Pd_0 > 1)
  TimePeriod := (Pd_1 * 60 + Pd_2) * 60000  ; minutes * 60 * 1000 mS
Else
  TimePeriod := Pd_1 * 60000    ; minutes * 60 * 1000 mS
  
TickPeriod := floor(TimePeriod/100)   ; Hundredth of total time to tick down progress bar

SetTimer,TimerTick,%TickPeriod%    ; used for the minute minder - ticks 100 times

BarColour = Red

ProgressWidth = 150  ; these two variables are set by the above gui in my original script
ProgressHeight = 12   ; they are used in the gui below, and that works.

Gui, Destroy  ; this gui has served its purpose, and has set its variables as desired.
; ================================================================================================

Gui, new
Gui, -Caption +AlwaysOnTop +Owner  
Gui, Margin, 0, 0 
Gui, Add, Progress, cSilver background%BarColour% vProgress1 w%ProgressWidth% h%ProgressHeight% Disabled, 0
Gui, Add, Text, xp wp hp BackgroundTrans gMoveGUI +HWNDhText
Gui, Show

ChangeCursor(hText)

; ================================================================================================
return

TimerTick:
{ Ticks--                   ; there are 100 ticks during the chosen period
  gp1 := 100 - Ticks
  FractionalTicks := Ticks / 10        ; this is for the audio warnings at 50%, 70%, 80% etc.
  gp2 := Floor(FractionalTicks)
  OutputDebug gp1:%gp1%  gp2:%gp2%
  If(Floor(FractionalTicks) = FractionalTicks)
  { OutputDebug In loop, Ticks: %Ticks%
    GuiControl,, Progress1, %Ticks%    ; This doesn't work here.  Why? Trace shows that it is executed. <<==========================
    ; even if it is changed to ...
    ; GuiControl,, Progress1, 50    ; it still doesn't set the progress bar. <<==========================
  }
  If(Ticks = 0)
  { SetTimer,TimerTick,off
    Tooltip
    ;ListLines
  }
}
Return

MoveGUI() 
{ ; WM_NCLBUTTONDOWN := 0xA1, HT_CAPTION := 0x2
  PostMessage, 0xA1, 0x2,,, A   ; 0xA1 = WM_NCLBUTTONDBLCLK
}

ChangeCursor(hWnd)                                 ; changes the cursor type.  The progress bar still moves if the cursor is not changed.
{ hCursor := DllCall("LoadCursor", "ptr", 0, "int", SizeAll := 32646, "ptr")
  DllCall("SetClassLong" (A_PtrSize=8 ? "ptr":""), "ptr", hWnd, "int", -12, "ptr", hCursor)
}

#x::
exitapp

#p::
Pause
return  

Assist:
msg = 
(
* Help information 
)

msgbox,, HourGlass, %msg%
msg =
ToolTip
Return
I think this is due to interdependence between the two gui's, but I haven't been able to find a tutorial, either here on AHK or on YouTube that explains it. "HellBent" presents a multi-Gui tutorial, but all it shows is how to display them - two Guis before the first return. There's so much more to say on the subject.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Custom progress bar

26 Aug 2020, 08:24

Add a gui name to the progress bar GUI:
Gui, Destroy ; this gui has served its purpose, and has set its variables as desired.
; ================================================================================================

; Gui, pg:new
Then you change the progress value like this:
GuiControl, pg:, Progress1, %Ticks%



Or use hwnd instead of v name
Gui, Add, Progress, +HWNDhPG cSilver background%BarColour% vProgress1 w%ProgressWidth% h%ProgressHeight% Disabled, 0
and then:
GuiControl,, %hPG%, %Ticks%
colmik
Posts: 83
Joined: 11 Mar 2014, 18:21

Re: Custom progress bar

26 Aug 2020, 14:46

Thanks yet again, tmplinshi. [ Irrelevant stuff edited out ]
I would never have got through this without your help.

Is there any instruction anywhere that I could find an in-depth guide on how to handle multiple GUIs?
In fact, if there were any detailed instruction books, I would quite happily spend some money on them.
How did you learn it? Is there a collection of docs somewhere that I don't know about, or did you learn it all from other people?

Much appreciation for your time.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Custom progress bar

28 Aug 2020, 10:04

You're welcome, colmik.

If I encounter any ahk problem, the first thing I usually do is to Google this fourm, it can solve the problem very quickly.

For example on this question you have, I would search site:autohotkey.com guicontrol multiple gui, as you can see, the first result is exactly what you're looking for. (BTW: I've assigned a search keyword "ahk" in Chrome, so I can just typing ahk guicontrol multiple gui from the address bar. gif demo).

Some docs you can read:
colmik
Posts: 83
Joined: 11 Mar 2014, 18:21

Re: Custom progress bar

28 Aug 2020, 18:47

Yes, you're right. It is there. I had actually tried googling for information, but if I found that page, I missed the info. That happens to me a lot.
Now that it's pointed out, however, I find that it is, in fact, in the Help file - but I can only find that one instance of it - buried at the bottom of all the other parameters for GuiControl, under Remarks. I knew about "Gui, G1:Show", etc, but in that case, the colon seems to connect G1 to the Show command, so that Show will be associated with the right Gui - but to have the colon in an argument where it doesn't seem to be associating two entities, seems all wrong to me - like using an adjective with no noun for it to qualify. Anyhow, that's how it is. I know now.
My script is almost finished now, and presents the timer in one of 5 colours, fat, medium or thin, horizontal or vertical, and it will run for any amount of time, will stay hidden till 50%, 70%, 80%, 90% of time, or will be always visible; and it gives audio warnings at any or all of 50% of time elapsed, 70%, 80%, 90% and at the end. I'm still playing with how to save the info for each colour, so that next time that colour is chosen, it will automatically populate the Setup Gui the same as last time it was used - but that's a different adventure. At least, I don't think there are any fancy Windows constructs to handle - just plain programming - though I'm having a bit of trouble with the flow. I'll get there. But without you, I wouldn't have.
colmik
Posts: 83
Joined: 11 Mar 2014, 18:21

Re: Custom progress bar  Topic is solved

30 Aug 2020, 14:54

At long last ... my script is written! Finished!! Completed!!! Wooo-Hoooo!
Look for it in the Scripts folder. It's called HourGlass.

My thanks to those who helped me - to Boiler for pointing out a couple of logicalities, and most especially Tmplinshi. Without them, it would still have been a dream - degenerating into a nightmare. It did for a while anyway.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Lpanatt, macromint, peter_ahk, Spawnova and 271 guests