Listbox Row Background Custom Colors

In a project (many) I use the code below to draw alternate colors as Row Background:

[code]If row Mod 2 = 0 Then
g.ForeColor = &cf3f6fA
Else
g.ForeColor = &cf3f600
End If

g.FillRect(0, 0, g.Width, g.Height)[/code]
And this works fine.

I also use a Tag to set special Row Background Colors (to mean something). The used code is a variant of:

If Me.CellTag(row, column ) = "Red" Then g.ForeColor = RGB(255, 0, 0) g.FillRect(0, 0, g.Width, g.Height) End If

At run time (IDE Or/And Standalone), the Listbox background alternate colors are drawn correctly, but to get my alternate colors, I have to select either all Rows or to select the individual Rows and move the selection with the arrow key to “activate” the background paint process. Once this is done for the visibles Rows, it is done automatically for the other Rows.

Ideas are welcome.

[code]Function CellBackgroundPaint(g As Graphics, row As Integer, column As Integer) Handles CellBackgroundPaint as Boolean
If row Mod 2 = 0 Then
g.ForeColor = &cf3f6fA
Else
g.ForeColor = &cf3f600
End If

If row < me.ListCount and Me.CellTag(row, column ) = “Red” Then
g.ForeColor = RGB(255, 0, 0)
End If

g.FillRect(0, 0, g.Width, g.Height)

End Function[/code]

After you set the CellTag, invalidate the cell. That will force a CellBackgroundPaint.

Markus, Tim: Thank for your answers.

@ Markus:
You are right: my example code was not functional. The real code is far more complex, but the g.FillRect line is at the code bottom line.

@ Tim:
I fill CellTag at file open time. And, as I wrote earlier, I have nothing to do for the Rows that are not visible at first (file open time).
I check…
I have hard times to get a way to be in the non functioning part (drag and drop works, Open csv works too; only Open sqlite does not works).

Nota: I use LB.Invalidate in the working cases.
Also: I boot my laptop using Sierra 12.6 (not my usual El Capitan…)
Used Xojo is 2015r1.

Now, where is the .SQLite open code ? Found, added LB.Invalidate and…import csv files does not works (I have to get a .sqlite file !)
Open .sqlite files seems to works.

OK: I will go back home and get a long, very long nap and forget this xojo business for sometimes !
(until I boot on El Capitan)

[quote=348143:@Emile Schwarz]@ Markus:
You are right: my example code was not functional. The real code is far more complex, but the g.FillRect line is at the code bottom line.[/quote]
My answer was not about the code not being functional, it was about you using the wrong event. Just try it:

Listbox:

Sub Open() Handles Open for i as integer = 0 to 10 me.AddRow "test" next End Sub

[code]Function CellBackgroundPaint(g As Graphics, row As Integer, column As Integer) Handles CellBackgroundPaint as Boolean
If row Mod 2 = 0 Then
g.ForeColor = &cf3f6fA
Else
g.ForeColor = &cf3f600
End If

If row < me.ListCount and Me.CellTag(row, column ) = “Red” Then
g.ForeColor = RGB(255, 0, 0)
End If

g.FillRect(0, 0, g.Width, g.Height)

End Function[/code]

Add PushButton1:

Sub Action() Handles Action Listbox1.CellTag( 3,0) = "red" End Sub

Add PushButton2:

Sub Action() Handles Action Listbox1.CellTag( 3,0) = "" End Sub

No need to use invalidate or keep track of it yourself.

Agree with this. Use ListBox.InvalidateCell if you want to see the change immediately.

INVALIDATECELL is not “immediate”… it happens at the end of each run loop… but is still the best method to use to keep from accidentaly tieing up the CPU

Don’t know about this. How do you know that? Profiling the code?

Ok, you’re right. CellBackgroundPaint is fired after looping.

gee … experience, reading documentation, research, other on this forum…
but reading the LR is a GREAT start
INVALIDTE

REFRESH

Emile, listbox.Invalidate does nothing. Use listbox.InvalidateCell instead.

Unless you want to see the result immediately, and not at some point in the future when the listbox refreshes.

to be clear “some point in the future” is USUALLY a fraction of a second, depending on the processing happening during the current run loop

and for those not as familiar…

x.refresh
x.refresh
x.refresh
x.refresh
x.refresh

vs

x.invalidate // or invalidatecell if a listbox
x.invalidate 
x.invalidate 
x.invalidate 
x.invalidate 

the first causes X to be redrawn FIVE times, while the second causes it to be redrawn ONCE

Not if you don’t invalidate the cell. Simply setting the CellTag will not cause the listbox to redraw. So you have the situation that Emile describes where he has to “tickle” the listbox (in his case by selecting each row in turn with the arrow key) before he sees the background color change. InvalidateCell solves that problem, which is what the OP was all about.

As Dave said. Try my example. Seems pretty immediate to me.

Tim… not sure what you are referrring to… and perhaps I misread as well… I was saying “Invalidate(cell)” usually causes the redraw within a fraction of a second

By golly, you’re right! It works with celltag, but not with rowtag. Emile, you aren’t using RowTag, are you?

Changing CellTag causes the cell to refresh.
Changing RowTag does not and requires InvalidateCell if you want to see the results immediately.

[quote=348217:@Tim Hare]By golly, you’re right! It works with celltag, but not with rowtag. Emile, you aren’t using RowTag, are you?

Changing CellTag causes the cell to refresh.
[/quote]

I would call that a bug… It can add overhead for cases when it is not needed… It should do that only when the cell value ( auto displayed contents) change.

As IMO that is a bug that SHOULD be fixed, one should call InvalidateCell when changing the CellTag IF (and only If) that change needs to change the displayed value too, in case it does get fixed.

  • Karen

On reflection I tend to agree with Karen. Maybe a Xojo engineer can throw some light on that?