Version 1.9.7 (November 2, 2019)
- Fixed: ListView notifications (Events) failing on 64 bit compiles.
- Fixed: Added back several missing Codetip popup items for the ListView.
https://github.com/PaulSquires/WinFBE/releases
This release fixes the few problems that have been reported related to the new ListView control.
Hi Paul,
ListView Click Event: 1 click any row any column and Click event fires 3 times. Clicking the same row (any col) a second time has no effect.
Quote from: SeaVipe on November 02, 2019, 10:04:05 PM
Hi Paul,
ListView Click Event: 1 click any row any column and Click event fires 3 times. Clicking the same row (any col) a second time has no effect.
Thanks Clive, I am looking into a different method for handling "Click". I believe that now it only fires when the selection changes rather when an item (or subitem) is clicked on. I will add a new event named something like "ItemSelectionChanged" to indicate that the selected row has changed. I also need to implement an event for "ColumnClick".
On my test form, Paul, moving the mouse pointer away from the ListView's "grid" to any other control (or the ListView's header row) and then moving the mouse pointer back to the non-header portion of the ListView, causes the Click event to fire 3 times (as per a mouse click) and displays the correct iTem and SubItems (using HitTest). No other Events are checked in the Visual Designer for the ListView control. Win64 Console (Debug)
Thanks Clive, I have noticed this also. Basically, when you bring back the mouse cursor over the Listview it will "automatically" select the row under the cursor even if you don't click on it. Moving the mouse over other rows does not select any of those rows (as you would expect if a hot tracking extended style such as LVS_EX_TRACKSELECT was present). It only happens if you move the mouse cursor off of the control and then back over the control again. I need to figure out why this happens because it is bothering me greatly :)
listview questions and ramblings.
Will it be able to handle files of say 5 million lines long, and ten columns, possibly sparsely populated? Is the size limit going to be memory or number of lines/whatever.
The example in the winfbe editor help
Row count = frmMain.ListView1.Items.Count
Selected count = frmMain.ListView1.Items.SelectedCount
Current row = frmMain.ListView1.SelectedIndex
dim i as Long
i = frmMain.ListView1.Columns.Add( "Column 1", 100, TextAlignment.Left )
i = frmMain.ListView1.Columns.Add( "Column 2", 100, TextAlignment.Center )
i = frmMain.ListView1.Columns.Add( "Column 3", 100, TextAlignment.Right )
for ii as long = 0 to 99
i = frmMain.ListView1.Items.Add( "Line " & ii )
frmMain.ListView1.Item(i).SubItems.Add( "L" & ii & "Sub1" )
frmMain.ListView1.Item(i).SubItems.Add( "L" & ii & "Sub2" )
next
frmMain.ListView1.Item(0).SubItem(0).ForeColor = colors.Red
frmMain.ListView1.Item(0).SubItem(2).ForeColor = colors.Red
frmMain.ListView1.Item(2).ForeColor = colors.Blue
frmMain.ListView1.Item(2).BackColor = colors.Yellow
frmMain.ListView1.Item(2).SubItem(1).ForeColor = colors.Blue
frmMain.ListView1.SelectedIndex = 0
the first three lines should be comments.
It makes more sense to me, to dispense with variable 'i' long. Somewhat unusual that a variable on the lhs is being changed without said variable being used. It works for me as far as the example shows and a bit more, but possibly it may cause problems later on. Is the intention, that the end user will be able to edit/delete values in listview?
frmMain.ListView1.Columns.Add( "Column 1", 100, TextAlignment.Left )
frmMain.ListView1.Columns.Add( "Column 2", 100, TextAlignment.Center )
frmMain.ListView1.Columns.Add( "Column 3", 100, TextAlignment.Right )
for ii as long = 0 to 90
frmMain.ListView1.Items.Add( "Line " & ii )
frmMain.ListView1.Item(ii).SubItems.Add( "L" & ii & "Sub1" )
frmMain.ListView1.Item(ii).SubItems.Add( "L" & ii & "Sub2" )
next
frmMain.ListView1.Item(0).SubItem(0).ForeColor = colors.Red
frmMain.ListView1.Item(0).SubItem(2).ForeColor = colors.Red
frmMain.ListView1.Item(2).ForeColor = colors.Blue
frmMain.ListView1.Item(2).BackColor = colors.Yellow
frmMain.ListView1.Item(2).SubItem(1).ForeColor = colors.Blue
frmMain.ListView1.SelectedIndex = 0
I have a number of minor questions.
afaik you are defining the number of rows as 100 in the following
frmMain.ListView1.Columns.Add( "Column 1", 100, TextAlignment.Left )
but you can enter any value in the fill loop e.g.
for ii =0 to 1000
it will fill 1000 rows. (I've not tried answering my first question, for ii= 0 to 5000000) There is always a blank row at the end (almost as if being trapped by the basic language not knowing whether the first item is a 1 or a zero - but I guess that tells you you've got to the end. If the text is longer than the width of the column, you put ellipsis at the end, but can the whole text be viewed (scroll bar/multi line)? Will it be possible to alter the colour, or darken the grid lines.
In general, I think the referencing system to a specific location, row, column, is rather convoluted and confusing. There appears to be too many item/subitem/items. Is there an argument/discussion where column could not be used instead of subitem? It may not be so, but if you show a grid to someone, they generally refer to rows and columns, not items and sub items. I think a sub item is thought more in relationship to a branch /leaf on a tree structure or profit/loss accounting, not engineering.
I hope this doesn't come over as being too critical, if I didn't think much of what you were attempting, I wouldn't be here, trying to break things ::)
Best wishes,
Ray
edit to add, I'm guessing it is a memory limit. using above code, ii=0 to 750000 runs OK, but ii=0 to 760000 or above, does not run. I maybe able to squeeze in my 2M lines.
again - the line such as frmMain.ListView1.Columns.Add( "Column 1", 100, TextAlignment.Left ) the 100 is NOT the length of list, but somehow connected to the width of the column, but although the columns seem to be for text, the 100 is not number of characters, maybe pixels or something. A pretty rubbish example, imnsho. comments would be helpful.
Quote from: SeaVipe on November 04, 2019, 01:07:42 PM
...causes the Click event to fire 3 times (as per a mouse click)
Got this one fixed. I was not filtering out the state change to isolate the LVIS_SELECTED state.
Fix will be in the next update.
Also, as you can see, in addition to the CLICK event, I have also added a ITEMSELECTIONCHANGED event.
if lNotification = LVN_ITEMCHANGED then
dim lpStateChange as NMLISTVIEW ptr = cast(NMLISTVIEW ptr, pNMHDR)
IF (lpStateChange->uChanged AND LVIF_STATE) = LVIF_STATE THEN
if (lpStateChange->uNewState AND LVIS_SELECTED) = LVIS_SELECTED then
if pListView->OnItemSelectionChanged Then pListView->OnItemSelectionChanged(*pListView, e)
end if
end if
end if
No use me winging, nobody listens... anyway I thought the proof of the pudding etc. so I started replicating something similar to that which I had written using firefly, last December, and it used the virtual list (or what I used to call a circular buffer) concept to handle large files. As it is, the raw listview will not accept files of that size, but I will look at including the vlist code. The listview looks a bit prettier than my firefly gui of a number of list boxes side by side. Just for proof, I've put a jpeg of part of the screen below. One thing that will be a bit of a gotcha, is that the whole view, or at least a whole row, must be populated at one go, even if by using code similar to frmmain.ListView1.item(j).subitems.add ("") . As always, when reading in large files, it is a toss up between displaying some sort of counter, or saving a bit of time. I think, but have not tested, that even though I read a line at a time and fill a row, the the listview is not displayed until all the file is read. But early days, yet.
Quote from: raymw on November 04, 2019, 03:50:29 PM
Will it be able to handle files of say 5 million lines long, and ten columns, possibly sparsely populated? Is the size limit going to be memory or number of lines/whatever.
Seriously doubt that there would be enough memory to hold that many items. Even Microsoft Excel is limited to 1,048,576 rows per worksheet. If you are trying to display 5 million items in a Listview then you may want to rethink your UI because I can't imagine a user trying to navigate 5 million rows.
Quote
The example in the winfbe editor help ......
Those are fair points. The documentation is pretty sparse right now because I am still flushing out some of the ListView functionality. I will give the documentation a better pass very soon.
Quote
afaik you are defining the number of rows as 100 in the following
frmMain.ListView1.Columns.Add( "Column 1", 100, TextAlignment.Left )
100 refers to the width of the column that you are adding. It is measured in pixels (the value is high dpi aware).
Quote
but you can enter any value in the fill loop e.g.
for ii =0 to 1000
it will fill 1000 rows.
That will create 1001 rows. Also, ListView rows start at number 0. Just about everything in the Windows api and every C based language is zero based. BASIC variants seem to have always allowed 1 based but when you try to use that with Windows api then you have to do the -1 adjustment. You see this a lot when PowerBasic programmers try to use DDT along with Windows api.
Quote
In general, I think the referencing system to a specific location, row, column, is rather convoluted and confusing. There appears to be too many item/subitem/items. Is there an argument/discussion where column could not be used instead of subitem? It may not be so, but if you show a grid to someone, they generally refer to rows and columns, not items and sub items. I think a sub item is thought more in relationship to a branch /leaf on a tree structure or profit/loss accounting, not engineering.
I did it this way because this is the terminology that Microsoft .NET uses.
Quote
I hope this doesn't come over as being too critical, if I didn't think much of what you were attempting, I wouldn't be here, trying to break things
I appreciate every word you've written! Thanks!
It uses Item and Subitem instead of Row and Column because a ListView is not a grid. It only looks like a grid when used in report mode, but if you use icon view or tile view, then row and column would be misleading and inappropriate.
Quote from: Paul Squires on November 04, 2019, 06:36:11 PM
Also, as you can see, in addition to the CLICK event, I have also added a ITEMSELECTIONCHANGED event.
I have also added a COLUMNCLICK event. I have added two properties to the e EVENTARGS that are passed to CLICK, COLUMNCLICK, and ITEMSELECTIONCHANGED. These are ListViewRow and ListViewColumn. This allows you to write code like the following:
''
''
Function frmMain_ListView1_Click( ByRef sender As wfxListView, ByRef e As EventArgs ) As LRESULT
? "ListView CLICK. e.ListViewRow: "; e.ListViewRow
Function = 0
End Function
''
''
Function frmMain_ListView1_ItemSelectionChanged( ByRef sender As wfxListView, ByRef e As EventArgs ) As LRESULT
? "ListView ITEMSELECTIONCHANGED. e.ListViewRow: "; e.ListViewRow
Function = 0
End Function
''
''
Function frmMain_ListView1_ColumnClick( ByRef sender As wfxListView, ByRef e As EventArgs ) As LRESULT
? "ListView COLUMNCLICK. e.ListViewColumn: "; e.ListViewColumn
Function = 0
End Function
Hi Paul and Jose. thanks for the reply. The example image that I posted a bit earlier on, I find I can read in about 220000 (220k) lines of similar code before it crashes. (that is parsing and populating the ten columns, as necessary). It is very critical that you know how to count! If you have ten columns, you can't just populate nine, unless there are settings unknown to me. I think I'll see if I can blend in the Vlist algorithm that I used in firefly, to get more rows. Once I've got it working with the number of lines I need, then I'll be playing with editing, I expect, which so far looks to be fairly straightforward. Presumably I can get as well as set the text colors for each item.
edit to add - tried 64bit got 595698 lines. tried the larger file 3.2 million lines , took ages to load, I think it stalled on parsing. I'll have a look later, it's late night/early morning here. But, in firefly, it loads very quickly, and completes populating in a couple of minutes. I'm getting the impression that firefly ran much quicker, certainly with my attempts at cgi graphics.
Hi Ray, How about only populating the ListView with a "range" of Rows that the user can comfortably navigate? Perhaps the height of the screen plus some number that can quickly be added or subtracted as the user scrolls up and down through the list. This would greatly cut down on memory usage.
It's crazy to try to populate a ListView with so many items. The best approach is to use a virtual ListView and provide the data on demand. This way, you can have as many items as you wish.
QuoteI think I'll see if I can blend in the Vlist algorithm that I used in firefly, to get more rows.
But, where is the acceptable non crazy limit? I had thought that listview had incorporated something like that vlist facility, since it was mentioned that listview handled thousands of items, or similar, iirc. I had already asked whether the limit was memory size, or something else. I guess nobody says 'cos nobody knows.
All I'm doing is testing. The best way, often, is to test it in the real world, on applications/data that I know. I have found out a fair bit on how listview behaves in the last day or so. it is robust enough within it's limits, (whatever they may be), but it does not fail gracefully. I'm not saying that is a good or bad thing, it doesn't need to be bogged down in data validation, but either information needs to be available in a way that I can understand, or I'll have to work it out for myself, or do something entirely different.
I mentioned in a previous response that the Listview is limited by system memory. I have implemented this control as a virtual listview in that the text data is NOT stored in the listview itself (the listview is created with the LVS_OWNERDATA style). It is stored in data collections within the listview classes that I have written for the visual designer code generation. When text is need to be displayed on the screen, the listview asks for those particular items and/or subitems via a Windows api notification LVN_GETDISPINFO. I return the pointers to the data and then the listview displays it. Also, the listview uses CustomDraw (responds to the NM_CUSTOMDRAW notification) in order to handle the coloring of the foreground and background of each item/subitem.
The vlist code that Borje posted on the PB Forums and from which I adapted for the corresponding Firefly custom control, uses a similar approach. The data is held in an array(s) and during WM_PAINT, the necessary rows to show on the screen are requested from the array and displayed. I expect that you'd never be able to fit the millions of data lines into those arrays either.
Hope that helps to explain it a bit better.
Hi Paul, click on the Button Bar "New" down arrow will crash WinFBE64.exe but not WinFBE32.exe. I've gone back to 1.9.0 and tested all releases through to 1.9.7 but only WinFBE 1.9.7 exhibits this behaviour.
QuoteIt is stored in data collections within the listview classes that I have written for the visual designer code generation
Perhaps you could explain with an example? with comments/explanation.I used Borje's vlist, in December, and it adequately handles 2.5 million lines of my data. I created a list, iirc, and then the list box sort of scrolled up and down that list. (Don't you love my mastery of technical terms!) Now, if you have included the vlist algorithm, within listview, then where/how do I refer to the list of data that I have read in. I'll get there in the end, but I think you are maybe thinking I have more background in windows programming than I have.
so, the following is incorrect?
open filename for input as #fnum
while not eof (fnum)
line input #fnum,a
frmmain.text2.Text = str(j)
frmmain.ListView1.items.add( a)
frmmain.ListView1.item(j).subitems.add ("")
frmmain.ListView1.item(j).subitems.add ("")
frmmain.ListView1.item(j).subitems.add ("")
frmmain.ListView1.item(j).subitems.add ("")
frmmain.ListView1.item(j).subitems.add ("")
frmmain.ListView1.item(j).subitems.add ("")
frmmain.ListView1.item(j).subitems.add ("")
frmmain.ListView1.item(j).subitems.add ("")
frmmain.ListView1.item(j).subitems.add ("")
frmmain.ListView1.item(j).subitems.add ("")
frmMain.ListView1.SelectedIndex = 0
j=j+1
wend
close #fnumfor wherever j is a large value, or incorrect in general? It is populating the listview along the lines of your example. It is slow and works for up to about 600000 lines of data, (as I said before) and most likely for larger files as well. When I used vlist with firefly, (I can check how I did it) I believe I read the file into a single array (i.e copied the file to memory) and processed it there, instead of reading and processing line by line. If I do a similar thing again, are you saying that I can dispense with my vlist routine if I use list view?
As I mentioned, a commented example would really help.
Hi Ray,
Here you go. I created this example based on the code that you posted. Ask as many questions as you need until you understand.
''
''
Function frmMain_Initialize( ByRef sender As wfxForm, ByRef e As EventArgs ) As LRESULT
dim as long j, i
dim as string a
' Ray, it looks like you want to have 11 columns of data total. I say this
' because in your example you are adding many subitems.
' You must define your columns before adding the item data. You can
' then choose to show or hide those column headers based on the
' ListView's HeaderStyle property (which you can set via code or via
' the visual desgner's propertylist).
for i = 0 to 10
frmMain.ListView1.Columns.Add( "SubItem" & i, 100, TextAlignment.Left )
next
' Hide the column headers
'frmMain.ListView1.HeaderStyle = ColumnHeaderStyle.None
' Show the column headers
frmMain.ListView1.HeaderStyle = ColumnHeaderStyle.Clickable
' Open a test file and display it in the ListView line-by-line
' We will use a copy of Jose's AfxWin.inc file as a test file.
dim as string filename = "AfxWin.inc"
dim as long fnum = freefile
open filename for input as #fnum
while not eof (fnum)
line input #fnum, a
' Add a new item to the ListView. The items.add call returns
' the newly added index value into the variable i. The newly
' created item automatically creates a subitem 0. Basically,
' the item and subitem(0) are the same thing and they can be
' referenced interchanably.
j = frmmain.ListView1.items.add(a) ' this creates subitem0
' Display in the TextBox the value of the newly created index.
frmmain.text2.Text = str(j)
' Now add any subitems for the newly created item
frmmain.ListView1.item(j).subitems.add ("") ' subitem1
frmmain.ListView1.item(j).subitems.add ("") ' subitem2
frmmain.ListView1.item(j).subitems.add ("") ' subitem3
frmmain.ListView1.item(j).subitems.add ("") ' subitem4
frmmain.ListView1.item(j).subitems.add ("") ' subitem5
frmmain.ListView1.item(j).subitems.add ("") ' subitem6
frmmain.ListView1.item(j).subitems.add ("") ' subitem7
frmmain.ListView1.item(j).subitems.add ("") ' subitem8
frmmain.ListView1.item(j).subitems.add ("") ' subitem9
frmmain.ListView1.item(j).subitems.add ("") ' subitem10
wend
' Select the first line in the ListView
frmMain.ListView1.SelectedIndex = 0
close #fnum
Function = 0
End Function
Thanks Paul, I'll try it out dreckly, and let you know.
Hi Paul, thanks again.
Here is what I had to initialise the listview Function frmmain_Initialize( ByRef sender As wfxForm, ByRef e As EventArgs ) As LRESULT
'set up list view
frmMain.ListView1.Columns.Add( "G-code", 400, TextAlignment.Left )
frmMain.ListView1.Columns.Add( "G", 60, TextAlignment.Left )
frmMain.ListView1.Columns.Add( "X", 80, TextAlignment.Left )
frmMain.ListView1.Columns.Add( "Y", 80, TextAlignment.Left )
frmMain.ListView1.Columns.Add( "Z", 80, TextAlignment.Left )
frmMain.ListView1.Columns.Add( "A", 80, TextAlignment.Left )
frmMain.ListView1.Columns.Add( "R", 80, TextAlignment.Left )
frmMain.ListView1.Columns.Add( "I", 80, TextAlignment.Left )
frmMain.ListView1.Columns.Add( "J", 80, TextAlignment.Left )
frmMain.ListView1.Columns.Add( "F", 80, TextAlignment.Left )
frmMain.ListView1.Columns.Add( "Comment", 400, TextAlignment.Left ) '11 cols
Function = 0
End Function
I can see nothing wrong there. The rest of the code, populating the listview,was/is similar to yours, I can see no significant difference in your method, and mine (seeing as mine was based on yours, too.)
In general, I think it is quicker to read in a file to an array in one burst, and then parse the entries in the array, and 'fill' the listview. I was reading a line and parsing each line as read. For smaller files, it is not noticeable, but for longer ones, I believe it is.
So, if you have included the vlist algorithm in listview, then I'm guessing it is not the same 'listview' which Jose said would be crazy to use on a mass of data.
But, I'd better run your last example code, on my data, and see for myself.
For quickly going through a million lines of data, then for the list box I made a column of adjacent small buttons (like a scroll bar) but buttons further away from the center pair, selected at plus or minus a multiple of ten items (and the listbox showed 20 or so items, so individua lines could be selected). e.g. centre pair of buttons would select +/- 10 from selected item, next outer pair select +/- 100, next pair select +/- 1000 - a sort of logarithmic scroll bar. A normal scroll bar is not very usable. Of course, line numbers and a search facility helps.
here you go -
I will be able to speed it up, or at least give the impression of speeding it up. What happens, with a large file, for the example code as you have just posted, But with my large file, (I added a print to console to show something happening) the form does not appear until the listview is populated, and reading a line from file, processing that line takes time. List view works as I expected, and it will handle large files - so 'winner,winner, chicken dinner!'
Finding that I had more or less understood listview, as far as i needed to know, I rerun yesterday's code, and waited (I should have timed it, but couldn't find a calendar). It eventually displayed the parsed g-code. Now to get into speeding it up. I would like to include my 'logarithmic scroll bar' so I think I may use two listviews - one for the file data , one column wide, which should get populated pretty quick as the file is read in, a line at a time, and one about ten columns for the parsed data, gleaned from the first listview. I may or may not tie the selected item rows together, it is handy to be able to return to a previously selected line- I can probably achieve that with colors. This of course, is only a part of what it will be doing. If i can get it to run as fast as, or faster than my firefly version, I'll migrate my firefly program, if not, I'll modify the firefly version.
Also realize that if you are outputting every line to the console as well then there will be a significant slow down. Printing to the console and scrolling the console is a very slow operation.
Thanks Paul, doing anything takes time. But somehow you need something to happen, else it can appear it is frozen/crashed. What I've done before is alter the file name text box to show loading + filename, and wait until it has loaded, and then change it back to filename. Testing the same two million or so lines of data, it is loaded and displayed in my firefly version in under five seconds, and then parsing to the separate lists takes about 20 seconds. I say parsing, but it does much more than that, finding max/min values, etc. I see no reason that using the same technique will not give similar timings using your listviews.
Editing individual values - will that be possible directly, or will it be necessary to use a separate textbox and do a copy/replace, as I've used in my firefly version using listboxes? I'm not sure if the longer entries ending in ellipsis can be expanded in situ, but not a major issue for me.
Thanks for your patience and expertise, it is much appreciated.
edit to add - just timed it. reading in the file into an array, less than 2seconds. Total time to read into and then get that array into a single column listview - straight copy, 8.93 minutes. That, in Firefly takes 5 seconds, using vlist and a custom control. Plan B beckons.
I find the width of listview as set in designer does not exactly tie with the width in pixels set in code. I'm guessing the width in designer includes the frame, whereas that in code is the usable width for data. I'm wondering, if not too difficult, if it would help for the cursor in designer to display it's location wrt the form?
edit to add - which has got me thinking wrt the grid. Does it 'steal' pixels from each item, or is it a sort of overlay on the whole tool. I imagine, that if a value in a sub item fills the area, that turning on the grid could cause ellipsis to display, if the grid steals pixels, but not necessarily so if it's an overlay.
Hi Ray,
I found the source of the slow down when adding bulk items to the ListView. If items are added during Initialize then it is very fast but if once the ListView is created (ie. the hWindow is valid) then the process slows down considerably. This is because I was making a call to ListView_SetItemCountEx after every Add if the hWindow existed. I was surprised of the huge performance effect this had.
I have added two new ListView methods: BeginUpdate, and EndUpdate. If you bookend your bulk adding loop with these calls then the adding is extremely fast (less than 2 seconds for 500,000 items on my testing computer).
So use code like this:
frmMain.ListView1.Items.Clear
frmMain.ListView1.BeginUpdate
dim i as Long
for ii as long = 0 to 500000
i = frmMain.ListView1.Items.Add( "Line " & ii )
frmMain.ListView1.Item(i).SubItems.Add( "L" & ii & "Sub1" )
frmMain.ListView1.Item(i).SubItems.Add( "L" & ii & "Sub2" )
next
frmMain.ListView1.EndUpdate
I will post an update to the Visual Designer tonight.
Hi Paul, will BeginUpdate and EndUpdate be required or optional? I'm guessing this block of code will still work with the new bookends excluded, just slower:
dim i as Long
for ii as long = 0 to 500000
i = frmMain.ListView1.Items.Add( "Line " & ii )
frmMain.ListView1.Item(i).SubItems.Add( "L" & ii & "Sub1" )
frmMain.ListView1.Item(i).SubItems.Add( "L" & ii & "Sub2" )
next
My current ListView requirements are for list of less than 200 so I have no need for speed in this case.
Hi Clive, it is optional.
Perfect. Thanks, Paul.
When I port my big FF project over to WinFBE, the file sizes will be much larger but still probably less than 50K individual entries (xml file). Mostly this will be for diagnostics though (I think) I can see the advantage of having all the entries in a single scrollable ListView.
I'll do some testing on larger file importing once the new release is out. It involves reading in and parsing an xml file (which is where the bottleneck will occur). The parser is my own so I'll be on the lookout for some optimizing ideas then.
Thanks for the begin/end update, Paul, I'll give it a whirl. For Clive, I think the 50K file will be fine. I know that data can vary, memory sizes, cpu speed, etc., but wrt parsing, even for my much larger files 90MB or so, it only takes 92 seconds to read in file to array and parse to nine other arrays, some conversion from string to single, etc. An 128K file, delay is not noticeable. I have some parsing code in firefly, which is different than my simple method, I will most likely run a comparison wrt timings.
Hi Ray, yes, lots of variables wrt hardware and so forth. In a different test project, I've been experimenting with a 28MB XML file with 14,400 entries. The FF version only takes a few seconds to open the file, parse XML and populate the ListView. Looking forward to trying out the WinFBE version with Begin/End.
Hi Clive, I found that my previously suggestion, somewhere on this forum, wrt parsing, (turning string to UCASE, then doing character comparison of first character as I went through the string) is considerably quicker if instead of doing the UCASE, I take the ASC of the left hand character of the string as I go through it, and compare with the ASC code for upper and lower case of the test characters. The timing went from 48 seconds down to 28 seconds.
You could also treat the string as an array of characters and iterate through it testing each byte which is much faster than using MID, etc.
Something like....
For i As Long = 0 To Len(MyText) - 1
Select Case MyText[i]
Case 65 ' whatever ascii value you need to test
End Select
Next
I expect it will be a niggle at the back of my mind. I can live with 28 seconds. The time I spend, recoding and testing may be much longer than the time saved in parsing. Maybe I run the large files, say 200 times. That will be roughly 100minutes in the parsing routine. It'll take me longer than that to recode and test, and even so, I won't be able to get the parsing time down to zero. Law of diminishing returns - but that has rarely stopped me before.
sub parsegcode2(byval gstring as string,byref gv as integer,byref xv as single,byref yv as single,byref zv as single,_
byref fv as single,byref rv as single,byref iv as single, byref jv as single,byref av as single)
'parses a gcode string, sets gv to -99 if comment, -9 if blank, -999 if can't do
'-999999 if not set
gv=-9
dim lns as string
dim t as Integer
t=len(gstring)
iv=-999999
xv=iv
yv=iv
zv=iv
gv=iv
fv=iv
rv=iv
jv=iv
av=iv
for k as integer =0 to t
lns= Right(gstring,t-k)
if left (lns,1)= "(" then
gv=-99
goto quit
end if
select case asc(left(lns,1) )
case 88,120
xv=Val(Right(lns,(t-(k+1)) ))
case 89,121
yv=Val(Right(lns,(t-(k+1)) ))
case 90,122
zv=Val(Right(lns,(t-(k+1)) ))
case 71,103
gv=Val(Right(lns,(t-(k+1)) ))
case 70,102
fv=Val(Right(lns,(t-(k+1)) ))
case 82,114
rv=Val(Right(lns,(t-(k+1)) ))
case 73,105
iv=Val(Right(lns,(t-(k+1)) ))
case 74,106
jv=Val(Right(lns,(t-(k+1)) ))
case 65,97
av=Val(Right(lns,(t-(k+1)) ))
end select
next
quit:
end sub
Overall, I'm not sure if it would be quicker if gv through av were stored as strings. Simply using VAL(anystring) gives the value if the first part of the string is a number, and I'm not sure if reading each character and testing and then multiplying the digits to get the value would be quicker. The numbers can be any value, any length, terminated by a space or end of line or any none-digit (including +,- etc.). I can make it look prettier, remove the GOTO if that causes offense XD but the order of the selects (putting most frequent first) is about right for most files I deal with.
Freebasic has a limit of 2GB for a string, I'm not sure about numeric arrays, but I expect the limit is well beyond what I need - there are about 40 characters per line of g-code so I could possibly have a file up to 50 million lines long, before i hit the 2GB string limit.
Hi Paul, I did a simple test of the .BeginUpdate and .EndUpdate (the bookends you mentioned in an earlier post).
Function frmMain_Initialize( ByRef sender As wfxForm, ByRef e As EventArgs ) As LRESULT
? "Standby..."
?
frmMain.ListView1.Items.Clear
Dim As Long l = GetTickCount()
Dim As Long i
i = frmMain.ListView1.Columns.Add( "Column 1", 100, TextAlignment.Left )
i = frmMain.ListView1.Columns.Add( "Column 2", 100, TextAlignment.Center )
i = frmMain.ListView1.Columns.Add( "Column 3", 100, TextAlignment.Right )
frmMain.ListView1.BeginUpdate
for ii as long = 0 to 1000000
'Application.DoEvents
i = frmMain.ListView1.Items.Add( "Line " & ii )
frmMain.ListView1.Item(i).SubItems.Add( "L " & ii & " Sub1" )
frmMain.ListView1.Item(i).SubItems.Add( "L " & ii & " Sub2" )
next
frmMain.ListView1.EndUpdate
? "Time to load", GetTickCount() - l
?
frmMain.ListView1.Item(5).SubItem(0).ForeColor = colors.Red
frmMain.ListView1.Item(5).SubItem(2).ForeColor = colors.Orange
frmMain.ListView1.Item(2).ForeColor = colors.Blue
frmMain.ListView1.Item(2).BackColor = colors.Yellow
frmMain.ListView1.Item(2).SubItem(1).ForeColor = colors.Green
frmMain.ListView1.SelectedIndex = 8
Function = 0
End Function
The time to load 1,000,000 items in ms after running 5 times with bookends and 5 times with bookends commented out:
With BookEnds : 17015, 17375, 17156, 16860, 16687
Without Bookends: 17031, 16641, 16422, 16344, 16546
Am I using the bookends incorrectly?
I see that you are doing the BeginUpdate/EndUpdate from within the Initialize event. The ListView hWindow is not valid at that point so you will see no added benefit from using this new feature. If you moved your code to the Load event then you will see a substantial difference.
For the next update I have added a new ListView property called "OddRowColor". This allows you to create the nice looking effect of alternating rows with different background color similar to a ledger spreadsheet.
Great, thanks, Paul! "OddRowColor", I've used an alternating row colour in apps with grids for (too many) years; they look good and help with user navigation. Perfect...
I also just found code from Jose Roca related to multiline ListView column headers so I will try to incorporate that into the designer as well. Making the column headers ownerdraw will allow for better coloring and multiline. I'll see how good/bad it looks/works over the next few days.
QuoteListView property called "OddRowColor".
80 column punched cards and 15inch music score perf paper core dumps. It was years b4 i got into the swing of writing code on a glass teletype.
Quote from: Paul Squires on November 04, 2019, 03:31:41 PM
Thanks Clive, I have noticed this also. Basically, when you bring back the mouse cursor over the Listview it will "automatically" select the row under the cursor even if you don't click on it. Moving the mouse over other rows does not select any of those rows (as you would expect if a hot tracking extended style such as LVS_EX_TRACKSELECT was present). It only happens if you move the mouse cursor off of the control and then back over the control again. I need to figure out why this happens because it is bothering me greatly
16 days later I've finally found the source of the problem. For all controls I've implemented a combination of events MouseEnter, MouseHover, and MouseLeave. All that code is found in the wfxApplication.inc file of the WinFormsX library. Because there is no such thing as a WM_MOUSEENTER message, I simulated it in WM_MOUSEMOVE by setting a tracking variable and invoking TrackMouseEvent api.
It appears that when I use the TrackMouseEvent api and also set the TME_HOVER flag, the ListView will react as described in my above quote. So, I have to remove the MouseHover event from the ListView control.
Case WM_MOUSEMOVE
WINFORMSX_HANDLE_MESSAGE(OnMouseMove)
' If this is a Label/ListBox then redraw so hot colors will be used
#ifdef CODEGEN_LABEL
if pLabel then pLabel->Refresh
#endif
#ifdef CODEGEN_LISTBOX
if pListBox then pListBox->Refresh
#endif
' There is no such thing as a WM_MOUSEENTER message so we need to simulate it
' here by using a tracking variable and TRACKMOUSEEVENT.
dim as DWORD dwFlags = TME_HOVER Or TME_LEAVE
#ifdef CODEGEN_LISTVIEW
' Do not allow HOVER on a ListView as it somehow invokes hot tracking an
' automatic row selection when the mouse hovers over it. Not desirable.
if pListView then dwFlags = TME_LEAVE
#endif
If pCtrl Then
If pCtrl->IsTracking = False Then
pCtrl->IsTracking = True
Dim tme As TrackMouseEvent
tme.cbSize = Sizeof(TrackMouseEvent)
tme.dwFlags = dwFlags
tme.hwndTrack = hWin
TrackMouseEvent(@tme)
WINFORMSX_HANDLE_MESSAGE(OnMouseEnter)
End If
End If
Case WM_MOUSELEAVE
If pCtrl Then pCtrl->IsTracking = False
WINFORMSX_HANDLE_MESSAGE(OnMouseLeave)
' If this is a Label/ListBox then redraw so normal colors will be used
#ifdef CODEGEN_LABEL
if pLabel then pLabel->Refresh
#endif
#ifdef CODEGEN_LISTBOX
if pListBox then pListBox->Refresh
#endif
Case WM_MOUSEHOVER
WINFORMSX_HANDLE_MESSAGE(OnMouseHover)
Hi Paul, I noticed that all controls on all forms and all forms have the same 2 Events; ListViewColumn and ListViewRow even in a project that does not have a ListView control. I'm not sure if this is relevant to your previous post.
Do you mean Properties rather than Events? Those two properties are part of the e EventArgs parameter. It is only used obviously for ListViews.
An EventArg.
Function frmJournal_btnExit_Click( ByRef sender As wfxButton, ByRef e As EventArgs ) As LRESULT
e.ListViewColumn
Function = 0
End Function