Item renderer - Rendering a row in flex - actionscript-3

I have got a datagrid with three columns. I have applied two different renderers on different columns (Say Renderer A at column 1 and Renderer B at column 3).
Now in set Data() of B (column three's renderer) I am changing a Requiredflag on the basis of some condition. In set Data of A (Column 1's renderer), I am checking the RequiredFlag and changing its style accordingly.
The problem is for a Row, A renders before B as it is the first column, so it does not get the updated value of requiredFlag (as the requiredFlag is updated in B).
So can I somehow render the first column's cell again after rendering third column's cell? Or if I can render the whole row again after the value of requiredFlag changes in third column's cell.

See the itemrender as a view, so the renderer itself does not do any computation, just check the value of the object...
If I understood correctly I'll do something like that...
(maybe you need to move the check from set data to updatedisplaylist)
example:
class Test
{
public var col1:String = "Everything";
public var col3:String = "Cars";
public function get color():uint
{
if (col1 == "Everything")
return 0xff0000;
return 0x000000;
}
}
itemrendererA.mxml
override public function set data(value:Object):void
{
super.data = value;
if (super.data != null && super.data is Test)
{
// do what you need to do..
lbl1.text = (super.data as Test).col1;
lbl1.setStyle("color", (super.data as Test).color);
}
}
itemrendererB.mxml
override public function set data(value:Object):void
{
super.data = value;
if (super.data != null && super.data is Test)
{
if ( (super.data as Test).color == 0xff0000)
// do something
else
// do something else
}
}
if that's not what you're looking for, please add some of your code...

Related

How to change a color of single cell in spark DataGrid

let's say I have rowIndex and columnIndex and I want to change background color of this cell
One way to do it is by extending the default itemRenderer and overriding the set data method:
override public function set data(value:Object):void {
super.data = value;
// retrieve the value of the list-based control's new public property
var minAge:Number = (listData.owner as MyList).minAge;
if (data.age < minAge) {
listLabel.setStyle("color",0xFF0000);
} else {
listLabel.setStyle("color",0x000000);
}
}
Here is a link to a good example :
http://blog.flexdevelopers.com/2009/06/flex-examples-item-renderers-in.html

JTable : how to get selected cells?

I have a JTable and its TableModel, it works well but what I want to do now is to get the selected cells of it. I thought of doing something like :
int rows = this.getTable().getRowCount();
int columns = this.getTable().getColumnCount();
for(int i = 0 ; i < rows ; i++)
{
for(int j = 0 ; j < columns ; j++)
{
if(table.getCell(i,j).isSelected() //...
}
}
But of course something like this doesn't exist. What should I do instead?
In JTable, you have the
JTable.getSelectedRow()
and
JTable.getSelectedColumn()
You can try combine this two method with a MouseListener and a KeyListener.
With the KeyListener you check if user is pressing the CTRL key, which means that user is selecting cells, then with a mouse listener, for every click you store maybe in a Vector or ArrayList the selected cells:
//global variables
JTable theTable = new JTable();//your table
boolean pressingCTRL=false;//flag, if pressing CTRL it is true, otherwise it is false.
Vector selectedCells = new Vector<int[]>();//int[]because every entry will store {cellX,cellY}
public void something(){
KeyListener tableKeyListener = new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_CTRL){//check if user is pressing CTRL key
pressingCTRL=true;
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_CTRL){//check if user released CTRL key
pressingCTRL=false;
}
}
};
MouseListener tableMouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if(pressingCTRL){//check if user is pressing CTRL key
int row = theTable.rowAtPoint(e.getPoint());//get mouse-selected row
int col = theTable.columnAtPoint(e.getPoint());//get mouse-selected col
int[] newEntry = new int[]{row,col};//{row,col}=selected cell
if(selectedCells.contains(newEntry)){
//cell was already selected, deselect it
selectedCells.remove(newEntry);
}else{
//cell was not selected
selectedCells.add(newEntry);
}
}
}
};
theTable.addKeyListener(tableKeyListener);
theTable.addMouseListener(tableMouseListener);
}
table.getSelectedRow() will get selected row.
table.getSelectedColumns() will get selected columns.
getValueAt(rowIndex, columnIndex) will give the value present at the selected row for each column.
JTable has methods to get the selected rows and get the selected columns.
You can use:
int row = table.rowAtPoint(e.getPoint());
int col = table.columnAtPoint(e.getPoint());
You can get the row and column with ( table.getSelectedRow() and table.getSelectedColumn()) but if you selected more than one cell the method table.getSelectedRow() and table.getSelectedColumn() return cell's position of the first cell that was clicked.
On the other hand, table.rowAtPoint(e.getPoint()) and table.columnAtPoint(e.getPoint()) return the exact cell's table that was clicked for the last time.

as3 reuse datagrid cellrenderer with different variables

I have a couple very large datagrids with custom cell renderers. The issue I am facing is that I now have > 80 of these, 1 for each column per data grid.
I'm curious if there is a way I can get these reduced down into 1 global cell renderer that I could pass variables into to define what is allowed by the cell renderer for that column.
ie:
...
col1 = new DataGridColumn("PurchaseStartDate");
col1.headerText = "Purchase Date (YYYY-MM)";
dg.addColumn(col1);
col1.width = 110;
col1.editable = false;
col1.sortable = false;
col1.cellRenderer = Alternating_Row_Colours_editable36;
Alternating_Row_Colours_editable36._dg = dg;
Alternating_Row_Colours_editable36.__enabled = true;
Alternating_Row_Colours_editable36._myCol = 12;
Alternating_Row_Colours_editable36._isNum = 3;
Alternating_Row_Colours_editable36._stage = this;
Alternating_Row_Colours_editable36._maxChars = 9;
within the cell renderer I'm using all of those variables to customize what is allowed.
ie:
...
public function Alternating_Row_Colours_editable36()
{
super();
if(_isNum == 0){
restrict = "a-z A-Z #_,.0-9//-";
maxChars = 64;
}else if (_isNum == 1){
restrict = ".0-9";
maxChars = 9;
}else if (_isNum == 2){
restrict = "0-9";
maxChars = 2;
}else if (_isNum == 3){
restrict = "0-9 \\-";
maxChars = 9;
}else if (_isNum == 4){
restrict = "0-9. %";
maxChars = 9;
}
if(_maxChars != -1){
maxChars = _maxChars;
}
The issue if you look at the above, I just noted that I had an error. I used "//-" to escape the hyphen instead of "\-". Now I've got 80+ changes to make and every time I try to add something new, for a callback, restricts, max chars, making it editable, scrubbing the input, changing it from dynamic to input and back again...
I would love to know if there is a way, to create an instance of the class and use that cell renderer. Or to be able to pass variables that affect only that column and not all columns.
I'm not the best, but I was under the impression that it might just be a set/get function I need to use, or change the variables to protected, private or something to get this desired result.
Anyone have any suggestions on how to bring these 80+ cell renderers under control. As I am not looking forward to needing to make the changes to them for sorting down the road...
jc
I know this is a very late reply and you've more than likely moved on by now!
You can do it by using the information in 'listData' property of the CellRenderer class:
// Create a private class level variable called _dataField...
private var _dataField:String;
// Assign the dataField...
public function set listData(value:ListData):void {
_listData = value;
this._dataField = DataGridColumn(DataGrid(this._listData.owner).columns[this._listData.column]).dataField;
// set the data again now...
this.data = _data;
invalidate(InvalidationType.DATA);
invalidate(InvalidationType.STATE);
}
// Use the dataField when setting value from DataProvider...
public function set data(value:Object):void {
_data = value;
if (this._dataField != "")
{
this.text = value[this._dataField];
}
}
Hope that satisfies any curiosity. Shame they don't just pass that property to the CellRenderer in the first place!
Cheers

How to handle event for nonvisual objects in Flex

I am trying to perform two way binding e.g I have a button (out of many controls), on its selection, I am showing the values of its diff properties(like height, width etc) in some textinput. This one way process works fine.
But the reverse process doesn't work. i.e When I select some button, and try to change its dimension by entering some value in height, width textinputs, the dimension are not changed.
How to know which button was selected by me? How events needs to be handled here ?
private void Form1_Load(object sender, System.EventArgs e)
{
//Create some data and bind it to the grid
dt1 = GetData(1000, 3);
this.UltraGrid1.DataSource = dt1;
//Set the grid's CreationFilter to a new instance of the NumbersInRowSelectors class.
this.UltraGrid1.CreationFilter = new NumbersInRowSelectors();
}
private void UltraGrid1_InitializeLayout(object sender, Infragistics.Win.UltraWinGrid.InitializeLayoutEventArgs e)
{
//Hide the default images that are drawn in the RowSelectors, like the pencil and asterisk, etc.
e.Layout.Override.RowSelectorAppearance.ImageAlpha = Infragistics.Win.Alpha.Transparent;
//Center the text in the RowSelectors.
e.Layout.Override.RowSelectorAppearance.TextHAlign = Infragistics.Win.HAlign.Center;
e.Layout.Override.RowSelectorAppearance.TextVAlign = Infragistics.Win.VAlign.Middle;
//There is no wy to change the width of the RowSelectors.
//Use a smaller font, so that 3-digit numbers will fit.
e.Layout.Override.RowSelectorAppearance.FontData.Name = "Small Fonts";
e.Layout.Override.RowSelectorAppearance.FontData.SizeInPoints = 6;
}
//The NumbersInRowSelectors class. This class Implements a CreationFilter and
//adds a TextUIElement to each RowSelector which displays the row number of
//the row.
public class NumbersInRowSelectors:Infragistics.Win.IUIElementCreationFilter
{
#region Implementation of IUIElementCreationFilter
public void AfterCreateChildElements(Infragistics.Win.UIElement parent)
{
//Don't need to do anything here
}
public bool BeforeCreateChildElements(Infragistics.Win.UIElement parent)
{
//Declare some variables
Infragistics.Win.TextUIElement objTextUIElement;
Infragistics.Win.UltraWinGrid.RowSelectorUIElement objRowSelectorUIElement;
Infragistics.Win.UltraWinGrid.UltraGridRow objRow;
int RowNumber;
//Check to see if the parent is a RowSelectorUIElement. If not,
//we don't need to do anything
if (parent is Infragistics.Win.UltraWinGrid.RowSelectorUIElement)
{
//Get the Row from the RowSelectorsUIElement
objRowSelectorUIElement = (Infragistics.Win.UltraWinGrid.RowSelectorUIElement)parent;
objRow = (Infragistics.Win.UltraWinGrid.UltraGridRow)objRowSelectorUIElement.GetContext(typeof(Infragistics.Win.UltraWinGrid.UltraGridRow));
//Get the Index of the Row, so we can use it as a row number.
RowNumber = objRow.Index;
//Check to see if the TextUIElement is already created. Since
//The RowSelectorsUIElement never has children by default, we
//can just check the count.
if (parent.ChildElements.Count == 0)
{
//Create a new TextUIElement and parent it to the RowSelectorUIElement
objTextUIElement = new Infragistics.Win.TextUIElement(parent, RowNumber.ToString());
parent.ChildElements.Add(objTextUIElement);
}
else
{
//There's already a TextUIElement here, so just set the Text
objTextUIElement = (Infragistics.Win.TextUIElement)parent.ChildElements[0];
objTextUIElement.Text = RowNumber.ToString();
}
//Position the TextUIElement into the RowSelectorUIElement
objTextUIElement.Rect = parent.RectInsideBorders;
//Return True let the grid know we handled this event.
//This doesn't really do anything, since the grid
//does not create any child elements for this object, anyway.
return true;
}
//Return false to let the grid know we did not handle the event.
//This doesn't really do anything, since the grid
//does not create any child elements for this object, anyway.
return false;
}
#endregion
}
}
Create a "currently selected item" member in the class where the button and the text edit are declared.
In the button selection event listener assign the event target to this member. Then use it in the text edit event listener.
For example:
// It's a declaration of the member variable
private var m_current_btn:Button = null;
// It's an event listener for your button
private function on_selection_change(event:Event):void
{
m_current_btn = event.target as Button;
// button_x and button_y are two text edits
button_x.text = m_current_button.x.toString();
button_y.text = m_current_button.y.toString();
}
// Event listener to track changes in the coordinate text inputs
private function on_coordinate_textedit_change(event:Event):void
{
if (m_current_btn != null)
{
m_current_btn.x = parseInt(button_x.text);
m_current_btn.y = parseInt(button_y.text);
}
}

I need a way out

public class NCell
{
private var _player: NPlayer;
public function set player(value: NPlayer):void
{
this._player = value;
}
public function get player():NPlayer {return this._player}
}
public class NPlayer
{
private var _cell: NCell;
public function set cell(value: NCell):void
{
if (this._cell != null)
{
this._cell.player = null;
}
this._cell = value;
if (this._cell != null)
{
this._cell.player = this;
this.position = this.cell.position;
}
}
}
So, I have a field of NCells (size 20x15) and several players on it. To move player I write
player.cell = field[4][4];
After it player knows his cell (and position) and cell has a link to player. Thus I have everything to calculate available moves. Sometimes there are situations when player has "cell", but "player" in the cell == null. It's bad. It becomes so because when I calculation moves I store players position then move players and then continue searching and when game points become 0 I restore players positions and continue searching. E.g. I have c1 == field[3][4], c2 == field[4][4], c3 == field[5][4], p1.cell == c1, p2.cell == c2. p2 moves to c3 and then p1 moves to c1. Then I restore position:
//c2.player == p1
p2.cell = c2;//now c2.player == c2 but p1.cell == c2
p1.cell = c1;//and here c2.player == null
and it doesn't depends of restoring sequence. How to avoid link wiping?
Well, I am not so sure the way you store your data is the best. If you really want this kind of linkage, you may want to consider making a cell capable of holding multiple players. This would resolve your current problem and would be more flexible, later on.
Basically, you problem can be solved like this:
public class NPlayer
{
private var _cell: NCell;
public function set cell(value: NCell):void
{
if (this._cell != null && this._cell.player == this) //only the owner may remove a link!
{
this._cell.player = null;
}
this._cell = value;
if (this._cell != null)
{
this._cell.player = this;
//this.position = this.cell.position; <-- no need for that, see below
}
}
}
Unless you access NPlayer::position a gazillion times per frame, there is no point in storing it. This only introduces a potential source of errors. The property should be calculated, by simply returning this.cell.position or a meaningful default value in case the player has no cell (or raising an exception, if that is not supposed to happen).
greetz
back2dos