CYCho Posted February 27 Posted February 27 (edited) This concept was used in my zPlayer to display long file names in a short label control. expandcollapse popup#include <GUIConstants.au3> $guiWidth = 300 $hGUI = GUICreate("Main GUI", $guiWidth, 70) $sString = "This is a long string that scrolls smoothly and infinitely in a short label control." ; Create a child GUI for scrolling label $iMargin = 10 $sGap = " " $iLabelWidth = $guiWidth - $iMargin * 2 $hChildGUI = GUICreate("", $iLabelWidth, 20, 10, 10, $WS_CHILD, -1, $hGUI) GUISetFont(12, 400, 0, "Arial") ; Create a label wide enough to hold a long string without truncation $idLabel = GUICtrlCreateLabel($sString, 0, 0, 2000, 20, BitOR($SS_NOPREFIX, $SS_LEFTNOWORDWRAP)) ; Get the string width $tmpLabel = GUICtrlCreateLabel($sString, 0, 0, -1, 20, BitOR($SS_NOPREFIX, $SS_LEFTNOWORDWRAP)) $iStringWidth = ControlGetPos($hChildGUI, "", $tmpLabel)[2] - 9 ; Label is wider than the string width by 9 pixels GUICtrlDelete($tmpLabel) GUISetState(@SW_SHOW, $hGUI) GUISetState(@SW_SHOW, $hChildGUI) ; Update the label data if the string width is larger than the label width If $iStringWidth > $iLabelWidth Then GUICtrlSetData($idLabel, $sString & $sGap & $sString) $iScrollPos = 0 $iMarquee = 0 $iScrollDelay = 40 AdlibRegister("_Marquee", $iScrollDelay) EndIf Do Until GUIGetMsg() = $GUI_EVENT_CLOSE Func _Marquee() $iMarquee += 1 If $iMarquee < 3000/$iScrollDelay Then Return ; 3 seconds of halt when $sString comes to the initial position $iScrollPos -= 1 If -$iScrollPos = $iStringWidth + StringLen($sGap) * 4 Then ; Initialize the $idLabel's position $iMarquee = 0 $iScrollPos = 0 EndIf GUICtrlSetPos($idLabel, $iScrollPos, 0) EndFunc Edited February 27 by CYCho Gianni and pixelsearch 2 zPlayer - A Small Audio and Video Player
MattyD Posted Tuesday at 01:48 AM Posted Tuesday at 01:48 AM (edited) Nice mate. its possible to reduce the flicker a bit by double buffering. So hope you don't mind - but here's another approach expandcollapse popup#include <GUIConstants.au3> #include <GDIPlus.au3> #include <WinAPI.au3> Global $iGUIWidth = 300 Global $hGUI = GUICreate("Main GUI", $iGUIWidth, 70) Global $sString = "This is a long string that scrolls smoothly and infinitely in a short label control." Global $iLabW = $iGUIWidth - 8, $iLabH = 30 ;The border style is here to mark the label boundry - for demo purposes! Global $hLabel = GUICtrlCreateLabel("", 4, 4, $iGUIWidth - 8, $iLabH, $WS_BORDER) GUISetState() Global $hLabGraphic, $hBuffGraphic, $hBuffBitMap Global $hBrush, $hFormat, $tLayout, $hFamily, $hFont, $iBkColour _GDIPlus_Startup() ;Graphic of the static control - its possible to draw directly to this, but we'll introduce flicker. $hLabGraphic = _GDIPlus_GraphicsCreateFromHWND(GUICtrlGetHandle($hLabel)) ;Create Buffer - Draw to this. Copy to the label once the image is complete. $hBuffBitMap = _GDIPlus_BitmapCreateFromGraphics($iLabW, $iLabH, $hLabGraphic) $hBuffGraphic = _GDIPlus_ImageGetGraphicsContext($hBuffBitMap) ;Create font etc.. $hBrush = _GDIPlus_BrushCreateSolid(0xFFAA0000) ;ARGB $hFormat = _GDIPlus_StringFormatCreate() $hFamily = _GDIPlus_FontFamilyCreate("Arial") $hFont = _GDIPlus_FontCreate($hFamily, 12, 3) ;Size, Italic + Bold $iBkColour = BitOR(0xFF000000, _WinAPI_GetSysColor($COLOR_3DFACE)) ;dialog background colour. ; ----- Find dims of the text. --------- Global $iMargin = 4 $tLayout = _GDIPlus_RectFCreate($iMargin, 0, 1, 1) ;Text rectangle. Margin of 4 from left Local $aStrMeasure[4] ;Expand height until we can fit 2 lines ;Sanity checks are required here! This'll break if there's < 2 printable characters in the string. Do $tLayout.Height += 1 $aStrMeasure = _GDIPlus_GraphicsMeasureString($hLabGraphic, $sString, $hFont, $tLayout, $hFormat) Until $aStrMeasure[2] = 2 $tLayout.Height -= 1 ; Gets us the max height of 1 line. ;Expand width until we can fit the entire string. Do $tLayout.Width += 1 $aStrMeasure = _GDIPlus_GraphicsMeasureString($hLabGraphic, $sString, $hFont, $tLayout, $hFormat) Until $aStrMeasure[1] = StringLen($sString) ;Center vertically in the label $tLayout.Y = Floor(($iLabH - $tLayout.Height)/2) ConsoleWrite(StringFormat("text dims: [%d, %d, %d, %d]\r\n", $tLayout.X, $tLayout.Y, $tLayout.Width, $tLayout.Height)) ;-------------------------------------- ;Initial write to label - cause I'm too lazy to fix scrolling logic! _GDIPlus_GraphicsDrawStringEx($hLabGraphic, $sString, $hFont, $tLayout, $hFormat, $hBrush) Local $hTimer = TimerInit(), $iShift = 3 ; $iShift = Pos shift on each iteration. While 1 If GUIGetMsg() = $GUI_EVENT_CLOSE Then ExitLoop ;Pause at string start. If TimerDiff($hTimer) < 2000 Then ContinueLoop ;wipe buffer _GDIPlus_GraphicsClear($hBuffGraphic, $iBkColour) ;Redraw the string at new position. $tLayout.X -= $iShift If ($tLayout.X + $tLayout.Width) < 0 Then ;If we've fallen off the label.. $tLayout.X = $iMargin ;Start at our initial position $hTimer = TimerInit() EndIf _GDIPlus_GraphicsDrawStringEx($hBuffGraphic, $sString, $hFont, $tLayout, $hFormat, $hBrush) ;Copy the buffer to the label _GDIPlus_GraphicsDrawImageRect($hLabGraphic, $hBuffBitMap, 0, 0, $iLabW, $iLabH) Sleep(40) WEnd ;Cleanup _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hBuffGraphic) _GDIPlus_ImageDispose($hBuffBitMap) _GDIPlus_GraphicsDispose($hLabGraphic) _GDIPlus_Shutdown() GUIDelete($hGUI) Edited yesterday at 09:57 AM by MattyD Minor code touchup Gianni and CYCho 1 1
Nine Posted Tuesday at 01:33 PM Posted Tuesday at 01:33 PM (edited) Here my take on it : #include <GUIConstants.au3> Local $hGUI = GUICreate("Main GUI", 300, 70, -1, -1, -1, $WS_EX_COMPOSITED) Global $sString = "This is a long string that scrolls smoothly and infinitely in a short label control." Global $idLabel = GUICtrlCreateLabel("", 10, 10, 280, 30, $SS_LEFTNOWORDWRAP) GUICtrlSetFont(-1, 11) $sString &= " " ; pad with space GUICtrlSetData($idLabel, $sString) GUISetState() AdlibRegister(Scroll, 150) Do Until GUIGetMsg() = $GUI_EVENT_CLOSE Func Scroll() Local Static $iPos = 0, $sScroll = $sString, $iLen = StringLen($sString) $iPos = Mod($iPos, $iLen) + 1 $sScroll = StringTrimLeft($sScroll, 1) & StringMid($sString, Mod($iPos - 1, $iLen) + 1, 1) GUICtrlSetData($idLabel, $sScroll) EndFunc No flicker on my side... Edited Tuesday at 01:40 PM by Nine CYCho 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Multi-Threading Made Easy
CYCho Posted Tuesday at 02:48 PM Author Posted Tuesday at 02:48 PM 42 minutes ago, Nine said: Here my take on it : Thanks for your interest in this. Yours is similar to one of my previous versions in that it scrolls one character at a time. Even though I set the Adlib time at 500 ms, it seemed a bit stuttering. Then in the next version, I made the control itself to move one pixel at a time. It looked OK, but the scroll spanned the entire width of the GUI. It looked like the string spilling over the GUI. The current version, shown in the above post, has a child GUI, the whole of which is a laabel control. This control scrolls the whole width of its parent GUI, but that GUI is a child of the main GUI and the scroll does not reach the perimeter of the main GUI. So far I am pretty much satisfied with it. zPlayer - A Small Audio and Video Player
Nine Posted Tuesday at 04:28 PM Posted Tuesday at 04:28 PM (edited) Understand what you mean now. Here a new version with no flickers. It uses a similar approach of yours. #include <GUIConstants.au3> Local $hGUI = GUICreate("Main GUI", 300, 70) Local $sString = "This is a long string that scrolls smoothly and infinitely without flickers..." GUISetState() Global $iLen = StringLen($sString) * 6.5 ; <<<<< adjust as needed or use M23 UDF StringSize for more precision Local $hGUI2 = GUICreate("", 280, 30, 10, 10, $WS_CHILD, $WS_EX_COMPOSITED, $hGUI) GUISetFont(11) Global $idLabel1 = GUICtrlCreateLabel($sString, 0, 0, $iLen, 30, $SS_LEFTNOWORDWRAP) Global $idLabel2 = GUICtrlCreateLabel($sString, $iLen, 0, $iLen, 30, $SS_LEFTNOWORDWRAP) GUISetState() AdlibRegister(Scroll, 25) Do Until GUIGetMsg() = $GUI_EVENT_CLOSE Func Scroll() Local Static $iPos = 0 $iPos -= 1 If -$iPos >= $iLen Then $iPos = 0 GUICtrlSetPos($idLabel1, $iPos) GUICtrlSetPos($idLabel2, $iLen + $iPos) EndFunc Edited Tuesday at 04:33 PM by Nine CYCho and Gianni 2 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Multi-Threading Made Easy
CYCho Posted Tuesday at 09:35 PM Author Posted Tuesday at 09:35 PM (edited) 5 hours ago, Nine said: Local $hGUI2 = GUICreate("", 280, 30, 10, 10, $WS_CHILD, $WS_EX_COMPOSITED, $hGUI) $WS_EX_COMPOSITED seems to help reduce flickers when the adlib time is set to 25. When the time is set to 40, it doesn't seem to help. Maybe it's due to my bad eye sights. Thanks for the hint anyway. As to the string size, creating a temporary label with width set to -1 seems to give precise width. I tried it with diferrent languages and different font weights, and so far, I am happy with the results. According to my observations, the label width is always 9 pixels longer than the actual string size. Edited Tuesday at 10:28 PM by CYCho Nine 1 zPlayer - A Small Audio and Video Player
Gianni Posted yesterday at 02:04 AM Posted yesterday at 02:04 AM If you want the text scrolling to continue even when you drag the GUI or even when an MsgBox() is in action, you can use _WinAPI_SetTimer instead of AdlibRegister, as in this slightly modified version of your script. ... But if you don't care, then forget it ... expandcollapse popup#include <GUIConstants.au3> #include <WinAPISysWin.au3> $guiWidth = 300 $hGUI = GUICreate("Main GUI", $guiWidth, 70) $sString = "This is a long string that scrolls smoothly and infinitely in a short label control." ; Create a child GUI for scrolling label $iMargin = 10 $sGap = " " $iLabelWidth = $guiWidth - $iMargin * 2 $hChildGUI = GUICreate("", $iLabelWidth, 20, 10, 10, $WS_CHILD, -1, $hGUI) GUISetFont(12, 400, 0, "Arial") ; Create a label wide enough to hold a long string without truncation $idLabel = GUICtrlCreateLabel($sString, 0, 0, 2000, 20, BitOR($SS_NOPREFIX, $SS_LEFTNOWORDWRAP)) ; Get the string width $tmpLabel = GUICtrlCreateLabel($sString, 0, 0, -1, 20, BitOR($SS_NOPREFIX, $SS_LEFTNOWORDWRAP)) $iStringWidth = ControlGetPos($hChildGUI, "", $tmpLabel)[2] - 9 ; Label is wider than the string width by 9 pixels GUICtrlDelete($tmpLabel) GUISetState(@SW_SHOW, $hGUI) GUISetState(@SW_SHOW, $hChildGUI) ; Update the label data if the string width is larger than the label width If $iStringWidth > $iLabelWidth Then GUICtrlSetData($idLabel, $sString & $sGap & $sString) $iScrollPos = 0 $iMarquee = 0 $iScrollDelay = 40 ; AdlibRegister("_Marquee", $iScrollDelay) ; -- setup timer-- Local $hTimerProc = DllCallbackRegister('_Marquee', 'none', 'hwnd;uint;uint_ptr;dword') Local $iTimerID = _WinAPI_SetTimer(0, 0, $iScrollDelay, DllCallbackGetPtr($hTimerProc)) ; ---------------- EndIf MsgBox(64, "Info", "text scrolls") Do Until GUIGetMsg() = $GUI_EVENT_CLOSE ; -- clean timer-- _WinAPI_KillTimer(0, $iTimerID) DllCallbackFree($hTimerProc) ; ---------------- Func _Marquee($hWnd, $iMsg, $iTimerID, $iTime) #forceref $hWnd, $iMsg, $iTimerID, $iTime $iMarquee += 1 If $iMarquee < 3000 / $iScrollDelay Then Return ; 3 seconds of halt when $sString comes to the initial position $iScrollPos -= 1 If - $iScrollPos = $iStringWidth + StringLen($sGap) * 4 Then ; Initialize the $idLabel's position $iMarquee = 0 $iScrollPos = 0 EndIf GUICtrlSetPos($idLabel, $iScrollPos, 0) EndFunc ;==>_Marquee SOLVE-SMART, Werty, pixelsearch and 1 other 3 1 Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....
Nine Posted 22 hours ago Posted 22 hours ago (edited) Good catch @Gianni. I found a somewhat weird issue when testing your code. If you run the script from double clicking it in Explorer, it won't start scrolling unless you click on the window. Do you guys have the same issue ? BTW, it is not related to the SetTimer API. I tested different codes (mine, @CYCho's) and all shows the same weird behavior...Scrolling won't start automatically. edit : in my case, the scripts are freezing after the second GUISetState (the child GUI) Reedit : it seems the script is loosing focus if you are double clicking normally. But when you click fastest you can, it works correctly...Still weird. Edited 22 hours ago by Nine “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Multi-Threading Made Easy
CYCho Posted 21 hours ago Author Posted 21 hours ago (edited) 1 hour ago, Nine said: Do you guys have the same issue ? @Gianni's and my codes work as expected when I double click the code in file Explorer. Please bear in mind that my code waits for 3 seconds before scrolling starts. Edited 21 hours ago by CYCho zPlayer - A Small Audio and Video Player
Dan_555 Posted 21 hours ago Posted 21 hours ago Quote If you run the script from double clicking it in Explorer, it won't start scrolling unless you click on the window. Do you guys have the same issue ? No, i tried to reproduce this by compiling it in 32/64bits, clicking from the explorer, and even using WinActivate to set focus to another app (before the timer is started), but is starts here, always. well, it takes about 2 seconds to start (with and without the message box). Some of my script sourcecode
Nine Posted 21 hours ago Posted 21 hours ago Ok, thanks for testing. There must be something on my side, but I have no idea what it could be. All other methods of starting the code works as expected. Only when I slowly double click that I have an issue. The compiled script reacts the same with the same issue, sigh... “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Multi-Threading Made Easy
Nine Posted 12 hours ago Posted 12 hours ago FYI, I tested on other computers. Older computer reacts correctly as it should be expected. Faster (more recent) computer behave exactly as I am experiencing. So this is not related to my own computer. It seems to be another of those timing issues with AutoIt. Sadly not the first, not the last... For those who face the same problem as I have, here a simple solution : #include <GUIConstants.au3> #include <Constants.au3> Example() Func Example() Local $hGUI = GUICreate("Main GUI", 300, 70) GUISetState() Sleep(100) Local $hGUI2 = GUICreate("", 280, 30, 10, 10, $WS_CHILD, -1, $hGUI) GUISetFont(11) Local $idLabel = GUICtrlCreateLabel("This is a test", 0, 0, 100, 30) GUISetState() MsgBox($MB_OK, "", "Test") Do Until GUIGetMsg() = $GUI_EVENT_CLOSE EndFunc ;==>Example Slow down the creation of child GUI by putting a Sleep in between. It is working on all computers correctly now. CYCho and Gianni 1 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Multi-Threading Made Easy
CYCho Posted 11 hours ago Author Posted 11 hours ago 32 minutes ago, Nine said: Slow down the creation of child GUI by putting a Sleep in between. Thanks for your test. How long should the Sleep be? In my zPlayer, the child is created after creation of all the other controls and there is about a 20ms time difference between the creation of the main GUI and the child. Would I still need to put some Sleep in between? zPlayer - A Small Audio and Video Player
Nine Posted 9 hours ago Posted 9 hours ago I tested different delays, and 100 was working for all computers. CYCho 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Multi-Threading Made Easy
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now