newTableView scrolling error

I’ve been working on a maintain selected-row display solution and have come across this runtime error when scrolling tableview.  (the top 3 statements are from prints where I’ve been trying to localize the actual error)

I/Corona  (11040): iNew=        true

I/Corona  (11040): showing selected

I/Corona  (11040): calling reload

I/Corona  (11040): ERROR: Runtime error

I/Corona  (11040): /data/data/com.masterboltdevelopment.sdzAdmin/files/coronaResources/tableView.lua:397: attempt to call method ‘setFillColor’ (a nil value)

I/Corona  (11040): stack traceback:

I/Corona  (11040):      /data/data/com.masterboltdevelopment.sdzAdmin/files/coronaResources/tableView.lua:397: in function ‘touch’

I/Corona  (11040):      /data/data/com.masterboltdevelopment.sdzAdmin/files/coronaResources/tableView.lua:913: in function ‘func’

I/Corona  (11040):      /Users/jenkins/slaveroot/workspace/Templates/label/android/platform/resources/init.lua:195: in function </Users/jenkins/slaveroot/workspace/Templates/label/android/platform/resources/init.lua:182>

I/Corona  (11040): applicationExit or applicationSuspend: db closed

It “appears” to be when there is a partial row displayed at the bottom, though I’m not touching it on the scroll.  I seem to remember that there was an error related to that some time ago.   I’m on 2017.3068, though I just updated today.  Prior I was on 2017.3068 and it also happened there.

my code: in the onTouch listener

local function onFromRowTouch(event) local phase = event.phase local row = event.target local id = row.index local t = row.params.rowSlot local iNew = false fromRowSelectedPair = row.params.pairCode or "" fromRowSelectedID = row.params.rowDataID resetFromTable() -- set all arrayElements to untouched print("done reset") if (t and t ~= 0) then print("got rowSlot") if (fromTable[t] == false) then iNew = true else iNew = false end print("iNew=",iNew) fromTable[t] = iNew if (fromTable[t] == true) then print("showing selected") row.selOn.isVisible = true row.selOff.isVisible = false else print("showing not selected") row.selOn.isVisible = false row.selOff.isVisible = true end end print("calling reload") deviceTableViewFrom:reloadData() end

the error relates to “attempt to call method ‘setFillColor’ (a nil value)”.  so you need to localise that code

I apologize for sounding foolish here, but the fail is coming from within the widget itself, isnt it?

From tableView.lua widget source:

 if not self.\_targetRow.isCategory then if self.\_targetRow.\_wasTouched then -- Set the row cell's fill color self.\_targetRow.\_cell:setFillColor( unpack( self.\_targetRow.\_rowColor.default ) ) -- The row was no longer touched self.\_targetRow.\_wasTouched = false 

it is a local function (in scope) to the widget’s _cell object.  How do you suggest that I detect that it is missing and localize it?

thanks

Can you post your tableView constructor and your code where you’re inserting rows?

Thanks

Rob

Constructor:

 deviceTableViewFrom = widget.newTableView({ left = dialogBg.x - (dialogBg.width \* 0.5) + (Prefs.margin \* 0.5), top = fromHeaderBg.y + (fromHeaderBg.height \* 0.5) + Prefs.marginBottom, height = tblHeight, width = dialogBg.width - ((Prefs.margin + Prefs.Rmargin) \* 0.5), backgroundColor = {0,0,0,.5}, onRowRender = onFromRowRender, onRowTouch = onFromRowTouch })

Category Insert:

 build\_row = { isCategory = true, rowHeight = Prefs.tableRowHeight \* .667, -- Prefs.tableRowHeight2, rowColor = { default = {0,0,0,1}, over = {1,0,0,0.5} }, lineColor = { 1, 1, 1 }, params = { collapsed = listData[sID].collapsed, title = listData[sID].name, description = "", verified = 0, icon1 = "right-arrow-wht", pairCode = listData[sID].pairCode, text\_color = Prefs.textColorWhite, pairCode = row.pairCode, rowDataID = row.ID, isConnection = true, } } --Insert the connection deviceTableViewFrom:insertRow(build\_row)

Lineitem insert:

 build\_row2 = { isCategory = false, rowHeight = Prefs.tableRowHeight, rowColor = { default = {0,0,0,1}, over = {1,0,0,0.5} }, params = { title = row.lname .. ", " .. row.fname, description = "", goto = "", icon1 = "", text\_color = Prefs.textColorWhite, pairCode = row.pairCode, rowDataID = row.ID, isConnection = true, rowSlot = toTableCount, } }

Thanks, @Rob

Dave

Humor me for a moment if you don’t mind. Remove the rowColor settings and try again. Also try with just setting a single color like:

rowColor = { 1, 1, 1 },

and

rowColor = { default={ 0.8, 0.8, 0.8, 0.8 } }

And see if either of those still generate the error. Your code for the rowColor looks right, but the error is pointing to where we are trying to set the default color. 

Thanks

Rob

Thanks, Rob.

rowColor as a single entry:  significantly reduced the frequency of the fail, though it still came after about 10 up and downs.

                                             does not recognize the color setting in the single table. ie: {1,0,0 } doesnt set it to red.

no rowColor:                        same result as single entry rowColor, though each row is white.

I took out the rowColor on the build_row, and added a newRect in the Render to set the proper color, though that left a single pixel border on the left side (only).  It still crashes if you quickly scroll up and down quickly, multiple times.  However, when using the default and over version, it crashed almost immediately.

Thanks,

Dave

Hi @davida6,

Would it be possible for you to construct the most basic example project showing how it crashes? Then submit that project to us for inspection? I would need to just see a basic TableView crashing under your current method. You could send it to: brent (at) coronalabs (dot) com.

Thanks,

Brent

sent it.

thanks

Hi Dave,

I inspected your project and determined that the crash is because you’re calling “:reloadData()” during the touch (all phases with no conditional filtering). That causes the TableView to think that it has been “reset” and then it registers the ability to re-press the row (even though it’s already pressed) in an endless sequence until you release. During this time, if you slide downward off the row, it crashes.

The typical purpose of “:reloadData()” is a one-time call to refresh the TableView after you’ve changed its intended content around… so you’re not exactly “wrong” to be using it for updating the little red dots in each row, but calling it during the touch phase is causing a sort of recursive loop and a liable crash.

Personally, I would handle this in a more simple way. Instead of doing all of the code with checking “rowSlot” and “iNew” and such, I would just loop through the visible rows of the TableView in the “press” phase of the touch… it’s very important that you filter out which phase of the row touch is being handled!

In the loop, check if the row currently being pressed is the same as the one being referenced by the loop index. If so, turn your little red dot on, and possibly update some other variable you need for tracking which row is selected. For the others, turn off the red dot.

This code shows how you might approach it:

local function onFromRowTouch(event) local phase = event.phase local row = event.target local id = row.index if ( phase == "press" ) then for i = 1,deviceTableViewFrom:getNumRows() do local thisRow = deviceTableViewFrom:getRowAtIndex( i ) if ( thisRow ~= nil and thisRow.isCategory == false ) then if ( id == thisRow.index ) then print( "MARK ROW " .. id .. " AS SELECTED (WITH RED DOT)" ) if ( thisRow.selOn and thisRow.selOff ) then thisRow.selOn.isVisible = true thisRow.selOff.isVisible = false end else if ( thisRow.selOn and thisRow.selOff ) then thisRow.selOn.isVisible = false thisRow.selOff.isVisible = true end end end end end end

Hope this helps somewhat,

Brent

oh, you’re good.

Thanks, Brent.  

Since the press event only comes on a long press, I added tap into the if, which made it appear more responsive.  Some day, I’d like to know how you were able to track and identify this.

Below is what I ended up with.  I left the reset of my table in case you guys ever moved the params out of the view when its de-rendered.

Thanks again.

Dave

 if (phase == "tap" or phase == "press") then resetFromTable() -- set all arrayElements to untouched for i=1, deviceTableViewFrom:getNumRows() do local thisRow = deviceTableViewFrom:getRowAtIndex( i ) if (thisRow ~= nil and thisRow.isCategory == false) then if ( id == thisRow.index ) then fromRowSelectedPair = row.params.pairCode or "" fromRowSelectedID = row.params.rowDataID fromTable[thisRow.params.rowSlot] = true thisRow.selOn.isVisible = true thisRow.selOff.isVisible = false else fromTable[thisRow.params.rowSlot] = false thisRow.selOn.isVisible = false thisRow.selOff.isVisible = true end end end end

That looks reasonable. And yes, usually I use both “tap” and “press” for TableView rows, since some users may not press long enough to trigger the “press”. Note that you can change how long it takes to register a press… default is 110 milliseconds… but you should test carefully because if you shorten it, you might get a “press” when you merely want to slide/drag the view. On the flip side, making it longer than 110 might seem too slow for users who expect a longer press (but then again, making it around 120-150 AND having a tap might be a nice combination… again, you should experiment to see what feels right to you).

https://docs.coronalabs.com/api/library/widget/newTableView.html#rowtouchdelay-optional

the error relates to “attempt to call method ‘setFillColor’ (a nil value)”.  so you need to localise that code

I apologize for sounding foolish here, but the fail is coming from within the widget itself, isnt it?

From tableView.lua widget source:

 if not self.\_targetRow.isCategory then if self.\_targetRow.\_wasTouched then -- Set the row cell's fill color self.\_targetRow.\_cell:setFillColor( unpack( self.\_targetRow.\_rowColor.default ) ) -- The row was no longer touched self.\_targetRow.\_wasTouched = false 

it is a local function (in scope) to the widget’s _cell object.  How do you suggest that I detect that it is missing and localize it?

thanks

Can you post your tableView constructor and your code where you’re inserting rows?

Thanks

Rob

Constructor:

 deviceTableViewFrom = widget.newTableView({ left = dialogBg.x - (dialogBg.width \* 0.5) + (Prefs.margin \* 0.5), top = fromHeaderBg.y + (fromHeaderBg.height \* 0.5) + Prefs.marginBottom, height = tblHeight, width = dialogBg.width - ((Prefs.margin + Prefs.Rmargin) \* 0.5), backgroundColor = {0,0,0,.5}, onRowRender = onFromRowRender, onRowTouch = onFromRowTouch })

Category Insert:

 build\_row = { isCategory = true, rowHeight = Prefs.tableRowHeight \* .667, -- Prefs.tableRowHeight2, rowColor = { default = {0,0,0,1}, over = {1,0,0,0.5} }, lineColor = { 1, 1, 1 }, params = { collapsed = listData[sID].collapsed, title = listData[sID].name, description = "", verified = 0, icon1 = "right-arrow-wht", pairCode = listData[sID].pairCode, text\_color = Prefs.textColorWhite, pairCode = row.pairCode, rowDataID = row.ID, isConnection = true, } } --Insert the connection deviceTableViewFrom:insertRow(build\_row)

Lineitem insert:

 build\_row2 = { isCategory = false, rowHeight = Prefs.tableRowHeight, rowColor = { default = {0,0,0,1}, over = {1,0,0,0.5} }, params = { title = row.lname .. ", " .. row.fname, description = "", goto = "", icon1 = "", text\_color = Prefs.textColorWhite, pairCode = row.pairCode, rowDataID = row.ID, isConnection = true, rowSlot = toTableCount, } }

Thanks, @Rob

Dave

Humor me for a moment if you don’t mind. Remove the rowColor settings and try again. Also try with just setting a single color like:

rowColor = { 1, 1, 1 },

and

rowColor = { default={ 0.8, 0.8, 0.8, 0.8 } }

And see if either of those still generate the error. Your code for the rowColor looks right, but the error is pointing to where we are trying to set the default color. 

Thanks

Rob

Thanks, Rob.

rowColor as a single entry:  significantly reduced the frequency of the fail, though it still came after about 10 up and downs.

                                             does not recognize the color setting in the single table. ie: {1,0,0 } doesnt set it to red.

no rowColor:                        same result as single entry rowColor, though each row is white.

I took out the rowColor on the build_row, and added a newRect in the Render to set the proper color, though that left a single pixel border on the left side (only).  It still crashes if you quickly scroll up and down quickly, multiple times.  However, when using the default and over version, it crashed almost immediately.

Thanks,

Dave

Hi @davida6,

Would it be possible for you to construct the most basic example project showing how it crashes? Then submit that project to us for inspection? I would need to just see a basic TableView crashing under your current method. You could send it to: brent (at) coronalabs (dot) com.

Thanks,

Brent

sent it.

thanks