Android: Connecting buttons to the java file through a for loop - for-loop

I'm trying to create a chess game for Android and would like to avoid having to declare every button when they are all named so similarly. I tried to generate all of the A + Num button using this for loop.
int RowNum ;
for (RowNum = 1; RowNum < 8; RowNum++) {
String Position = "A" + RowNum;
Button Position = (Button)findViewById(R.id.Position);
}
But I have an error: Variable 'Position' is already defined in the scope.
I would really appreciate if someone could explain to me the best way to go about doing this.
Thanks in advance.

R.Id.A1, R.id.A2, etc. are identifiers and each of them is mapped to a single integer during compilation of R class. Thus, you cannot manipulate the 'R.id.sth' as a string because it will not compile properly.
A way to solve that is search for the string in resources dynamically with a code like this:
Button[] buttons=new Button[8];
for(int RowNum=0; RowNum<8; RowNum++) {
String buttonID = "A"+(RowNum+1);
int resID = getResources().getIdentifier(buttonID, "id", getPackageName());
buttons[RowNum] = ((Button) findViewById(resID));
}
Alternatively, to avoid the time overhead of dynamic search you can add a resource array:
int[] butIds = {R.id.A1, R.id.A2,...};
Button[] buttons= new Button[8];
for(int RowNum=0; RowNum<8, RowNum++) {
buttons[RowNum]= ((Button) findViewById(butIds[RowNum]));
}
You can even store the resource array in XML form and retrieve it as a TypedArray.

You called your String and Button object both Position. Give them different names, e.g.
for (int RowNum = 1; RowNum < 8; RowNum++) {
String currentPosition = "A" + RowNum;
//Why doesn this not use the Position (now 'currentPosition' variable)?
Button currentButton = (Button)findViewById(R.id.Position);
}
Semantically I still don't get that piece of code because Position is not used within the argument of findViewById, to which you pass a static variable R.id.Position.

Related

office script - range find - return row or array to power automate

I have been trying several different ways to write an office script to search for a value in a cell and return the row or rows to power automate.
I believe I need to use range.find in order to make use of the "completematch: true" option.
However, I have also tried a filter and a foreach loop to find rows which include the text I am searching for.
I'm after a hint as to which method might be best?
essentially trying to:-
power automate - pass text parameter to the script
Scripts search for a match in excel business spreadsheet
the script finds match(s)
Script passes back the row(s) to powerautomate as an array
this is what I have so far: essentially it just finds the row number in which the matching result is found. This seems to work better to avoid partial matched (as happened with the filter method )
any pointers, most welcome
function main(workbook: ExcelScript.Workbook, siteNameToFilter: string) {
let activeSheet = workbook.getActiveWorksheet();
let range = activeSheet.getUsedRange();
let values = range.getValues();
/**
* This script searches for the next instance of the text "Fino" on the current worksheet.
*/
// Get the next cell that contains "Fino".
let findCell = range.find("Fino", {
completeMatch: true, /* Don't match if the cell text only contains "fino" as part of another string. */
matchCase: false,
searchDirection: ExcelScript.SearchDirection.forward /* Start at the beginning of the range and go to later columns and rows. */
});
// Set focus on the found cell.
findCell.select();
// Remove the "TK" text value from the cell, as well as any formatting that may have been added.
//tkCell.clear(ExcelScript.ClearApplyTo.all);
let row = findCell.getRow().getUsedRange();
let ur = findCell.getUsedRange();
console.log(row);
}
I think Find may only be returning the first match. It sounds like you want all matches with the siteName. To do this, you'd either want to filter the range or loop through it.
Here's an example that loops through the range and adds the values from the rows containing the site name to an array. After the loop's completed, the array containing the values is returning by the function:
function main(workbook: ExcelScript.Workbook, siteNameToFilter: string) {
let activeSheet = workbook.getActiveWorksheet();
let range = activeSheet.getUsedRange()
let values = range.getValues() as string[][];
let rowCount = range.getRowCount()
let colCount = range.getColumnCount()
let colIndex = range.getColumnIndex()
let rowsArr: string[][][] = []
for (let i = 0; i < rowCount; i++) {
for (let j = 0; j < colCount; j++) {
if (values[i][j] === siteNameToFilter) {
rowsArr.push(activeSheet.getRangeByIndexes(i, colIndex, 1, colCount).getValues() as string[][])
}
}
}
return rowsArr
}

trying to figure out why a for each statement worked with an if statement, but throws an exception when i switch it to a for loop

Sorry in advance, as I have only been working with C# for about a month with limited history in VB years ago. It's a Mail merge kind of loop that I am trying to create for work to make their life easier. I have the dates figured out. I have a NumUpDown control setting the int myInt, and a formCount int starting at 0.
The code worked fine when I used if(formCount==0), when I switched it to
for(formCount=0;formCount<myInt;formCount++)
it now throws a
"System.NullReferenceException: 'Object reference not set to an
instance of an object.'"
I know there is probably another way to do what I am working on which is to just add sequential dates to forms a month at a time. I have the dates stored in an array myDate[31].
I am using the numUpDwn(min 1 max 31) to get myInt so we can select how many days in the month, or only print a couple days if we need to replace pages, so we can print anywhere from 1 to 31 pages.
With the if statement it would create the first page from the template (.dotx) to doc(var) copy the contents of doc to doc2 and add a new page to receive the next content paste.
I am sure this is a silly question, that someone will have a simple answer too. The loop is supposed to open the template, add the date, copy to doc2. close the original, and restart until it reached the number of pages/dates selected. Thanks for any help, this is the last section I need to finish and I am stumped. Oh, and I used the != because it was skipping the merge field, but with only 1 field not equal to anything worked.
private void BtnPrint_Click(object sender, EventArgs e)
{
var app = new Microsoft.Office.Interop.Word.Application();
var doc = new Microsoft.Office.Interop.Word.Document();
var doc2 = new Microsoft.Office.Interop.Word.Document();
//app.Visible = true;
doc = null;
doc2.PageSetup.Orientation = WdOrientation.wdOrientLandscape;
doc2.PageSetup.TopMargin = app.InchesToPoints(0.6f);
doc2.PageSetup.BottomMargin = app.InchesToPoints(0.17f);
doc2.PageSetup.LeftMargin = app.InchesToPoints(0.5f);
doc2.PageSetup.RightMargin = app.InchesToPoints(0.5f);
String fileSave;
fileSave = ("OTSU" + "_" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
int formCount;
//formCount = 0;
var filepath = System.Windows.Forms.Application.StartupPath + outfile;
doc = app.Documents.Add(filepath);
doc2.Activate();
//OBJECT OF MISSING "NULL VALUE"
Object oMissing = System.Reflection.Missing.Value;
for (formCount = 0; formCount<myInt;formCount++)
{
doc.Activate();
foreach (Microsoft.Office.Interop.Word.Field field in doc.Fields)
{
Range rngFieldCode = field.Code;
String fieldText = rngFieldCode.Text;
// ONLY GETTING THE MAILMERGE FIELDS
if (fieldText.StartsWith(" MERGEFIELD"))
{
Int32 endMerge = fieldText.IndexOf("\\");
Int32 fieldNameLength = fieldText.Length - endMerge;
String fieldName = fieldText.Substring(11);
// GIVES THE FIELDNAMES AS THE USER HAD ENTERED IN .dotx FILE
fieldName = fieldName.Trim();
if (fieldName != "M_2nd__3rd")
{
field.Select();
app.Selection.TypeText(myDate[formCount].ToShortDateString());
}
formCount++;
Microsoft.Office.Interop.Word.Range dRange = doc.Content;
dRange.Copy();
doc2.Range(doc2.Content.End - 1, doc2.Content.End - 1).PasteSpecial(DataType: Microsoft.Office.Interop.Word.WdPasteOptions.wdKeepSourceFormatting);
doc2.Range(doc2.Content.End - 1, doc2.Content.End - 1).InsertBreak(Microsoft.Office.Interop.Word.WdBreakType.wdPageBreak);
Clipboard.Clear();
doc.Close(WdSaveOptions.wdDoNotSaveChanges);
}
}
}
doc2.SaveAs2("OTSU" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
app.Documents.Open("OTSU" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
doc.Close(WdSaveOptions.wdDoNotSaveChanges);
doc2.Close(WdSaveOptions.wdDoNotSaveChanges);
I haven’t run your code, but as far as I can see, this code would probably fail even without the formcount loop in the situation where you have more than one MERGEFIELD field because you close doc As soon as you have processed such a field, and yet the foreach loop is processing each Field in doc.Fields.
Even if that foreach loop terminates gracefully, in the next iteration of the formCount loop you are using doc.Activate(), but doc has closed so that will fail.
So I suggest that the main thing to do is consider which documents need to be open at which point for the process to work.
Some observations (not necessarily to do with your primary question)
where is myInt set?
is having a formCount++ loop and using formCount++ within the loop for every MERGEFIELD in doc Really your intention?
you might be better off testing field.Type() when filtering MAILMERGE fields rather than matching the text, at least if such fields can be set up by end users
when you process collections in Word and you are either adding or deleting members of the collection, you sometimes have to consider using a loop that starts with last member of the collection and works back towards the beginning. Not sure you need to do that in this case but since you may be “deleting” when you do your field.Select then Typetext, please bear that in mind
It may seem like a complication when you are mainly trying to sketch out the logic of your loops, but I generally find it very helpful to start using try...catch...finally blocks sooner rather than later during development.
I did find a solution for now. Since there is only one MERGFIELD, instead of trying to open doc, insert date, copy to new doc2, close doc, repeat I found I can open, insert date, copy to new doc2, undo edit on doc and repeat. At least it works for now, and I can get back to the books and learn some more while I map out the big project I have planned. I am sure I will be on here a bit with more questions. Without #slightly-snarky asking the questions he did, I wouldn't have thought of this so I have to give them credit for the answer. I did have to put the doc.Undo(); at the top of the loop and it will only work with one field. But its a start.
private void BtnPrint_Click(object sender, EventArgs e)
{
var app = new Microsoft.Office.Interop.Word.Application();
String fileSave;
fileSave = ("OTSU" + "_" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
int formCount;
formCount = 0;
var filepath = System.Windows.Forms.Application.StartupPath + outfile;
var doc = new Microsoft.Office.Interop.Word.Document();
doc = app.Documents.Add(filepath);
app.Visible = true;
doc.Activate();
var doc2 = new Microsoft.Office.Interop.Word.Document();
doc2.PageSetup.Orientation = WdOrientation.wdOrientLandscape;
doc2.PageSetup.TopMargin = app.InchesToPoints(0.6f);
doc2.PageSetup.BottomMargin = app.InchesToPoints(0.17f);
doc2.PageSetup.LeftMargin = app.InchesToPoints(0.5f);
doc2.PageSetup.RightMargin = app.InchesToPoints(0.5f);
doc2.Activate();
//OBJECT OF MISSING "NULL VALUE"
Object oMissing = System.Reflection.Missing.Value;
for (formCount = 0; formCount < myInt; formCount++)
{
doc.Undo();
foreach (Microsoft.Office.Interop.Word.Field field in doc.Fields)
{
Range rngFieldCode = field.Code;
String fieldText = rngFieldCode.Text;
// ONLY GETTING THE MAILMERGE FIELDS
if (fieldText.StartsWith(" MERGEFIELD"))
{
Int32 endMerge = fieldText.IndexOf("\\");
Int32 fieldNameLength = fieldText.Length - endMerge;
String fieldName = fieldText.Substring(11);
// GIVES THE FIELDNAMES AS THE USER HAD ENTERED IN .dotx FILE
fieldName = fieldName.Trim();
if (fieldName != "M_2nd__3rd")
{
field.Select();
app.Selection.TypeText(myDate[formCount].ToShortDateString());
}
Microsoft.Office.Interop.Word.Range dRange = doc.Content;
dRange.Copy();
doc2.Range(doc2.Content.End - 1, doc2.Content.End - 1).PasteSpecial(DataType: Microsoft.Office.Interop.Word.WdPasteOptions.wdKeepSourceFormatting);
doc2.Range(doc2.Content.End - 1, doc2.Content.End - 1).InsertBreak(Microsoft.Office.Interop.Word.WdBreakType.wdPageBreak);
Clipboard.Clear();
}
}
}
doc2.SaveAs2("OTSU" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
doc.Close(WdSaveOptions.wdDoNotSaveChanges);
doc2.Close(WdSaveOptions.wdDoNotSaveChanges);
app.Documents.Open("OTSU" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
}
}
}

How to populate the table dynamically and correctly with Ajax?

I have a form where the user submits a query and then have a Servlet that processes this query and returns the results in XML. With this result trying to populate a table dynamically via Ajax, for such, I use the following code below.
var thead = $("<thead>");
var rowsTHead = $("<tr>");
var tbody = $("<tbody>");
var numberOfColumns;
$(xml).find("head").each(function(){
var variable = $(this).find("variable");
numberOfColumns = variable.length;
for (var i = 0; i < variable.length; i++){
var name = $(variable[i]).attr("name");
rowsTHead.append($("<th>").html(name));
}
});
thead.append(rowsTHead);
$(xml).find("result").each(function(){
var literal = $(this).find("literal");
var rowsTBody = $("<tr class=\"even\">");
literal.length = numberOfColumns;
for (var j = 0; j < literal.length; j++){
var tdBody = $("<td>");
tdBody.html($(literal[j]).text());
rowsTBody.append(tdBody);
}
tbody.append(rowsTBody);
});
$(".tablesorter").empty()
.append(thead)
.append(tbody);
This code works perfectly until it was used in a UNION query. When using a UNION the returned xml comes in the following way http://pastebin.com/y7hXK1Zy
As can be observed, this query has 4 variables that are: gn1, indication1, gn2, indication2.
What is going wrong is that the values of all the variables being written in columns corresponding to gn1 and indication1.
What I wish I was to write the value of each variable in its corresponding column. I wonder what should I change in my code to make this possible.
You need to respect the name values of the binding elements, and relate them back to the columns that you correctly built from parsing the element. When you are doing the find "literal", you are skipping the parsing of the binding elements. You should find "binding", respect the name and look up which column to use based on that, and then for each of those, find the "literal" elements for the actual values.

Using an array in select expert, is it possible?

I currently have the following in select expert to select a bunch of fields:
{Order.OrderDate} in {?Start date} to {?End date} and
{Order.PostingCode} in ["j500", "j501", "j502"]
I am having to add from j500 all the way up to j713.
Is it possible to point it to a string array?
For example, in java:
int count = 0;
int fieldnumber = 500;
String[] fieldarray = new String[214];
while (count < 214){
System.out.println("j"+fieldnumber);
fieldarray[count] = "j"+fieldnumber;
fieldnumber++;
count++;
}
So in crystal I could just point crystal at the "fieldarray" string array and say use everything in there. Is that possible with crystal? If so, how?
Thanks guys.
why not use:
{Order.OrderDate} in {?Start date} to {?End date} and
{Order.PostingCode} >= "j500" and
{Order.PostingCode} <= "j713"

Paging a collection with LINQ

How do you page through a collection in LINQ given that you have a startIndex and a count?
It is very simple with the Skip and Take extension methods.
var query = from i in ideas
select i;
var paggedCollection = query.Skip(startIndex).Take(count);
A few months back I wrote a blog post about Fluent Interfaces and LINQ which used an Extension Method on IQueryable<T> and another class to provide the following natural way of paginating a LINQ collection.
var query = from i in ideas
select i;
var pagedCollection = query.InPagesOf(10);
var pageOfIdeas = pagedCollection.Page(2);
You can get the code from the MSDN Code Gallery Page: Pipelines, Filters, Fluent API and LINQ to SQL.
I solved this a bit differently than what the others have as I had to make my own paginator, with a repeater. So I first made a collection of page numbers for the collection of items that I have:
// assumes that the item collection is "myItems"
int pageCount = (myItems.Count + PageSize - 1) / PageSize;
IEnumerable<int> pageRange = Enumerable.Range(1, pageCount);
// pageRange contains [1, 2, ... , pageCount]
Using this I could easily partition the item collection into a collection of "pages". A page in this case is just a collection of items (IEnumerable<Item>). This is how you can do it using Skip and Take together with selecting the index from the pageRange created above:
IEnumerable<IEnumerable<Item>> pageRange
.Select((page, index) =>
myItems
.Skip(index*PageSize)
.Take(PageSize));
Of course you have to handle each page as an additional collection but e.g. if you're nesting repeaters then this is actually easy to handle.
The one-liner TLDR version would be this:
var pages = Enumerable
.Range(0, pageCount)
.Select((index) => myItems.Skip(index*PageSize).Take(PageSize));
Which can be used as this:
for (Enumerable<Item> page : pages)
{
// handle page
for (Item item : page)
{
// handle item in page
}
}
This question is somewhat old, but I wanted to post my paging algorithm that shows the whole procedure (including user interaction).
const int pageSize = 10;
const int count = 100;
const int startIndex = 20;
int took = 0;
bool getNextPage;
var page = ideas.Skip(startIndex);
do
{
Console.WriteLine("Page {0}:", (took / pageSize) + 1);
foreach (var idea in page.Take(pageSize))
{
Console.WriteLine(idea);
}
took += pageSize;
if (took < count)
{
Console.WriteLine("Next page (y/n)?");
char answer = Console.ReadLine().FirstOrDefault();
getNextPage = default(char) != answer && 'y' == char.ToLowerInvariant(answer);
if (getNextPage)
{
page = page.Skip(pageSize);
}
}
}
while (getNextPage && took < count);
However, if you are after performance, and in production code, we're all after performance, you shouldn't use LINQ's paging as shown above, but rather the underlying IEnumerator to implement paging yourself. As a matter of fact, it is as simple as the LINQ-algorithm shown above, but more performant:
const int pageSize = 10;
const int count = 100;
const int startIndex = 20;
int took = 0;
bool getNextPage = true;
using (var page = ideas.Skip(startIndex).GetEnumerator())
{
do
{
Console.WriteLine("Page {0}:", (took / pageSize) + 1);
int currentPageItemNo = 0;
while (currentPageItemNo++ < pageSize && page.MoveNext())
{
var idea = page.Current;
Console.WriteLine(idea);
}
took += pageSize;
if (took < count)
{
Console.WriteLine("Next page (y/n)?");
char answer = Console.ReadLine().FirstOrDefault();
getNextPage = default(char) != answer && 'y' == char.ToLowerInvariant(answer);
}
}
while (getNextPage && took < count);
}
Explanation: The downside of using Skip() for multiple times in a "cascading manner" is, that it will not really store the "pointer" of the iteration, where it was last skipped. - Instead the original sequence will be front-loaded with skip calls, which will lead to "consuming" the already "consumed" pages over and over again. - You can prove that yourself, when you create the sequence ideas so that it yields side effects. -> Even if you have skipped 10-20 and 20-30 and want to process 40+, you'll see all side effects of 10-30 being executed again, before you start iterating 40+.
The variant using IEnumerable's interface directly, will instead remember the position of the end of the last logical page, so no explicit skipping is needed and side effects won't be repeated.

Resources