 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Lexikos
Joined: 17 Oct 2006 Posts: 7299 Location: Australia
|
Posted: Wed Nov 28, 2007 9:26 pm Post subject: |
|
|
| majkinetor wrote: | | Use #NoTrayIcon as the first line in your script. | Then I'd have to change NIM_MODIFY to NIM_ADD and probably add a couple other fields...
| Quote: | | Yes nice work lex. How have you created a header for the icon? and couldnt gdi+ be used for the transparency part? | No header. I create a 32-bit bitmap, draw onto it, then create an icon from the bitmap. GDI+ could be used, yes, but that's IMO not as easy to use. Manually setting the pixels works well and doesn't add a dependency on GDI+.
It occurred to me after I finished that I'd already written some code for dynamic icon generation. It hadn't occurred to me since I used the icons in a ListView instead of the tray... |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4511 Location: Belgrade
|
Posted: Wed Nov 28, 2007 10:05 pm Post subject: |
|
|
| Quote: | | Then I'd have to change NIM_MODIFY to NIM_ADD and probably add a couple other fields... |
It will solve the problem, right ?  _________________
 |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4511 Location: Belgrade
|
Posted: Thu Nov 29, 2007 8:45 am Post subject: |
|
|
I was playing with lexikos code and its really blazingly fast, like lex said.
My TaskInfo keeps long avarage CPU at 0 with loop that has 25ms sleep in it (you don't need faster then that). So, this is exactly the speed we want.
Tic, you should use this method as basis for your final code. First of all, it totaly avoids machine code; not that i have something totaly against it, but going that deep generaly defits the reason we are here and I think about it only when there are not other options available in AHK. It will also make script updatable by only few people.
I also want to ask you to add additional parameter to the function, optional flag. When set to true, return icon handle, when set to false (default) do the same as now (save icon to hd).
| Quote: | | I would also really like to know which signs people think would be good as prefixs! |
I have better proposal, IMO:
| Code: | > overwrite right
< overwrite left
+ add right, shift contest left
- add left, shift contest right |
Note that special chars for deleting are not necessary as you can get it with <0 and >0. Also, using single char will make your check very easy by using (*&input = asc) syntax.
To get the curve, we can first intialise icon with 32 zeros then use +NextVal to draw afterwards. _________________
 |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 7299 Location: Australia
|
Posted: Thu Nov 29, 2007 11:29 am Post subject: |
|
|
| majkinetor wrote: | It will solve the problem, right ?  | Yes, and I would do it if I were intending to actually use the script.
| majkinetor wrote: | | My TaskInfo keeps long avarage CPU at 0 with loop that has 25ms sleep in it | I tried it with a Sleep of 1ms, and CPU stays mostly at 0% (instead of ~30%). It isn't even perceptibly slower! |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4511 Location: Belgrade
|
Posted: Thu Nov 29, 2007 11:39 am Post subject: |
|
|
| Quote: | | I tried it with a Sleep of 1ms, and CPU stays mostly at 0% |
Yes, the same behavior here.
I wonder if such speed can be acomplished with same algorythm in AutoIt or VBscript. _________________
 |
|
| Back to top |
|
 |
tic
Joined: 22 Apr 2007 Posts: 1786
|
Posted: Thu Nov 29, 2007 4:55 pm Post subject: |
|
|
I have posted the updated code in the 1st post, and modifiers are <,>,-,+
Also you shouldnt really need a sleep with this function now when looping it. I could get the speed down to a similar speed with the Shell notify, but I would have to remove all the features. It is comparitively fast now.
Remember when using - and + that they can only be used a maximum of 31 times in a row, as only 32 bars are allowed. To make the pixel 16 wide, only specify 16 points.
You may see in the example I am having some problems with Guicontrolling pictures. They flicker too much. Is there any way round this? |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Thu Nov 29, 2007 5:22 pm Post subject: |
|
|
| majkinetor wrote: | | ...avoids machine code; not that i have something totally against it, but going that deep generally defeats the reason we are here and I think about it only when there are not other options available in AHK. It will also make script updatable by only few people. | It is like a built in language feature: a simple task is made a standalone tool, short, lightning fast and only include it, when needed. You should never need to update a machine code function. Convert binary to hex or back is not what you modify, but use, like a standard function. The Windows libraries are much riskier: MS changes functions, they are different in different Windows versions. Your code works with the machine code function everywhere (assuming standard X86 instructions), but it may not work in certain Windows versions (95,98,ME) or setups (older .net libraries). In general, short machine code functions are safer, but of course, less powerful than Windows libraries. |
|
| Back to top |
|
 |
tic
Joined: 22 Apr 2007 Posts: 1786
|
Posted: Thu Nov 29, 2007 5:47 pm Post subject: |
|
|
I agree Laszlo and think that if people try out the bin2hex machine code included, then it aptly shows the advantage of using machine code. it shouldnt ever need to be updated and is very fast. its only used for writing the ico, so shouldnt need to be changed.
I would really love to know a way to change a pciture without it flickering as some really cool controls could be made with these icos. |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 7299 Location: Australia
|
Posted: Thu Nov 29, 2007 7:50 pm Post subject: |
|
|
| tic wrote: | | I would really love to know a way to change a pciture without it flickering as some really cool controls could be made with these icos. | Flicker can often be removed by sub-classing the control and blocking WM_ERASEBKGND messages.
| majkinetor wrote: | | I wonder if such speed can be acomplished with same algorythm in AutoIt or VBscript. | I wonder if VBscript is capable of generating icons at all.  |
|
| Back to top |
|
 |
tic
Joined: 22 Apr 2007 Posts: 1786
|
Posted: Thu Nov 29, 2007 8:02 pm Post subject: |
|
|
| Quote: | | Flicker can often be removed by sub-classing the control and blocking WM_ERASEBKGND messages. |
Huh? How do you do that?
http://www.catch22.net/tuts/flicker.asp
dont know what to do
Edit: Being hasty on the "i dont understand front"
| Code: | #Persistent
SetWorkingDir %A_ScriptDir% ; Ensure working directory is used so that icon location is know
#Include tic-MakeICOBars-1.10.ahk
OnMessage(0x200, "WM_MOUSEMOVE")
OnMessage(0x0014, "WM_ERASEBKGND")
SoundGet, Volume
MakeICOBars(Volume, "ff0000", "Vol.ico")
Gui, 1: +LastFound
Gui1 := WinExist()
Gui, 1: Add, Picture, x10 y10 w256 h256 vVolControl, Vol.ico
Gui, 1: Show, AutoSize, Volume Control
ControlGetPos, CX, CY, CW, CH, Static1
Return
WM_MOUSEMOVE()
{
Global
MouseGetPos, HX, HY, HWin, HControl
If HControl = Static1
{
Loop
{
Sleep, 25
GetKeyState, LButtonState, LButton
If LButtonState = U
Return
MouseGetPos, HX, HY, HWin, HControl
If ((Round(100*((CH-(HY-CY))/ CH)) > StorePerc+5) || (Round(100*((CH-(HY-CY))/ CH)) < StorePerc-5)) && (HY < CH+CY) && (HY > CY)
{
GuiControl, Hide, VolControl
MakeICOBars(Round(100*((CH-(HY-CY))/ CH)), "ff0000", "Vol.ico")
GuiControl,, VolControl, Vol.ico
GuiControl, Show, VolControl
StorePerc := Round(100*((CH-(HY-CY))/ CH))
SoundSet, % Round(100*((CH-(HY-CY))/ CH))
}
}
}
Return
}
WM_ERASEBKGND()
{
Return, 1
}
Esc::ExitApp |
Much better but still slightly flickery. Any more ideas how to cut the flicker?
Some very nice new controls could be made with this |
|
| Back to top |
|
 |
Andreone
Joined: 20 Jul 2007 Posts: 257 Location: Paris, France
|
Posted: Thu Nov 29, 2007 8:18 pm Post subject: |
|
|
| tic wrote: | Huh? How do you do that?  | Majekinor has written some time ago an example of subclassing here AbstractCombo
The concept is to change the default callback (function pointer) of a window by yours, thus you can filter the messages it receives and finally change its behavior. |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 7299 Location: Australia
|
Posted: Thu Nov 29, 2007 8:51 pm Post subject: |
|
|
| tic wrote: | | the machine code is creating 32pixel icos not 16 (so they can be added as pictures as well) |
Btw, I edited my code to show a) it's easy to change the icon size, and b) it's easy to add it to a GUI. If you're using it on a GUI, you'd probably want to either draw directly onto the GUI or use the generated bitmap without generating an icon (especially since icon sizes may be restricted.) For simplicity, my example uses the icon. A lot of speed is lost (with bigger images) in the loop that calculates alpha data. GDI+ would be faster, as would AlphaBlend (which would require you to create a bitmap for the background, but would not require GDI+.) Alternatively, you could replace the loop with a machine code function.
I suppose another advantage of using GDI or GDI+ is that you could draw images, not just bars...
| Quote: | | How do you do that? |
See SetWindowLong.
| Quote: | | Calling SetWindowLong with the GWL_WNDPROC index creates a subclass of the window class used to create the window. An application can subclass a system class, but should not subclass a window class created by another process. The SetWindowLong function creates the window subclass by changing the window procedure associated with a particular window class, causing the system to call the new window procedure instead of the previous one. An application must pass any messages not processed by the new window procedure to the previous window procedure by calling CallWindowProc. This allows the application to create a chain of window procedures. |
|
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4511 Location: Belgrade
|
Posted: Thu Nov 29, 2007 9:01 pm Post subject: |
|
|
| Code: | Gui, 1: Add, Picture, x10 y10 w256 h256 vVolControl HWNDhCtrl, Vol.ico
WindowProcNew := RegisterCallback("WindowProc", "F")
WindowProcOld := DllCall("SetWindowLong", "UInt", hCtrl, "Int", -4, "Int", WindowProcNew, "UInt")
Return
WindowProc(hwnd, uMsg, wParam, lParam){
global WindowProcOld
if (uMsg = 0x14)
return 0
res := DllCall("CallWindowProcA", "UInt", WindowProcOld, "UInt", hwnd, "UInt", uMsg, "UInt", wParam, "UInt", lParam)
return res
} |
This, unfortunately doesn't solve the problem. Flickering can be solved by directly drawin icon on the DC. For that, you need to return us handle of the icon, not the file. I suggest your function to return hIcon if user passes empty string for icon name, or 0 if not succeiful.
Speaking about your "Volume Control" example, you can use Tray module to make changing the volume possible directly from tray. It can watch mouse moves, so you can update the icon in tray the same way you do it in GUI. You can even make horizontal, larger volume line, by monitoring mouse moves over two or more icons
BTW, CPU monitor example looks very nice. _________________
 |
|
| Back to top |
|
 |
tic
Joined: 22 Apr 2007 Posts: 1786
|
Posted: Thu Nov 29, 2007 11:59 pm Post subject: |
|
|
Ive fixed some very minor errors I found, and improved the examples so they flicker less (not uploaded yet), but as you want it so much what do you think would be the best way to retrive the hIcon rather than writing to file? Ill add it in if I can get a nice way of doing it, and I think the syntax should be that if you specify hIcon and then the name of the handle, then it will put hIcon into the handle, as i find having those errorlevels very useful.
Example:
| Code: | | MakeICOBars("25|50", "ff0000|0000ff", "hIcon Handle") |
I hope you like the neater version of my code and that my commenting is adequate.
Also I think the cpu shifting example looks better if set to 150 timer rather than 250 |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 7299 Location: Australia
|
Posted: Fri Nov 30, 2007 2:52 am Post subject: |
|
|
It seems most of the flickering is actually caused by GuiControl invalidating the GUI itself. Try using STM_SETICON (0x170) or STM_SETIMAGE (0x172) to set the icon/bitmap instead. You'll probably find that it flickers much less, but still occasionally flickers. LoadImage() can be used to get a HICON from file.
| Quote: | | improved the examples so they flicker less | I'm curious... how?
Sometimes the only way to remove flicker entirely is to do all the drawing yourself (i.e. handle WM_PAINT.) For some controls you can cheat by printing the control into a buffer (an in-memory bitmap) using PrintWindow or WM_PRINT, then painting the buffer onto the window.
Edit: The remaining flicker happens because the picture control paints the background each time it paints the icon. Since it does both operations directly on the window, occasionally the window updates after the background is drawn, but before the icon is finished. The solution is to override WM_PAINT.
The following example should be entirely flicker-free:
| Code: | Gui, Add, Picture, vIcon hwndhPic w256 h256 icon4, %A_AhkPath%
WindowProcNew := RegisterCallback("WindowProc")
WindowProcOld := DllCall("SetWindowLong","uint",hPic,"int",-4,"int",WindowProcNew,"uint")
Gui, Show
SetTimer, switch, 100
Return
switch:
; Load an icon from the current executable.
hicon := DllCall("LoadImage","uint",DllCall("GetModuleHandle","uint",0)
,"uint",(s:=!s) ? 208:207,"uint",1,"int",256,"int",256,"uint",0)
if !hicon
return
; Set the icon.
SendMessage, 0x170, hicon,,, ahk_id %hPic%
; Destroy the previous icon.
if ErrorLevel
DllCall("DestroyIcon","uint",ErrorLevel)
return
GuiClose:
ExitApp
WindowProc(hwnd, uMsg, wParam, lParam)
{
global WindowProcOld
Critical 500 ; Must ensure AutoHotkey doesn't check for messages.
if (uMsg = 0x14)
return 1
if (uMsg = 0xF)
{
WinGetPos,,, w, h, ahk_id %hwnd%
VarSetCapacity(ps,64,0)
DllCall("BeginPaint","uint",hwnd,"uint",&ps)
hdc := NumGet(ps,0)
if hicon := CallWindowProc(WindowProcOld, hwnd, 0x171,0,0) ; STM_GETICON
{
; Get a brush to be used as the background.
hbr := DllCall("GetSysColorBrush","int",15)
; DrawIconEx draws the background and icon into a temporary buffer,
; then draws the buffer onto the window. (It draws directly onto the
; window if hbr is not a valid brush handle.)
DllCall("DrawIconEx","uint",hdc,"int",0,"int",0,"uint",hicon
,"int",w,"int",h,"uint",0,"uint",hbr,"uint",0x3)
}
DllCall("EndPaint","uint",hwnd,"uint",&ps)
return 0
}
res := CallWindowProc(WindowProcOld, hwnd, uMsg, wParam, lParam)
return res
}
CallWindowProc(wndProc, hwnd, uMsg, wParam, lParam) {
return DllCall("CallWindowProc","uint",wndProc,"uint",hwnd,"uint",uMsg,"uint",wParam,"uint",lParam)
} | If you comment out these two lines: | Code: | WindowProcNew := RegisterCallback("WindowProc")
WindowProcOld := DllCall("SetWindowLong","uint",hPic,"int",-4,"int",WindowProcNew,"uint") | ...it should flicker less than it would with GuiControl, but still occasionally "blink."
A typical control paints everything in WM_PAINT, but if you find it easier to pre-generate the icon and paint only that from WM_PAINT, you may as well. |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|