I am using Lua with gideros
I have the text updating in OnEnterFrame method:
count = count + 1
text7 = TextField.new(conf.fontchange, count)
text7:setPosition(conf.dx - conf.width/3, conf.dy - conf.height/3)
text7:setTextColor(0x000ff)
self:addChild(text7)
but this way the next count is just displayed over the earlier one.
If I do
self:removeChild(text7) , the text is not displayed at all. Where should I be removing the last count so that only the updated count is displayed?
It should be:
text7 = TextField.new(conf.fontchange, count)
text7:setPosition(conf.dx - conf.width/3, conf.dy - conf.height/3)
text7:setTextColor(0x000ff)
self:addChild(text7)
And then later inside ENTER_FRAME event:
count = count + 1
text7:setText(count)
Related
//Sample sheet here
Hi,
I am using formulas to calculate an array N:R. Once calculated, I want to determine the last row of the array with a non-empty cell (the empty cells are not blank).
What I can do so far:
Return the last non-empty cell of a column
=INDEX(FILTER(O:O,O:O<>""), ROWS(FILTER(O:O,O:O<>"")))
or the row of the filter selection (in my case 25 in the filter selection vs 38 in the sheet)
=ROWS(FILTER(O:O,O:O<>""))
What I haven't figured out is how to:
Do this search for the whole array and not just one row at a time
Return the row of the last non-empty cell in the array
Cheers
For a formulaic approach, you can try
=max(filter(row(N2:N), MMULT(N(N2:R<>""), transpose(column(N2:R2)^0))>0))
This custom function will do it. Sometimes scripts are way easier than some of the bizarre formulas that arise (IMHO). It just loops through the data row by row and notes the row number if it finds data ie cell.value() != ""
function findHighestNonEmptyRow(dummyRange){
var sheet = SpreadsheetApp.getActive();
var range = sheet.getRange("N:R");
var valuesRC = range.getValues();
var numRows = range.getNumRows();
var numCols = range.getNumColumns();
var highestNonEmptyRow = 0;
for (var row = 0; row < numRows; row++) {
for (var col = 0; col < numCols; col++) {
if (valuesRC[row][col] != ""){
highestNonEmptyRow = row+1; // +1 to offset loop variable
}
}
}
Logger.log(highestNonEmptyRow);
return highestNonEmptyRow;
}
Log show correct value of 38. You can delete the Logger.log(highestNonEmptyRow); line when you have tested.
I put the formula in W44 in your test sheet....
EDIT: Due to feedback that all was not as expected...
There was a typo in the first script: This line var range =
sheet.getRange("N:D"); should have been var range =
sheet.getRange("N:R");
I found out that Google scripts caches the result of custom
formulas, and just returns the cached value, even if things on the
sheet have changed. This is bizarre behavior, but is intended to
reduce CPU time. The workaround is to pass in a range that is likely
to change, and this causes the function to recalculate. I updated
the formula and the called the function like this:
=findHighestNonEmptyRow(N2:R42)
and hey it all works!
Stick to the formula... however, we both learned a lot from your
question I think, so thanks for that!
How my sheet works
I'm making a spreadsheet to show how much parts I have. By using a dropdown, am I able to show that I created a product. With conditional formatting I am showing that having 0 items isn't an issue when the product is created. Created products with 0 items change from red to purple. Purple means it doesn't matter to have 0 items from this product.
My issue
My issue starts with my dropdown. If I merge cells, The value will go into the upperleft cell. This means other cells inside the merged cell are blank. This gives me a problem with conditional formatting.
My conditional formatting code example:
=if($D2=0;$E2="Created")
I have to change this code for every cell because of the condition combined with a dropdown. Having more than 250 rows would be inhumanly hard to do by hand.
My questions
Are there ways to give all cells of a merged cell the value of the combined cell in an efficient way?
Is there a better way to make my conditional formatting code applyable to merged cells?
This is my sheet
Product items collected sheet link (Shows the problem and solution!)
Product items collected sheet image (Version 1)
Product items collected sheet image (Version 2)
At the heart of this question is the operation of merged cells. When a cell is merged, say over several rows, only the cell at the top left of the merged cell can contain data, respond to conditional formatting, and so on. In a manner of speaking the other cells cease to exist and values CANNOT be assign to them.
The questioner asks:
Q: Are there ways to give all cells of a merged cell the value of the combined cell in an efficient way?
A: No. Not just in an "efficient" way; it's just not possible.
Q: Is there a better way to make my conditional formatting code applicable to merged cells?
A: No and yes ;)
No. In so far as a merged cell is concerned, everything is driven by the value in the top cell of the merged range. There are no other options for the "rest" of the merged cell.
Yes. I'd create a "helper" cells in Column F as in this screenshot
The code to achieve this is dynamic - it will automatically adapt to adding more products, more items, etc.
The logic is fairly simple: Start in F2, test whether E2 has a value (that is, is it the top of the merged cell?). If yes, then assign the value of E2 to F2 AND put that value in a variable for the following cells. If no, the cell in Column E must be part of a merged cell, so assign the value for Column F to the variable that was saved earlier.
function so5270705902() {
// basic declarations
var ss = SpreadsheetApp.getActiveSpreadsheet();
// note this is going to work on the second sheet in the spreadsheet - this can be edited.
var sheet = ss.getSheets()[1];
// Column B contains no merged cells, and always contains data (it is the BOM for the Products).
// so we'll use it to established the last row of data.
var Bvals = sheet.getRange("B1:B").getValues();
var Blast = Bvals.filter(String).length;
// Row 1 is a header row, so data commences in Row 2 - this can be edited
var dataStart = 2;
// Logger.log("the last row in column D = "+Blast);// DEBUG
// set up to loop through the rows of Column F
var mergedcellvalue = "";
for (i = dataStart; i < (Blast + 1); i++) {
// set the range for the row
var range = sheet.getRange(i, 6);
//Logger.log("row#"+i+" = "+range.getA1Notation()); DEBUG
// get the value in column E
var ECell = range.offset(0, -1);
var ECellVal = ECell.getValue();
//Logger.log("offsetrange#"+i+" range value = "+ECellVal);
//Logger.log("Column E, row#"+i+", value = "+ECell.getA1Notation()+" range value = "+ECellVal);//DEBUG
// when a row is merged, on the top row contains any data
// so we'll evaluate to see whether there is any value in this row in Column E
if (ECell.isBlank()) {
//Logger.log("ECell is blank. We're in the middle of the Merged Cell"); ??DEBUG
// Set the value to the lastes value of "mergedcellvalue"
range.setValue(mergedcellvalue);
} else {
//Logger.log("ECell has a value. We're at the top of the merged cell");//DEBUG
// paste the ECellVal into this range
range.setValue(ECellVal);
// Update the "mergedcellvalue" variable so that it can be applied against lower cells of this merged cell
mergedcellvalue = ECellVal;
} // end of the if isblank
} // end of the loop through column F
}
UPDATE 22 October 2018
For development purposes, I used a small range of only 14 rows in Column E. However the questioner's data covers over 250 rows, so I expanded development testing to cover 336 rows (yeah, I know, but I was copy/pasting and I ended up with 336 and was too lazy to delete any rows. OK?). I found that the code took over 81 seconds to process. Not good.
The primary reason (about 80 seconds worth) for the long processing time is that there is a getValue statement within the loop - var ECellVal = ECell.getValue();. This costs about 0.2 seconds per instance. Including getValue in a loop is a classic performance mistake. My bad. So I modified the code to get the values of Column E BEFORE the loop
var Evals = sheet.getRange("e2:E").getValues();.
I was surprised when the execution time stayed around the same mark. The reason was that the isBlank evaluation - if (ECell.isBlank()) { which previously took no time at all, was now consuming #0.2 second per instance. Not good++. So after searching Stack Overflow, I modified this line as follows:
if (!Evals[(i-dataStart)][0]) {.
Including setValues in a loop is also asking for trouble. An option would have been to write the values to an array and then, after the loop, update the Column E values with the array. However in this case, the execution time doesn't seem to have suffered and I'm leaving the setValues inside the loop.
With these two changes, total execution time is now 1.158 seconds. That's a percentage reduction of , um, a LOT.
function so5270705903() {
// basic declarations
var ss = SpreadsheetApp.getActiveSpreadsheet();
// note this is going to work on the second sheet in the spreadsheet - this can be edited.
var sheet = ss.getSheets()[2];
// Column B contains no merged cells, and always contains data (it is the BOM for the Products).
// so we'll use it to established the last row of data.
var Bvals = sheet.getRange("B1:B").getValues();
var Blast = Bvals.filter(String).length;
// Row 1 is a header row, so data commences in Row 2 - this can be edited
var dataStart = 2;
// Logger.log("the last row in column D = "+Blast);// DEBUG
// set up to loop through the rows of Column F
var mergedcellvalue = "";
// get the values for Column E BEFORE the loop
var Evals = sheet.getRange("e2:E").getValues();
for (i = dataStart; i < (Blast + 1); i++) {
// set the range for the row
var range = sheet.getRange(i, 6);
//Logger.log("row#"+i+" = "+range.getA1Notation()); DEBUG
// get the value in column E
var ECell = range.offset(0, -1);
var ECellVal = Evals[(i - dataStart)][0];
//Logger.log("Column E, row#"+i+", value = "+ECell.getA1Notation()+" range value = "+ECellVal);//DEBU
// when a row is merged, on the top row contains any data
// so we'll evaluate to see whether there is any value in this row in Column E
// instead is isblank, which was talking 0.2 seconds to evaluate, this if is more simple
if (!Evals[(i - dataStart)][0]) {
//Logger.log("ECell is blank. We're in the middle of the Merged Cell"); //DEBUG
// Set the value to the lastes value of "mergedcellvalue"
range.setValue(mergedcellvalue);
} else {
//Logger.log("ECell has a value. We're at the top of the merged cell");//DEBUG
// paste the ECellVal into this range
range.setValue(ECellVal);
// Update the "mergedcellvalue" variable so that it can be applied against lower cells of this merged cell
mergedcellvalue = ECellVal;
} // end of the if isblank
} // end of the loop through column F
}
UPDATE 3 March 2019
The questioner made his final changes to the code. This code is the final solution.
function reloadCreatedCells() {
// Basic declarations.
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Note this is going to work on the second sheet in the spreadsheet - this can be edited.
var sheet = ss.getSheets()[1];
// Column B contains no merged cells, and always contains data (it is the BOM for the Products).
// so we'll use it to established the last row of data.
var D_vals = sheet.getRange("D1:D").getValues();
var D_last = D_vals.filter(String).length;
// First row with data.
var dataStart = 2;
// Set up to loop through the rows of Column H - K.
var mergedcellvalue = "";
// Get the values for Column H - K BEFORE the loop.
var H_K_vals = sheet.getRange("H2:K").getValues();
// How many people we have.
var people = 4;
// The first vertical row.
var rowStart = 12;
// Horizontal rows.
for (var h = 0; h < people; h++) {
// Vertical rows.
for (var v = dataStart; v < D_last; v++) {
// Set the range for the row.
var range = sheet.getRange(v, rowStart + h);
// Logger.log(range.getA1Notation()); //DEBUG
// Get the value in column H - K.
var H_K_Cell = range.offset(0, -people);
// Adding Created and not created values inside L - O.
var H_K_CellVal = H_K_vals[(v - dataStart)][h];
// Logger.log(H_K_Cell.getA1Notation() + ': ' + H_K_CellVal); //DEBUG
// When a row is merged, the value is only inside the top row.
// Therefore, you need to check if the value is empty or not.
// If the value is empty. Place the top value of the merged cell inside the empty cell.
if (!H_K_vals[(v - dataStart)][h]) {
// Logger.log(H_K_Cell.getA1Notation() + ": is blank. We're below the top cell of the merged cell."); //DEBUG
// Set the value to the top cell of the merged cell with "mergedcellvalue".
range.setValue(mergedcellvalue);
} else {
// Logger.log(H_K_Cell.getA1Notation() + ": has a value. We're at the top of the merged cell."); //DEBUG
// Paste the H_K_CellVal into this range.
range.setValue(H_K_CellVal);
// Update the "mergedcellvalue" variable, so that it can be applied against lower cells of this merged cell.
mergedcellvalue = H_K_CellVal;
} // end of the if isblank.
} // End of the vertical row loop.
} // End of the horizontal row loop.
}
I need help with Action Script 2.0
I have this scoreboard system with 2 buttons one to count up to a certain number and the other to count down if i need to.
However, the problem with the count down button.
Count Down button code:
on(release) {
score.text = 0;
score.text = scorebk
_root.scorebk--;
if the score is 9 for example when i count down it adds up 1 and then it counts down normally, also when score is 0 it goes to -1...etc.
I do not want that. how can i stop this button from going to minus? and counts normally.
You just have to check that the value is greater than zero before you decrement:
on(release) {
if(scorebk > 0){
scorebk--;
}
score.text = scorebk;
}
I am doing my first game in Corona SDK and I've been stuck for a while. I am trying to move two display objects, every object has a position property, after every move I update the position property, the problem is if I click again the object it don't show me the updated position.
I created my objects this way:
while count<=16 do
button[count] = display.newImage(count..".png")
button[count].position = count
count = count+1
end
And in my touch handler listener I want to move object 1 and 2:
local c = 1
while c <= 2 do
--HERE I DO THE MOVEMENT, THIS WORKS
transition.to( button[c], { time=200, delta=true, x=100 } )
--HERE I CHANGE THE POSITION
button[c].position = 1000
c = c+1
end
Then if I click again any of the 2 objects the position property was not updated! Thank you!
Little explication: I have an app with 5 textfields, i already got the code to make the avaerage of them. Using floates and giving a variable to each textfield.so, the adding of the value of all the textfield /5 (divided per 5)
My problem is that when a textfield is leaved emptty, its not goona be /5, if user fill in only 4 cells it will be/4 and so on.
Question: how to divide the adding of cells depending in how many cells have content?
I was tryng with textfield.text.length > 0 in an if. But i dont get it
Thanks, hope i was clear.
You could check each textfield and see if the text is NULL or blank (#"")
Use an int to keep track of the number of textfields that have a value.
For example:
int counter = 0;
float total = 0.0;
if([textfield1.text length] > 0)
{
counter++;
float thisValue = [textfield1.text floatValue];
total = total + thisValue;
}
repeat this for all 5 textfields and then divide your total by the counter variable.
You could include the if statement in a loop if you are going to vary the number of text fields or to reduce the amount of coding you do.
EDIT I have changed my answer based on the good suggestions of other to use text.length
try to count the number of used textfields by increasing a number every time you read out a textfield that has valid text in it and divide the result by that number. (logically the "number" should be initialized as 0)