I'm following this question for formatting timespan value in the gridview.
Format TimeSpan in DataGridView column
I'm diaplying only minutes value in grid as follows
DataGridViewColumn idleTimeColumn = myGridView.Columns["IdleTime"];
idleTimeColumn.DefaultCellStyle.FormatProvider = new TimeSpanFormatter();
idleTimeColumn.DefaultCellStyle.Format = "m";
This cell is editable, so when I enter 5 (that mean 5 min) in the cell, then it should take it minute, but it take it as day value (ie, 5.00:00:00).
I tried different values for format (mm,%m) but all these gives the same output.
You have to implement the feature to parse an input value.
TimeSpanFormatter can be used to convert a bound TimeSpan data to a formatted string for displaying. But it can't convert an input value to TimeSpan. You have to convert an input value in DataGridView.CellParsing event handler.
The following is the sample code to parse an input value.
DataGridView.CellParsing event handler
private void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
{
if (e.DesiredType == typeof(TimeSpan))
{
TimeSpanParser parser = new TimeSpanParser();
e.Value = parser.Parse(e.Value.ToString(), e.InheritedCellStyle.Format);
e.ParsingApplied = true;
}
}
TimeSpanParser class
public class TimeSpanParser
{
private Regex formatParser;
private List<TimeSpanPart> parts;
public TimeSpanParser()
{
this.formatParser = new Regex("d{1,2}|h{1,2}|m{1,2}|s{1,2}|f{1,7}", RegexOptions.Compiled);
this.parts = new List<TimeSpanPart>();
}
public TimeSpan Parse(string input, string format)
{
this.parts.Clear();
var pattern = this.formatParser.Replace(format, m => ReplaceFormat(m));
var match = Regex.Match(input, "^" + pattern + "$");
TimeSpan result = new TimeSpan();
for (int i = 1; i < match.Groups.Count; i++)
{
var value = Convert.ToDouble(match.Groups[i].Value);
switch (this.parts[i - 1])
{
case TimeSpanPart.Day:
result = result.Add(TimeSpan.FromDays(value));
break;
case TimeSpanPart.Hour:
result = result.Add(TimeSpan.FromHours(value));
break;
case TimeSpanPart.Minute:
result = result.Add(TimeSpan.FromMinutes(value));
break;
case TimeSpanPart.Second:
result = result.Add(TimeSpan.FromSeconds(value));
break;
case TimeSpanPart.Millisecond:
int digit = match.Groups[i].Value.Length;
value =value * Math.Pow(10, 3 - digit);
result = result.Add(TimeSpan.FromMilliseconds(value));
break;
}
}
return result;
}
private string ReplaceFormat(Match match)
{
switch (match.Value)
{
case "dd":
case "d":
this.parts.Add(TimeSpanPart.Day);
return "(\\d{1,2})";
case "hh":
case "h":
this.parts.Add(TimeSpanPart.Hour);
return "(\\d{1,2})";
case "mm":
case "m":
this.parts.Add(TimeSpanPart.Minute);
return "(\\d{1,2})";
case "ss":
case "s":
this.parts.Add(TimeSpanPart.Second);
return "(\\d{1,2})";
case "fffffff":
case "ffffff":
case "fffff":
case "ffff":
case "fff":
case "ff":
case "f":
this.parts.Add(TimeSpanPart.Millisecond);
return "(\\d{1,7})";
default:
return match.Value;
}
}
}
TimeSpanPart enum
public enum TimeSpanPart
{
Day,
Hour,
Minute,
Second,
Millisecond,
}
I believe you are handling the cell formatting event properly
Youe were referring this i guess
Try mm or %m instead of m; idleTimeColumn.DefaultCellStyle.Format = "mm";
Related
Tried writing a sort method where input was given like a string of comma-delimited years and year ranges String input = '2017, 2018,2020-2023,1800-1700,2020,20a9,19z5-1990,2025,20261,2013';
Expectation is to get a string of comma-delimited years and year ranges,and remove all duplicates and invalid inputs.
Below is class written which is not giving me correct output
public class sortYearAndYearRangesString {
public static List<String> sortSpecialString(String input) {
system.debug(input);
List<String> inputList = input.split('');
system.debug(inputList);
Map<Integer,String> stringMap = new Map<Integer,String>();
system.debug(stringMap);
List<String> output = new List<String>();
for (Integer i=0; i<inputList.size(); i++) {
String charac = inputList[i];
if(!charac.isAlphaNumeric()) {
system.debug(charac);
stringMap.put(i,charac);
}else {
output.add(charac);
system.debug(output);
}
}
String finalString = String.join(output,'');
system.debug(finalString);
List<String> resultList = finalString.reverse().split('');
for( Integer I : stringMap.keySet() ){
system.debug(I);
resultList.add(I,stringMap.get(I));
system.debug(resultList);
}
return resultList;
}
Tried validating the solution in Anonymous Apex but no success
public static void validateSolution() {
String input = '2017, 2018,2020-2023,1800-1700,2020,20a9,19z5-1990,2025,20261,2013';
List<Integer> expected = new List<Integer> {2013,2017,2018,2020,2021,2022,2023,2025};
List<Integer> actual = sortYearAndYearRangesString(input);
System.assertEquals(expected, actual, 'Invalid Results');
}
}
Your help is appreciated
Regards
Carolyn
According to your test case, you should also define at least a constant for a maximum value, in order to exclude 20261. Probably you need a minimum too.
I used 1700 as min and 4000 as max because these are the limits for a Date or Datatime field: docs
Moreover the method must return a List<Integer> instead of a List<String>.
You don't need a Map, just a Set would work.
public class SortYearAndYearRangesString {
private static final Integer MAX_YEAR = 4000;
private static final Integer MIN_YEAR = 1700;
public static List<Integer> sortSpecialString(String input) {
Set<Integer> output = new Set<Integer>();
List<String> yearsList = input.split(',');
for (String yearString : yearsList) {
yearString = yearString.trim();
if (yearString.isNumeric()) {
try {
Integer year = Integer.valueOf(yearString);
if (year >= MIN_YEAR && year <= MAX_YEAR) {
output.add(year);
}
} catch (TypeException e) {
System.debug(e.getMessage());
}
} else {
List<String> range = yearString.split('-');
if (range.size() == 2 && range[0].isNumeric() && range[1].isNumeric()) {
try {
// Modify the following two lines once you know how to handle range like 1300-1500 or 3950-4150
Integer firstYear = Math.max(Integer.valueOf(range[0]), MIN_YEAR);
Integer lastYear = Math.min(Integer.valueOf(range[1]), MAX_YEAR);
while (firstYear <= lastYear) {
output.add(firstYear++);
}
} catch (TypeException e) {
System.debug(e.getMessage());
}
}
}
}
List<Integer> sortedYears = new List<Integer>(output);
sortedYears.sort();
return sortedYears;
}
}
If a range that exceed the boundaries (like 1300-1500 or 3950-4150) should be treated as invalid and skipped, please change these lines
Integer firstYear = Math.max(Integer.valueOf(range[0]), MIN_YEAR);
Integer lastYear = Math.min(Integer.valueOf(range[1]), MAX_YEAR);
while (firstYear <= lastYear) {
output.add(firstYear++);
}
as follow:
Integer firstYear = Integer.valueOf(range[0]);
Integer lastYear = Integer.valueOf(range[1]);
if (firstYear >= MIN_YEAR && lastYear <= MAX_YEAR) {
while (firstYear <= lastYear) {
output.add(firstYear++);
}
}
I tested it in anonymous console with the following code:
String input = '2017, 2018,2020-2023,1800-1700,2020,20a9,19z5-1990,2025,20261,2013';
List<Integer> expected = new List<Integer> {2013,2017,2018,2020,2021,2022,2023,2025};
List<Integer> actual = SortYearAndYearRangesString.sortSpecialString(input);
System.debug(actual);
System.assertEquals(expected, actual, 'Invalid Results');
input = '1500,2017, 2018,2020-2023,1800-1700,2020,20a9,19z5-1990,2025,20261,2013,3998-4002';
expected = new List<Integer> {2013,2017,2018,2020,2021,2022,2023,2025,3998,3999,4000};
actual = SortYearAndYearRangesString.sortSpecialString(input);
System.assertEquals(expected, actual, 'Invalid Results');
I made some changes to the class.
It does increment all ranges - and doesn't check if they're years that would make sense. You'll need to add that logic in there (e.g. 1500-1600 would return all years between 1500-1600. Prob best to cap at 1900 or something)
public class SortYearAndYearRangesString{
public static List<Integer> sortSpecialString(String input){
List<String> inputList = input.split(',');
Set<Integer> output = new Set<Integer>();
system.debug('input ' + input);
system.debug('inputList ' + inputList);
for (String s : inputList){
Set<Integer> tempSet = new Set<Integer>();
s.remove(' ');
if (s.contains('-')){
//// break the ranges and fill in years
List<String> tempSet2 = s.split('-');
for (String s2 : tempSet2){
try{
///capture valid integers
Integer tempInt = Integer.valueOf(s2);
tempSet.add(tempInt);
} catch (Exception e){
tempSet.clear();
break;
}
}
System.debug('set ' + tempSet);
if (tempSet.size() > 1){
List<Integer> tempList = new List<Integer>(tempSet);
tempList.sort ();
Integer r = tempList.size() - 1;
// iterate through the years
for (Integer i = tempList.get(0); i < tempList.get(r); i++){
tempSet.add(i) ;
}
}
} else{
try{
///capture valid integers
Integer tempInt = Integer.valueOf(s);
tempSet.add(tempInt);
} catch (Exception e){
continue;
}
}
output.addAll(tempSet);
}
// output is currently set of ints, need to convert to list of integer
List<Integer> finalOutput = new List<Integer>(output);
finalOutput.sort ();
System.debug('finalOutput :' + finalOutput);
return finalOutput;
}}
I have a gameObject with an ID, the gameObjects are spawned by giving initial ID: 1 , then any after spawned will be +1 so next is ID: 2.
I have two buttons that check current gameObjects ID#, BackOneButton (-1) and PlusOneButton (+1).
Currently it works but only if the array of gameObjects have IDs in order like for example [gameObject-ID:1], [gameObject-ID:2], [gameObject-ID:3]
But since you can self destruct a certain gameObject, here is where the error is --->
Now the array is not in order for example [gameObject-ID:1], [gameObject-ID:3], [gameObject-ID:4]. So if I'm currently in [gameObject-ID:3] and I use the BackOneButton and looks for ID: 2 it won't find it BUT there is ID:1. That's my error, I can't seem to figure out how to handle this.
Basically, How do I handle missing increments and skip over the missing?
Left Button (MinusOneButton)
void ButtonAction_LeftMinusOne()
{
// Get list of all gameObjects and -1 current to switch
string objName = manager.currentObjectTransform.name;
string[] splitArray = objName.Split('_');
string idObjNumber = splitArray[1];
switch (idObjNumber)
{
case "0":
// not supposed to be ID: 0
break;
case "1":
// nothing to go back to, this is ID: 1
break;
default:
// currently in (ID: 2 & Up) second object
int currentID = int.Parse(idObjNumber);
string idBackOne = (currentID - 1).ToString();
GameObject[] allObjInFull = GameObject.FindGameObjectsWithTag("Object");
if (allObjInFull.Length >= 2)
{
for (int i = 0; i < allObjInFull.Length; i++)
{
if (allObjInFull[i].transform.name.Contains(idBackOne))
{
// Set Camera
camera.transform.parent = allObjInFull[i].transform.GetChild(0).GetChild(1);
camera.transform.position = allObjInFull[i].transform.GetChild(0).GetChild(1).position;
camera.transform.rotation = allObjInFull[i].transform.GetChild(0).GetChild(1).rotation;
}
}
}
break;
}
}
Right Button (PlusOneButton)
void ButtonAction_RightPlusOne()
{
// Get list of all objects and +1 current to switch
string objName = manager.currentObjectTransform.name;
string[] splitArray = objName.Split('_');
string idObjNumber = splitArray[1];
switch (idObjNumber)
{
case "0":
// not supposed to be ID: 0
break;
default:
// currently in (ID: 1 & Up) object
int currentID = int.Parse(idObjNumber);
string idPlusOne = (currentID + 1).ToString();
GameObject[] allObjInFull = GameObject.FindGameObjectsWithTag("Object");
if (allObjInFull.Length >= 2)
{
for (int i = 0; i < allObjInFull.Length; i++)
{
if (allObjInFull[i].transform.name.Contains(idPlusOne))
{
// Set Camera
camera.transform.parent = allObjInFull[i].transform.GetChild(0).GetChild(1);
camera.transform.position = allObjInFull[i].transform.GetChild(0).GetChild(1).position;
camera.transform.rotation = allObjInFull[i].transform.GetChild(0).GetChild(1).rotation;
}
}
}
break;
}
}
It would be way better (especially regarding maintenance) and more efficient to have a central manager class with a List<GameObject> where you simply Add and Remove items dynamically. (Since you already seem to have one in manager I would rather extend that one)
public static class ObjectsManager
{
// If you are not concerned about
// capsulation you could ofcourse make this public as well
// but I thought this is cleaner
private static List<GameObject> objects;
// Read-only property
public static int Count
{
get
{
Initialize();
return objects.Count;
}
}
// initialize the list once
// I first had this in e.g. Awake
// but now you can easily use this in multiple scenes
public static void Initialize(bool force reinitialize = false)
{
if(objects != null && ! reinitialize) return;
objects = FindObjectsWithTag("Object").ToList();
}
public static void Add(GameObject newObject)
{
Initialize();
if(objects.Contains(newObject) return;
objects.Add(newObject);
}
public static void Destroy(GameObject toDestroy)
{
Initialize();
if(objects.Contains(toDestroy)
{
objects.Remove(toDestroy);
}
Object.Destroy(toDestroy);
}
public static int IndexOf(GameObject obj)
{
Initialize();
return objects.IndexOf(obj);
}
public static GameObject GetByIndex(int index)
{
Initialize();
// Use modulo to wrap around the index in case
// +1 or -1 exceeds the list ends
// in your case you might not need it
// but I decided to add it to be more flexible
var nextIndex = (index + 1) % objects.Count;
return objects[index];
}
}
Everytime you Instantiate a new object make sure to also call
ObjectsManager.Add(newObject);
and everytime where you destroy an object rather use
ObjectsManager.Destroy(objectToDestroy);
so it is also removed from the list first.
Then you can easily use
var currentIndex = ObjectsManager.IndexOf(certainObject);
to get the current index of an object and simply move through the index (+1, -1)
var nextObject = ObjectsManager.GetByIndex(currentIndex + 1);
var lastObject = Objects manager.GetByIndex(currentIndex - 1);
In case you switch the scene you have reinitialize the list once in order to get rid of null references
ObjectsManager.Initialize(true);
In your example code you would e.g. use something like
void ButtonAction_LeftMinusOne()
{
GameObject currentObject = manager.currentObjectTransform.gameObject;
int currentIndex = ObjectsManager.IndexOf(currentObject);
if(currentIndex < 0)
{
Debug.LogErrorFormat(this, "Object {0} is not in list!", currentObject.name);
return;
}
if(currentIndex == 0)
{
// nothing to do go back to
// Except you want wrap around then simply remove this check
Debug.Log("Already is first object in list", this);
return;
}
GameObject newObject = ObjectsManager.GetByIndex(currentIndex - 1);
Transform childOfNewObject = newObject.GetChild(0).GetChild(1);
// Set Camera
// Using simply SetParent with parameter worldPositionStays=false
// reduces it to one single call
camera.transform.SetParent( childOfNewObject, false);
}
And accordingly
void ButtonAction_RightPlusOne()
{
GameObject currentObject = manager.currentObjectTransform.gameObject;
int currentIndex = ObjectsManager.IndexOf(currentObject);
if(currentIndex < 0)
{
Debug.LogErrorFormat(this, "Object {0} is not in list!", currentObject.name);
return;
}
if(currentIndex == ObjectsManager.Count - 1)
{
// nothing to do go forward to
// Except you want wrap around then simply remove this check
Debug.Log("Already is last object in list", this);
return;
}
GameObject newObject = ObjectsManager.GetByIndex(currentIndex + 1);
Transform childOfNewObject = newObject.GetChild(0).GetChild(1);
// Set Camera
// Using simply SetParent with parameter worldPositionStays=false
// reduces it to one single call
camera.transform.SetParent( childOfNewObject, false);
}
This question is specific for Codename One and it's about if my following code is a good-code or if there are better strategies.
This is my use case:
with a REST request, I get a database table as a list of DAOs (each DAO is row) serialized by JSON;
the client has a ServerAPI class with a method that returns the server response as List<SportTypeDAO>;
each SportTypeDAO is implemented as a PropertyBusinessObject;
I want to show a Form with a Table object that allows the user the view all the table and to modify some fields (and to add rows, but I didn't implemented this yet);
the Table will be serialized as JSON to send the modified table to the server.
The problems:
a Property can be easily binded to a TextField or to a InputComponent, but I don't know any default easy way to bind a PropertyBusinessObject to a row of a Table... or even to bind a List<PropertyBusinessObject> to a Table;
the Table uses internally a createCell method that uses the data passed to the TableModel to create each cell as Label or TextField (according to the fact that the cell is editable or not), so I cannot directly insert in the table TextFields binded to Properties.
I tried to solve the problem in the following way... but there is a lot of code for an easy conceptual task (bind a List<PropertyBusinessObject> to a Table)... is there any better approch? I have to do the same task for a lot of tables, and I'm worried to find a good solution that can be generalized as most as possible.
public class FormSportType extends BaseForm {
private static List<SportTypeDAO> listToShow = null;
public FormSportType() {
super("FormSportType", BoxLayout.y());
fillForm();
}
public FormSportType(Form backForm) {
super("FormSportType", BoxLayout.y());
addBackCommand(backForm);
fillForm();
}
private void fillForm() {
add(new Label("FormSportType"));
UiBinding uib = new UiBinding();
if (listToShow == null) {
listToShow = serverAPI.readSportType();
}
int rows = listToShow.size();
int colums = 5;
Object[][] dataArray = new Object[rows][colums];
for (int row = 0; row < rows; row++) {
for (int column = 0; column < colums; column++) {
String cell = "";
switch (column) {
case 0:
cell = listToShow.get(row).keyword.get();
break;
case 1:
cell = listToShow.get(row).text_IT.get();
break;
case 2:
cell = listToShow.get(row).text_EN.get();
break;
case 3:
cell = listToShow.get(row).position.get().toString();
break;
case 4:
cell = listToShow.get(row).dbAction.get().toString();
break;
}
dataArray[row][column] = cell;
}
}
TableModel model = new DefaultTableModel(new String[]{"Keyword", "Text_IT", "Text_EN", "Position", "DbAction"}, dataArray) {
#Override
public boolean isCellEditable(int row, int col) {
return (row > -1 && col != 0 && col != 4);
}
#Override
public void setValueAt(int row, int column, Object o) {
if (DEBUG) {
Log.p("Executing setValueAt \"" + o + "\" at row " + row + ", column " + column);
}
super.setValueAt(row, column, o);
try {
String value;
if (o instanceof String) {
value = (String) o;
} else if (o instanceof Integer) {
Integer num = (Integer) o;
value = num.toString();
} else {
if (DEBUG) {
Log.p("ERROR in setValueAt row " + row + ", column " + column + " because wrong object class");
}
throw new IllegalArgumentException("Object o is not a String or an Integer");
}
switch (column) {
case 0:
listToShow.get(row).keyword.set(value);
break;
case 1:
listToShow.get(row).text_IT.set(value);
break;
case 2:
listToShow.get(row).text_EN.set(value);
break;
case 3:
listToShow.get(row).position.set(Integer.valueOf(value));
break;
case 4:
listToShow.get(row).dbAction.set(Integer.valueOf(value));
break;
default:
if (DEBUG) {
Log.p("ERROR in setValueAt row " + row + ", column " + column + ", because wrong column number");
}
}
} catch (Exception ex) {
if (DEBUG) {
Log.p("ERROR in setValueAt row " + row + ", column " + column);
Log.e(ex);
}
}
if (DEBUG) {
List<Map<String, Object>> listMaps = new LinkedList<>();
for (SportTypeDAO dao : listToShow) {
listMaps.add(dao.getPropertyIndex().toMapRepresentation());
}
Map<String, List<Map<String, Object>>> toConvert = new HashMap<>();
toConvert.put("root", listMaps);
Log.p("--- New JSON content:\n" + JSONParser.mapToJson(toConvert));
}
}
#Override
public Object getValueAt(int row, int column) {
// if(DEBUG) Log.p("Executing getValueAt row " + row + ", column " + column);
try {
switch (column) {
case 0:
return listToShow.get(row).keyword.get();
case 1:
return listToShow.get(row).text_IT.get();
case 2:
return listToShow.get(row).text_EN.get();
case 3:
return listToShow.get(row).position.get();
case 4:
return listToShow.get(row).dbAction.get();
default:
if (DEBUG) {
Log.p("ERROR: cannot get value at row " + row + ", column: " + column);
}
return "";
}
} catch (Exception err) {
if (DEBUG) {
Log.p("ERROR: cannot get value at row " + row + ", column: " + column);
Log.e(err);
}
return "";
}
}
};
Table table = new Table(model) {
#Override
protected Component createCell(Object value, int row, int column, boolean editable) {
Component cell = super.createCell(value, row, column, editable);
if (row > -1) {
cell.setUIID("TableCell");
}
if (row > -1 && row % 2 == 0) {
// pinstripe effect
cell.getAllStyles().setBgColor(0xeeeeee);
cell.getAllStyles().setBgTransparency(255);
}
return cell;
}
#Override
protected TableLayout.Constraint createCellConstraint(Object value, int row, int column) {
TableLayout.Constraint con = super.createCellConstraint(value, row, column);
con.setWidthPercentage(100 / model.getColumnCount());
return con;
}
};
table.setSortSupported(true);
try {
table.sort(3, false); // order by position
if (DEBUG) {
Log.p("table.sort executed successfully");
}
} catch (Exception ex) {
if (DEBUG) {
Log.p("ERROR: cannot order table, maybe there are null values");
Log.e(ex);
}
}
add(table);
}
}
Right now we don't have a property list to table bind. I tried a stab on this and I think this is pretty easy. I'll add this to the next update but you should already be able to use this:
/**
* Implements table model binding, this is implemented as a class to allow
* additional features such as adding/removing rows
*/
public class BoundTableModel implements TableModel {
private List<PropertyBusinessObject> objects;
private PropertyBusinessObject prototype;
private Set<String> exclude = new HashSet<String>();
private PropertyBase[] columnOrder;
private Set<String> uneditable = new HashSet<String>();
private EventDispatcher listeners = new EventDispatcher();
/**
* Creates a table model with the business objects
* #param objects the objects of the model
* #param prototype the type by which we determine the structure of the table
*/
public BoundTableModel(List<PropertyBusinessObject> objects,
PropertyBusinessObject prototype) {
this.objects = objects;
}
/**
* The properties that are ignored
* #param b the property to ignore
*/
public void excludeProperty(PropertyBase b) {
exclude.add(b.getName());
}
/**
* Sets the order of the columns explicitly
* #param columnOrder the order of the columns based on the prototype
*/
public void setColumnOrder(PropertyBase... columnOrder) {
this.columnOrder = columnOrder;
}
/**
* Makes the property editable or uneditable
* #param pb the property base
* #param editable true for editable (the default)
*/
public void setEditable(PropertyBase pb, boolean editable) {
if(editable) {
uneditable.remove(pb.getName());
} else {
uneditable.add(pb.getName());
}
}
/**
* {#inheritDoc}
*/
#Override
public int getRowCount() {
return objects.size();
}
/**
* Adds a new business object to the table
* #param index the index of the addition
* #param b the business object
*/
public void addRow(int index, PropertyBusinessObject b) {
objects.add(index, b);
for(int col = 0 ; col < getColumnCount() ; col++) {
listeners.fireDataChangeEvent(col, index);
}
}
/**
* Removes the row at the given index
* #param index the position in the table
*/
public void removeRow(int index) {
objects.remove(index);
listeners.fireDataChangeEvent(Integer.MIN_VALUE, Integer.MIN_VALUE);
}
/**
* {#inheritDoc}
*/
#Override
public int getColumnCount() {
if(columnOrder != null) {
return columnOrder.length;
}
return prototype.getPropertyIndex().getSize() - exclude.size();
}
#Override
public String getColumnName(int i) {
if(columnOrder != null) {
return columnOrder[i].getLabel();
}
return prototype.getPropertyIndex().get(i).getName();
}
#Override
public boolean isCellEditable(int row, int column) {
return !uneditable.contains(prototype.getPropertyIndex().get(column).getName());
}
#Override
public Object getValueAt(int row, int column) {
PropertyBusinessObject pb = objects.get(row);
String n;
if(columnOrder != null) {
n = columnOrder[column].getName();
} else {
n = pb.getPropertyIndex().get(column).getName();
}
return pb.getPropertyIndex().get(n).get();
}
#Override
public void setValueAt(int row, int column, Object o) {
PropertyBusinessObject pb = objects.get(row);
String n;
if(columnOrder != null) {
n = columnOrder[column].getName();
} else {
n = pb.getPropertyIndex().get(column).getName();
}
pb.getPropertyIndex().get(n).setImpl(o);
listeners.fireDataChangeEvent(column, row);
}
#Override
public void addDataChangeListener(DataChangedListener d) {
listeners.addListener(d);
}
#Override
public void removeDataChangeListener(DataChangedListener d) {
listeners.removeListener(d);
}
}
Getting error when mouse hover an element with below code in selenium:
public void our_medicines(String locatorType, String value) {
try {
By locator;
locator = locatorValue(locatorType, value);
Actions action = new Actions(driver);
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
action.moveToElement(element).click().build().perform();
} catch (Exception e) {
System.err.format("no such element to mousehover" + e);
}
}
This is my locatorValue method:
public By locatorValue(String locatorTpye, String value) {
By by;
switch (locatorTpye) {
case "id":
by = By.id(value);
break;
case "name":
by = By.name(value);
break;
case "xpath":
by = By.xpath(value);
break;
case "css":
by = By.cssSelector(value);
break;
case "linkText":
by = By.linkText(value);
break;
case "partialLinkText":
by = By.partialLinkText(value);
break;
case "className":
by = By.className(value);
break;
default:
by = null;
break;
}
return by;
}
Okay so the problem I found with your locatorValue method was that it could not handle unspecified locators in this block
default: by = null;
break;
}
return by; }
I added something simple just to deal with that, but you can tune it however you want
default: throw new Exception("Locator type not defined");
}
return by; }
Make sure the locatorType parameter being passed to public void our_medicinesis a valid Locator type.
I have a UIScrollView into which I am creating and adding UILabels containing the results of a simple LINQ query.
I have set up a UISwipeGestureRecognizer within the loop that generates the labels (iOS: issues with UIGestureRecognisers vs Subviews says I need a new recogniser for each control - I'm assuming I can do with a UILabel the same as UIImageView for adding a recogniser) and then added the recogniser to the label.
When the view containing the UIScrollView is started, the scrollview works as expected, but the swipe isn't.
Caveat : only tried this on the simulator, my iPhone is acting up.
private void CreateViewHistory()
{
float xtext = 4f;
float y = 4f;
int c = 0;
var tv = tank.Events.OrderByDescending(t => t.Date).ToList();
tbiHistClearAll.Enabled = enableDelete;
//tgrRemove.AddTarget(this, new Selector("screenSwipe"));
//pgrRemove.DelaysTouchesBegan = true;
foreach (var e in tv)
{
var tgrRemove = new UISwipeGestureRecognizer()
{
NumberOfTouchesRequired = 1,
Direction = UISwipeGestureRecognizerDirection.Right,
};
tgrRemove.AddTarget(this, new Selector("screenSwipe"));
svHistoryEvents.PanGestureRecognizer.RequireGestureRecognizerToFail(tgrRemove);
string info = string.Format("{0} - {1}{2} ({3})\n{4} - {5}\n{6} - {7}\n{8} - {9}", e.EventType, e.Volume, AppDelegate.Self.db.getShortVolumeUnits(), e.Date.ToShortDateString(),
StringUtils.GetString("Sowcrop.Implement"), e.Implement != null ? e.Implement.ImplementType : StringUtils.GetString("Common.NonRecorded"),
StringUtils.GetString("Common.User"), StringUtils.GetString("Common.NonRecorded"),
StringUtils.GetString("Common.Notes"), !string.IsNullOrEmpty(e.Notes) ? e.Notes : StringUtils.GetString("Common.NonRecorded"));
var lbl = new UILabel()
{
UserInteractionEnabled = true
};
lbl = UICreation.MakeLabelWithTag(svHistoryEvents, new RectangleF(xtext, y, 320f, 90f), info, UITextAlignment.Left, UIColor.Black, false, 4, c);
lbl.AddGestureRecognizer(tgrRemove);
svHistoryEvents.AddSubview(lbl);
lblTemp.Add(lbl);
c++;
y += 94f;
}
UIUtils.ResizeScrollView(svHistoryEvents);
}
[Export("screenSwipe")]
public void SwipeRemove(UIGestureRecognizer s)
{
var swipe = s as UIGestureRecognizer;
var tv = tank.Events.OrderByDescending(t => t.Date).ToList();
var txt = swipe.View as UILabel;
switch (swipe.State)
{
case UIGestureRecognizerState.Began:
Console.WriteLine("Swipe began");
break;
case UIGestureRecognizerState.Changed:
Console.WriteLine("Swipe changed");
tv.RemoveAt(txt.Tag);
CreateViewHistory();
break;
case UIGestureRecognizerState.Ended:
Console.WriteLine("Swipe ended");
break;
case UIGestureRecognizerState.Cancelled:
Console.WriteLine("Swipe cancelled");
break;
}
}
MakeLabelWithTag generates a UILabel which can then be added to the scrollview.
Am I missing something here, or do I need to do something special as the label is held within a scrollview?
I've also tried what has been suggested at UISwipeGestureRecogniser in a UIScrollView, but still without success.
Found the problem and it's probably the dumbest thing I've encountered in a long time!
To get the swipe gesture to work within a scrollview, you have to first encompass whatever it is you want to add within a UIView and then add that to the scrollview.
To therefore get a swipe within a scrollview to work, you need to do the following
private void CreateViewHistory()
{
foreach (var i in svHistoryEvents.Subviews)
if (i is UIView)
i.RemoveFromSuperview();
float xtext = 4f;
float y = 4f;
int c = 0;
tbiHistClearAll.Enabled = enableDelete;
foreach (var e in tv)
{
var tgrRemove = new UISwipeGestureRecognizer()
{
NumberOfTouchesRequired = 1,
Direction = UISwipeGestureRecognizerDirection.Right,
};
tgrRemove.AddTarget(this, new Selector("screenSwipe"));
var view = new UIView(new RectangleF(xtext, y, 320f, 90f));
svHistoryEvents.PanGestureRecognizer.RequireGestureRecognizerToFail(tgrRemove);
string info = string.Format("{0} - {1}{2} ({3})\n{4} - {5}\n{6} - {7}\n{8} - {9}", e.EventType, e.Volume, AppDelegate.Self.db.getShortVolumeUnits(), e.Date.ToShortDateString(),
StringUtils.GetString("Sowcrop.Implement"), e.Implement != null ? e.Implement.ImplementType : StringUtils.GetString("Common.NonRecorded"),
StringUtils.GetString("Common.User"), StringUtils.GetString("Common.NonRecorded"),
StringUtils.GetString("Common.Notes"), !string.IsNullOrEmpty(e.Notes) ? e.Notes : StringUtils.GetString("Common.NonRecorded"));
var lbl = new UILabel()
{
UserInteractionEnabled = true
};
lbl = UICreation.MakeLabelWithTag(svHistoryEvents, new RectangleF(0, 0, 320f, 90f), info, UITextAlignment.Left, UIColor.Black, false, 4, c);
view.AddGestureRecognizer(tgrRemove);
view.AddSubview(lbl);
svHistoryEvents.AddSubview(view);
lblTemp.Add(lbl);
c++;
y += 94f;
}
UIUtils.ResizeScrollView(svHistoryEvents);
}
[Export("screenSwipe")]
public void SwipeRemove(UIGestureRecognizer s)
{
var swipe = s as UIGestureRecognizer;
var txt = swipe.View.Subviews[0] as UILabel;
switch (swipe.State)
{
case UIGestureRecognizerState.Began:
Console.WriteLine("Swipe began");
break;
case UIGestureRecognizerState.Changed:
Console.WriteLine("Swipe changed");
break;
case UIGestureRecognizerState.Ended:
Console.WriteLine("Swipe ended");
tv.RemoveAt(txt.Tag);
CreateViewHistory();
break;
case UIGestureRecognizerState.Cancelled:
Console.WriteLine("Swipe cancelled");
break;
}
}
It is not possible to add just a UILabel and have the swipe act on that, it has to be on a UIView with the label as a subview to it.