If yes: I thought that was done automatically at the end of the sub
No, it isn't. If the scope of the Graphics instance is the Sub then that is what you must do. Dispose is not called automatically, you either have to call Dispose or use a Using block (some sort of Try-Catch-Dispose pattern).
In your Code Project code you are assigning new Graphics instance to a class field (through property setter), you can't do that without disposing the previous instance first. You do this in constructor, in OnHandleCreated method and in SizeChanged event handler. Only with the OnHandleCreated/OnHandleDestroyed pair (that you copied from the code I posted) is the current Graphics instance disposed correctly, which is of course not valid any longer when you introduce new Graphics instances from other code paths.
Your Font property does not have the same problem, here you pass the new Font object to the base class (Control class) Font property setter, which is disposing the previous instance for you before replacing the new value.
Each time your ShowPercentage method is called (many times!) you are creating one StringFormat object and two Region objects without disposing them.
All these objects are left in memory until GC collects them, GC will only call Finalize (if Dispose didn't suppress this) and free the memory, so if the object has locked unmanaged resources these will not be unlocked.
As a general rule always check if an object you are creating has a Dispose method, know the scope of the object, call the Dispose method when you are done with the object.