Page 1 of 1

Refreshing ListView breaks scrolling

Posted: 06 Apr 2017, 21:27
by AlleyArtwork
I created a proof of concept gui for the intended use of our HelpDesk to manage and communicate amongst themselves priority/severity incidents.
Eventually I want this to feed into another app (as read only) that our operations uses so they can see any priority/severity tickets the helpdesk is coordinating.

The first load works fine. The listview is scrollable.
After the listview refreshes (10 seconds to start) 2 odd things happen that i can't figure out why:
* The Gui size gets slightly larger, just a little bit, one time, both in width and height
* The ListView is no longer scrollable

Any idea why?

below is the Proof of concept.
Warning: Running this script will create a TEMP folder on your C drive and create a TEST.CSV with some generic data for use in the test in that directory
(only if you choose Yes at the msgbox prompt).

Code: Select all

#SingleInstance force
refreshtime = %A_MM%/%A_DD%/%A_YYYY% at %A_Hour%:%A_Min%:%A_Sec%
Filecsv = C:\Temp\test.csv
Filetext = C:\Temp\test.txt

IfNotExist, C:\Temp\test.csv ; Check for presence of file. Warn & exit if non existent or create a test file
{
	MsgBox, 4, ,Unable to locate %Filecsv%`nPlease check for network connection or create the file in: %filecsv%.`n`nWOULD YOU LIKE TO CREATE A TEST.CSV in C:\Temp\?
		IfMsgBox, yes
			{
			IfNotExist C:\Temp\
				FileCreateDir, C:\Temp\
			loop, 20
				{
				FileAppend, 1010%a_index%`,IT is investigating`,Something was broken`n, %filecsv%
				}
			}
		else,
			return
}

loop
{

refreshtime = %A_MM%/%A_DD%/%A_YYYY% at %A_Hour%:%A_Min%:%A_Sec%
gosub, Delete_LV
gosub, datagrab
gosub, create_LV

WinGetPos, X, Y, W, H, Sev Status Tracker
Gui, add, text, cred, Last update was %refreshtime%
if x =
	{
	Gui,  Show, NoActivate h250 w600 x300 y300, Sev Status Tracker
	Gui, +resize
	}
else,
	{
	Gui,  Show, NoActivate h250 w600 x%x% y%y%, Sev Status Tracker
	Gui, +resize
	}
sleep, 10000
}

Delete_LV:
gui, submit, nohide
LV_Delete()
return

datagrab:
filedelete, %Filetext% ; Delete Text file
Fileread, sevtext, %Filecsv% ; read the contents of the CSV
FileAppend, %sevtext%, %Filetext% ; Recreate Text file with new data from CSV 
return

create_LV:
Gui, Add, ListView,grid x8 y8 r10 w575 +hscroll, Row|P-Ticket#|Status|Description 
LV_ModifyCol(1,auto)
LV_ModifyCol(2,80)
LV_ModifyCol(3,100)
LV_ModifyCol(4,200)

loop, read, %Filetext%
{
	Loop, parse, A_loopreadline, `, ; Loop each line of file and parse each line by comma
		{
		p%a_index% = %a_loopField%
		}
	if p4 != Arch!ve ; Resolved escalations:  Skip over Priorities marked as "Arch!ve" in the 4th column when the issue is resolved.
		{
		LV_Add("",a_index,p1,p2,p3)	
		}
}
Return

GUIClose:
GUIEscape:
ExitApp
and a bonus question if anyone knows.. is there a way to omit the first column which indicates the line# of the file being read? it's actually been useful for testing, but I don't think it needs to be in the final version of what I want (like reading row 500 after a year or two of tickets being escalated etc.)

Re: Refreshing ListView breaks scrolling

Posted: 07 Apr 2017, 01:08
by just me
You're not refreshing the ListView. You're creating additional ListView and Text controls each time the Gui is updated.

I suggest to create the whole Gui (including all controls) only once when the script is started. After that, only refresh the controls:
  • ListView:

    Code: Select all

    LV_Delete()
    LV_Add()
    ...
  • Text:

    Code: Select all

    GuiControl, , ControlID, New text.
Alternatively, destroy your Gui and recreate it.

Re: Refreshing ListView breaks scrolling

Posted: 07 Apr 2017, 22:06
by AlleyArtwork
Thanks Just Me!
I'm definitely doing it wrong. I can get it to work with a button, using LV_Delete() and LV_Add() in the loop that reads the file, but I can't seem to put the function of what the button does into an automation/loop. Below I've done what you suggested in part, by creating the whole gui first, though it's the controls for the listview i'm still struggling with.

I'm assuming you add the GuiControl inside of a loop instead, but i'm not sure how to get it to write to the complete looped contents of the LV_Add() to the listview properly, since the loop is adding it 1 line at a time as it reads through the CSV file.
At one point, I sort of had the automatic refresh working but it would only add in 4 lines of the file at a time (not sure why 4 lines at a time instead of only 1. well, obviously bad scripting is why)

Updated: Here's the clickable working version with the button for refreshing, but the end goal is to have what the "datagrab" (refresh button) subroutine is doing when clicked, to instead automatically run every xSeconds so that when the CSV file is altered and saved, the listview automatically shows the changes.

Code: Select all

#SingleInstance force

Filecsv = C:\Temp\test.csv
Filetext = C:\Temp\test.txt

IfNotExist, C:\Temp\test.csv ; Check for presence of file. Warn & exit if non existent or create a test file
{
	MsgBox, 4, ,Unable to locate %Filecsv%`nPlease check for network connection or create the file in: %filecsv%.`n`nWOULD YOU LIKE TO CREATE A TEST.CSV in C:\Temp\?
		IfMsgBox, yes
			{
			IfNotExist C:\Temp\
				FileCreateDir, C:\Temp\
			loop, 15
				{
				FileAppend, 1010%a_index%`,IT is investigating`,Something was broken`n, %filecsv%
				}
			}
		else,
			return
}

Gui, Add, ListView,grid x8 y8 r10 w575 +hscroll , Row|Ticket#|Status|Description
LV_ModifyCol(1,0) ; Hide Row# column
LV_ModifyCol(2,80)
LV_ModifyCol(3,100)
LV_ModifyCol(4,auto)

Gui, Add, Button, gdatagrab vdatagrab default, Refresh List

Gui, 1: Show, h250 w600 x300 y300, Sev Status Tracker
Gui, +resize

gosub, datagrab

Return

GuiEscape:
GuiClose:
ExitApp


datagrab:
LV_Delete()
filedelete, %Filetext% ; Delete Text file
Fileread, sevtext, %Filecsv% ; read the contents of the CSV
FileAppend, %sevtext%, %Filetext% ; Recreate Text file with new data from CSV
loop, read, %Filetext%
{
	Loop, parse, A_loopreadline, `, ; Loop each line of file and parse each line by comma
		{
		p%a_index% = %a_loopField%
		}
	if p4 != Arch!ve ; Skip over Sevs marked as Archived
		{
		LV_Add("",a_index,p1,p2,p3)	
		}
}

return

Re: Refreshing ListView breaks scrolling  Topic is solved

Posted: 08 Apr 2017, 02:04
by just me
Hi Alley,

that's what I would try to do in this case (see comments):

Code: Select all

#SingleInstance force

Filecsv = C:\Temp\test.csv
; Filetext = C:\Temp\test.txt ; <<<<< commented out - I believe you don't need this file any more
TimerPeriod := 10000 ; <<<<< added: set the timer period
PreviousSize := 0 ; <<<<< added: initialize the previous file size
refreshtime = 00/00/0000 at 00:00:00 ; <<<<< added: initialize the refresh time

IfNotExist, C:\Temp\test.csv ; Check for presence of file. Warn & exit if non existent or create a test file
{
   MsgBox, 4, ,Unable to locate %Filecsv%`nPlease check for network connection or create the file in: %filecsv%.`n`nWOULD YOU LIKE TO CREATE A TEST.CSV in C:\Temp\?
      IfMsgBox, yes
      {
         IfNotExist C:\Temp\
            FileCreateDir, C:\Temp\
         loop, 15
         {
            FileAppend, 1010%a_index%`,IT is investigating`,Something was broken`n, %filecsv%
         }
         DeleteFile := True ; <<<<< added: delete the test file on exit
      }
      else,
         return
}

Gui, Add, ListView, grid x8 y8 r10 w575 +hscroll, Row|Ticket#|Status|Description
LV_ModifyCol(1,0) ; Hide Row# column
LV_ModifyCol(2,80)
LV_ModifyCol(3,100)
LV_ModifyCol(4,auto)

; Gui, Add, Button, gdatagrab vdatagrab default, Refresh List ; <<<<< commented out
Gui, add, text, cred vLastRefresh, Last update was %refreshtime% ; <<<<< added

Gui, 1: Show, h250 w600 x300 y300, Sev Status Tracker
Gui, +resize

gosub, datagrab
SetTimer, datagrab, %TimerPeriod% ; <<<<< added: set the timer

Return

GuiEscape:
GuiClose:
If (DeleteFile) ; <<<<< added: delete the test file on exit
   FileDelete, %Filecsv%
ExitApp


datagrab:
sevtext := "" ; <<<<< added: initialize the variable for read text
If (File := FileOpen(Filecsv, "r")) ; <<<<< added: use the file object
{
   If (File.Length <> PreviousSize) ; <<<<< added: check whether the size has changed
   {
      ; LV_Delete() ; <<<<< commented out
      ; filedelete, %Filetext% ; Delete Text file ; <<<<< commented out
      If (PreviousSize <> 0) ; <<<<< added: set the file pointer only on second+ iteration
         File.Pos := PreviousSize ; <<<<< added: set the file pointer to the previous size -> read only the appended lines
      sevtext := File.Read() ; read the contents of the CSV ; <<<<< changed: use the file object
      ; FileAppend, %sevtext%, %Filetext% ; Recreate Text file with new data from CSV ; <<<<< commented out
      PreviousSize := File.Length ; <<<<< added: store the current size
   }
   File.Close() ; <<<<< added: close the csv file
}
If (sevtext <> "") ; <<<<< added: if some text has been read
{
   loop, parse, sevtext , `n, `r ; <<<<< changed: parse sevtext instead of Loop, Read
   {
      Split := StrSplit(A_LoopField, ",") ; <<<<< changed: use StrSplit() instead of a parsing loop
      If (Split.Length() >= 3) && (Split.4 <> "Arch!ve") ; <<<<< ?: typo?
         LV_Add("", A_Index, Split.1, Split.2, Split.3)
   }
   refreshtime = %A_MM%/%A_DD%/%A_YYYY% at %A_Hour%:%A_Min%:%A_Sec% ; <<<<< added: update the refresh time
   GuiControl, , LastRefresh, %refreshtime% ; <<<<< added: update the Gui
}
return
Edit1: Changed datagrab:.

Edit2: In case I misunderstood your puspose, here's another version of datagrab: always processing the whole file:

Code: Select all

datagrab:
FileRead sevtext, %Filecsv%
If (ErrorLevel) ; FileRead failed
   Return
LV_Delete()
loop, parse, sevtext , `n, `r 
{
   Split := StrSplit(A_LoopField, ",")
   If (Split.Length() >= 3) && (Split.4 <> "Arch!ve") ; <<<<< ?: typo?
      LV_Add("", A_Index, Split.1, Split.2, Split.3)
}
refreshtime = %A_MM%/%A_DD%/%A_YYYY% at %A_Hour%:%A_Min%:%A_Sec% 
GuiControl, , LastRefresh, %refreshtime%
sevtext := ""
return

Re: Refreshing ListView breaks scrolling

Posted: 08 Apr 2017, 08:38
by AlleyArtwork
Thanks again Just Me!
The second option is what I need. I misunderstood you the first time and was trying to add a guicontrol do the ListView itself (unsuccessfully of course).
I'm let me explain a little of the purpose of what I am building into part of a larger toolset.

Basically, there's a helpdesk team that manages communication of outages/severities/priorities (different places call them different things), to the business, mostly affecting our various call centers in different locations.
-- the "Arch!ve" was not a typo, it was a way to tag a particular line as no longer required to display in the listview but allows keeping the data if the helpdesk wanted to keep all data tracked directly in the CSV file. Hind sight this is probably not required.

I already have an app built for our operations that does a bunch of other things; In a new tab on this app I was going to include this data/dashboard.
The Helpdesk can update a master file with their currently running outages, and all of operations can see the status through the dashboard which is running on their desktops.
This will help reduce call and ticket volume since known issues will be instantly communicated with a side benefit of internal awareness to the helpdesk themselves (people come in late/didn't get the memo etc.).

side note:
One of those tabs is a user-customizable hotkeys creation though it's extremely limited. (only 5 customizable hotkeys though limited by size of gui... trying to squeeze in more by adding a scrollable window inside of a tab but it doesn't seem possible. If you were interested in looking at another working example of what that particular section looks like, I posted it here: https://autohotkey.com/boards/viewtopic ... 54#p140154
Maybe i'm trying to do this wrong too.

Either way, thank you so much! this was extremely helpful and I learned a new way to parse something! i'll have to read up on it to understand it better, but that's fine with me!