Listbox database doesn't move when re-ordered

So, I have a databases that populates a listbox. The listbox contains
0 Name, 1 picture, 2 SequenceID
I thought it maybe good to reorder them so my users could have their favourite ones at the top. They choose notes on the fretboard and the sequences will play them.
I enabled re-order. 0 and 2 moved to the new row - but the pictures stay in the same row that i dragged from. I have tried quite few tactics to get them to update… Doing something in callbackground paint… a completely new method to put the pictures in column 1.
Any ideas?

Which event handlers have you implemented in th elistbox?

Show us the code you used to display the images…

Also, you have to know that sorting the ListBox change nothing to the data base row order.

This is also because databases don’t have a row order. The database can return rows to you in ANY order, UNLESS you have an ORDER BY clause in your SQL.

Here’s what I put in cell background paint

if column=1 and patt(row)<>nil then
  g.DrawPicture (patt(row),0,0,patt(row).width*0.60,40,0,0,patt(row).Width,patt(row).Height)
end if
return true

as for the code to populate patt(row) it’s

dim f AS FolderItem
SequenceData.databaseFile =specialfolder.ApplicationData.child("Guitar SightReader Toolbox").child("database").child("SequenceDataBase")
Dim rs as RecordSet
dim rec as DatabaseRecord
rec = New DatabaseRecord
dim i as integer=0
dim p as Picture

f=specialfolder.ApplicationData.child("Guitar SightReader Toolbox").child("Invertor order.txt")
if f=Nil or f.exists=false then
  rs = SequenceData.SQLSelect( "SELECT * FROM Sequences" )
  // Clear the passed listbox
  SequenceList.DeleteAllRows
  SequenceList.GridLinesHorizontal=2
  While Not rs.EOF
    SequenceList.AddRow (rs.field("Name"))
    i=SequenceList.LastIndex
    patt(i)=StringtoPicture(rs.field("Image"))
    SequenceList.cell(i,2)=rs.field("SequenceID")
    rs.MoveNext
  Wend
end if

So you’re storing the pictures in your own array, not the Listbox and that’s why they’re not reordering. You’ll have to reorder your array or, which I recommend more, store the picture as either a RowTag or CellTag, and it will move for you.

1 Like

I’ll try it

Or

While Not rs.EOF
SequenceList.AddRow (rs.field(“Name”))
i=SequenceList.LastIndex
SequenceList.rowtag(i) = i

plus


if column=1 and patt(row)<>nil then
dim actualimage as integer = me.rowtag(row)
  g.DrawPicture (patt(actualimage),0,0,patt(actualimage).width*0.60,40,0,0,patt(actualimage).Width,patt(actualimage).Height)
end if
return true

You will need to do something to save the new positions of the list when the window closes, of course.

The problem is that ‘row’ does not change when you re-order the listbox.

Two possible solutions:
1.When you add the data to the listbox store a copy of the index in a cell tag which you can then look up during the paint event.

Populate Data:

While Not rs.EOF
    SequenceList.AddRow (rs.field("Name"))
    i=SequenceList.LastIndex
    patt(i)=StringtoPicture(rs.field("Image"))
    SequenceList.cell(i,2)=rs.field("SequenceID")

    SequenceList.celltag(i,0)=i

    rs.MoveNext
  Wend

Paint Event:

Dim index As Integer

index = Me.CellTag(row, 0)
if column=1 and patt(index)<>nil then
  g.DrawPicture (patt(index),0,0,patt(index).width*0.60,40,0,0,patt(index).Width,patt(index).Height)
end if
return true




2.Store the picture in a cell tag rather than storing it in an array.

Populate Data:

While Not rs.EOF
    SequenceList.AddRow (rs.field("Name"))
    i=SequenceList.LastIndex
    SequenceList.cell(i,2)=rs.field("SequenceID")

    SequenceList.celltag(i,0)=StringtoPicture(rs.field("Image"))

    rs.MoveNext
  Wend

Paint Event:

Dim p As Picture

p = Me.CellTag(row, 0)
if column=1 and p<>nil then
  g.DrawPicture (p,0,0,p.width*0.60,40,0,0,p.Width,p.Height)
end if
return true

Did you do any debugging in order to find out what was going on?

Old method:

 While Not rs.EOF
    SequenceList.AddRow (rs.field("Name"))
    i=SequenceList.LastIndex
    patt(i)=StringtoPicture(rs.field("Image"))
    SequenceList.cell(i,2)=rs.field("SequenceID")
    rs.MoveNext
  Wend

new method I propose:

While Not rs.EOF
    SequenceList.AddRow (rs.field("Name"))
   Bad :  i=SequenceList.LastIndex
   Good: i=SequenceList.LastAddedRowIndex
   var dico as New Dictionary 
   For rang As Integer = 0 To rs.LastColumnIndex
  dico.Value ( rs.ColumnAt(i).Name ) =  rs.ColumnAt(i rang)
  next
  SequenceList.RowTagAt(LastAddedRowIndex ) = dico
 
 patt(i)=StringtoPicture(rs.field("Image"))
  SequenceList.cell(i,2)=rs.field("SequenceID")
  rs.MoveNext
  Wend

Well, all answers were winning!
It works and drags to reorder the lists including the Image (there are 2 - the main screen and the editor (all in the same window)). My question is… how would you keep the order of the list when reopening the tool? My first thought is to textoutput a text file with the list of sequenceIDs. Your thoughts?
Here’s working my code so far:

dim f AS FolderItem
SequenceData.databaseFile =specialfolder.ApplicationData.child("Guitar SightReader Toolbox").child("database").child("SequenceDataBase")
Dim rs as RecordSet
dim rec as DatabaseRecord
rec = New DatabaseRecord
dim i as integer=0
dim p as Picture

SequenceList.DeleteAllRows
SequenceList2.DeleteAllRows

rs = SequenceData.SQLSelect( "SELECT * FROM Sequences" )
While Not rs.EOF
  SequenceList.AddRow (rs.field("Name"))
  SequenceList2.AddRow (rs.field("Name"))
  i=SequenceList.LastIndex
  patt(i)=StringtoPicture(rs.field("Image"))
  SequenceList.cell(i,2)=rs.field("SequenceID")
  SequenceList2.cell(i,2)=rs.field("SequenceID")
  SequenceList.celltag(i,0)=i
  SequenceList2.celltag(i,0)=i
  rs.MoveNext
Wend

and in the cellbackgroundpaint event:

Dim index As Integer
index = SequenceList.CellTag(row, 0)
if column=1 and patt(index)<>nil then
  g.DrawPicture (patt(index),0,0,patt(index).width*0.60,40,0,0,patt(index).Width,patt(index).Height)
end if
return true

You can use my class
lb_pptes.xojo_binary_project.zip (12.9 KB)

That’s your answer ?

Uh-oh… Big hiccup.
Using the method

SequenceList.DeleteAllRows
rs = SequenceData.SQLSelect( "SELECT * FROM Sequences" )
While Not rs.EOF
  SequenceList.AddRow (rs.field("Name"))
  i=SequenceList.LastIndex
  patt(i)=StringtoPicture(rs.field("Image"))
  SequenceList.cell(i,2)=rs.field("SequenceID")
  SequenceList.celltag(i,0)=i
  rs.MoveNext
Wend

I have 42 items in the database. It’s all good until I scroll down to the bottom - then I get a out of bounds error in the cellbackgroundpaint event if the row=42. I know the sequencelist listindexs should only up to 41 (0 based list). But for some reason, I have this error. What am I missing? Why is there even a row 42 able to be called here? Apart from this it’s working well.

Thanks to Wayne Goldings example, I changed my cellbackground event to

If row < me.ListCount Then
  Dim index As Integer
  index = SequenceList2.CellTag(row, 0)
  if column=1 and patt(index)<>nil then
    g.DrawPicture (patt(index),0,0,patt(index).width*0.60,40,0,0,patt(index).Width,patt(index).Height)
  end if
end if
return true

That
If row<me.listcount then… made it work
(Waynes example used row count - but I’m using 2019r1 on high sierra - I don’t want to upgrade until Xojo implements JPEG from HTML again - and because I’m poor)

Method:

SequenceList.DeleteAllRows
rs = SequenceData.SQLSelect( "SELECT * FROM Sequences" )
While Not rs.EOF
  SequenceList.AddRow ( rs.field("Name") , "???" , rs.field("SequenceID" )
  SequenceList.RowTagAt ( SequenceList.LastAddedRowIndex ) = rs.field("Image")
  rs.MoveNext
Wend

Event PaintCellBack:

If row < Me.ListCount Then
  Var p As Picture 
  p = Me.RowTagAt ( row ) 
  DrawPicture( p , X As Double, Y As Double, [destWidth As Double], [destHeight As Double], [sourceX As Double], [sourceY As Double], [sourceWidth As Double], [sourceHeight As Double])
End If