WinFBE Suite 1.9.7 (November 2, 2019)

Started by Paul Squires, November 02, 2019, 08:59:15 PM

Previous topic - Next topic

raymw

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.

SeaVipe

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.
Clive Richey

raymw

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.

Paul Squires

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

Paul Squires
PlanetSquires Software

raymw

#34
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.

SeaVipe

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?
Clive Richey

Paul Squires

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.
Paul Squires
PlanetSquires Software

Paul Squires

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.
Paul Squires
PlanetSquires Software

SeaVipe

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...
Clive Richey

Paul Squires

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.
Paul Squires
PlanetSquires Software

raymw

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.

Paul Squires

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)

Paul Squires
PlanetSquires Software

SeaVipe

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.
Clive Richey

Paul Squires

Do you mean Properties rather than Events? Those two properties are part of the e EventArgs parameter. It is only used obviously for ListViews.
Paul Squires
PlanetSquires Software

SeaVipe


An EventArg.


Function frmJournal_btnExit_Click( ByRef sender As wfxButton, ByRef e As EventArgs ) As LRESULT
    e.ListViewColumn
    Function = 0
End Function
Clive Richey