Set Flex AxisRenderer's axisStroke via CSS - apache-flex

I'm trying to set the axisStroke style on AxisRenderer via CSS. It's of type IStroke. How do I create a Stroke in CSS?

Someone :) suggested I should post a link to my InsideRIA about how to "tweak" a CSSStyleDeclaration to add the stroke information so that you don't have to override AxisRenderer (or have an explicit AxisRenderer at all) http://insideria.com/2010/08/usinc-css-for-strokes-on-flex.html,
Additionally, I'd like to add that I've started dealing with custom styles in a way that's a little different than how the examples show. It looks something like this:
protected var _myStyleValue:SomeType = someValueThatWouldNeverOccurInNature;
protected var _myThingTheStyleIsAttachedTo:IStyleClient;
//set this flag whenever you want to refresh the object
protected var _myThingTheStyleIsAttachedToChanged:Boolean;
override protected function commitProperties():void {
if (_myThingTheStyleIsAttachedToChanged) {
var myStyleValue:SomeType = getMyStyleValue();
_myThingTheStyleIsAttachedTo.setStyle('myStyle', myStyleValue);
_myThingTheStyleIsAttachedToChanged = false;
}
}
override public function styleChanged(styleProp:String):void {
super.styleChanged(styleProp);
if (styleProp=='myStyle') {
_myThingTheStyleIsAttachedToChanged = true;
_myStyleValue = someValueThatWouldNeverOccurInNature;
}
}
protected function getMyStyleValue():SomeType {
if (_myStyleValue==someValueThatWouldNeverOccurInNature) {
var theValue:*=getStyle('myStyle');
if (theValue==undefined) {
_myStyleValue=theDefaultValue;
} else {
_myStyleValue=theValue as SomeType;
}
return _myStyleValue;
}
}
It's a little more verbose than what you usually see, especially if there are multiple properties you need to look at. However, it sidesteps issues about styles applied in MXML vs. CSS style declaration, as well as what happens when a style changes. It's also "lazy", and so may not get called if it is not needed.

Why not try my (admittedly, somewhat crazy) CSS post-processing trick: http://bitrotincarnate.wordpress.com/2009/12/16/strokes-and-fills-in-flex-css-through-actionscript-injection/

#James:
Looks like a little bug here:
if ((getStyle("axisStrokeColor") != null) && (getStyle("axisStrokeColor") != null))
{
var axisStroke:Stroke = new Stroke(getStyle("axisStrokeColor"), getStyle("axisStrokeColor"));
Repeating the axisStrokeColor twice. Think you meant to refer to strokeWeight as well:
if ((getStyle("axisStrokeWeight") != null) && (getStyle("axisStrokeColor") != null))
{
var axisStroke:Stroke = new Stroke(getStyle("axisStrokeColor"), getStyle("axisStrokeWeight"));

Not sure I understand the guts of your code logic above, although I do understand its purpose. ;-)
However, relying on styleChanged() alone did not work for me. Particularly if I switched CSS styles during run-time and and the new style declaration didn't have "axisStroke" in it -- which of course it can't! The fuller solution would be to include code for styleChanged() and also stylesInitialized(). In the source, I also include a reference to the stroke object _axisStroke. This cuts down countless calls to getStyle("axisStroke") as well as being necessary for the guaranteed instantiation logic below.
Like I said, my problem was I would get run-time errors if I declared a style entry in CSS for an axis renderer component but did not set its "axisStroke" style property programatically. Although the work-around for this is usually to instantiate a default CSSStyleDeclaration in a classConstructed() static method (see adobe's developer guide and styles for this common practice), this will not work if the style CSS is changed dynamically during run-time. The classConstructed() only gets called initially and usually checks to make sure there is no style declaration already for the component before registering the default. Then later, when you change styles, your component's "axisStroke" style gets cleared. THEN, you can get null exceptions. Furthermore, just using CSS, you can't insert a new "axisStroke" style. But, since stylesInitialized() is called anytime a component's style selector setting changes -- eg: StyleManager.setStyleDeclaration("MyComponent", myStyleDeclaration) -- you can insure all the styles are set and in place, and anything that might throw a null exception, such as a missing "axisStroke" style, can be accounted for.
private var _axisStroke:IStroke;
override public function stylesInitialized():void {
super.stylesInitialized();
_axisStroke = getStyle("axisStroke");
if (!_axisStroke) {
//usually a default stroke style is set in a default CSSStyleDeclaration
//created in a classConstructed() method
_axisStroke = new Stroke(0xCCDDEE, 8, 1, false, LineScaleMode.NORMAL, CapsStyle.NONE);
//note: I do NOT register _axisStroke to the style "axisStroke".
//Since "axisStroke" is still technically not set, I leave it null.
//You may need to set it, however, if you are extending AxisRenderer.
//setStyle("axisStroke", _axisStroke);
}
var axisColor:Number = getStyle("axisColor");
if (!isNaN(axisColor)) {
Object(_axisStroke).color = axisColor;
}
...
}
Anyway, if just using styleChanged() works for you, great. But if you still get run-time errors from styles not being initialized or in the wrong order, look into using stylesInitialized(). This is particularly useful when making your own IAxisRenderer classes.

The solution I finally used was to create a custom extension of AxisRenderer that exposed the styles I needed:
package
{
import mx.charts.AxisRenderer;
import mx.graphics.Stroke;
[Style(name="axisStrokeColor", type="uint", format="Color", inherit="yes")]
[Style(name="axisStrokeWeight", type="Number", format="Length", inherit="yes")]
[Style(name="minorTickStrokeColor", type="uint", format="Color", inherit="yes")]
[Style(name="minorTickStrokeWeight", type="Number", format="Length", inherit="yes")]
[Style(name="tickStrokeColor", type="uint", format="Color", inherit="yes")]
[Style(name="tickStrokeWeight", type="Number", format="Length", inherit="yes")]
public class StyledAxisRenderer extends AxisRenderer
{
override public function styleChanged(styleProp:String):void
{
super.styleChanged(styleProp);
var stylesUpdated:Boolean = false;
if ((styleProp != "axisStroke") && (styleProp != "minorTickStroke") && (styleProp != "tickStroke"))
{
if ((getStyle("axisStrokeColor") != null) && (getStyle("axisStrokeWeight") != null))
{
var axisStroke:Stroke = new Stroke(getStyle("axisStrokeColor"), getStyle("axisStrokeWeight"));
setStyle("axisStroke", axisStroke);
stylesUpdated = true;
}
if ((getStyle("minorTickStrokeColor") != null) && (getStyle("minorTickStrokeWeight") != null))
{
var minorTickStroke:Stroke = new Stroke(getStyle("minorTickStrokeColor"), getStyle("minorTickStrokeWeight"));
setStyle("minorTickStroke", minorTickStroke);
stylesUpdated = true;
}
if ((getStyle("tickStrokeColor") != null) && (getStyle("tickStrokeWeight") != null))
{
var tickStroke:Stroke = new Stroke(getStyle("tickStrokeColor"), getStyle("tickStrokeWeight"));
setStyle("tickStroke", tickStroke);
stylesUpdated = true;
}
if (stylesUpdated)
{
invalidateDisplayList();
}
}
}
}
}

Related

"Control" Property In Custom Renderers and Effects Is Null For Layouts

When I try to write a custom renderer for any of the layout classes, the "Control" property appears null. It is OK since the renderer already is the wrapper for the native control but it is a problem when creating an Effect. So I cannot do any customization with the layout classes using Effects since Control property is not assigned. Is this a bug?
The PlatformEffect class has another property called Container which could also be used for the effect when the Control is null, e.g. at layouts.
So I saw the same issue as the original post.
I was inheriting PlatformEffect<UIView, UILabel> on iOS. The control was null when I was debugging. I changed my Effect to inherit from PlatformEffect and then cast the control as ((UILabel)Control) and everything started working.
Returned a Null Control
MultilineTruncateLabelEffect : PlatformEffect<UIView, UILabel>
{
protected override void OnAttached()
{
var effect = (MultilineEffect) Element.Effects.FirstOrDefault(e => e is MultilineEffect);
if (effect != null)
{
Control.Lines = effect.Lines;
}
}
}
Worked Fine
public class MultilineTruncateLabelEffect : PlatformEffect
{
protected override void OnAttached()
{
var effect = (MultilineEffect) Element.Effects.FirstOrDefault(e => e is MultilineEffect);
if (effect != null)
{
((UILabel)Control).Lines = effect.Lines;
}
}
}
Layout do not have renderers, and as they have no renderers or native views (i.e. no Control), there's nothing you could possibly modify with an Effect.

Actionscript: I am trying to use actionscript buttons with a key press instead of a mouse click

This in flash.
I have a bunch of buttons that I want to animate once I've hit the corresponding key for. Each button has an "Up," "Over," "Down," and "Hit" state.
I get the error I keep getting is:
Access of possibly undefined property enabled through a reference with static type Class.
I think there is something wrong with the way I called "Pad7" which is a button with a class name of "Pad7."
Here is my code
stage.addEventListener(KeyboardEvent.KEY_DOWN, fl_KeyboardDownHandler);
function fl_KeyboardDownHandler(event:KeyboardEvent):void
{
Pad7.enabled = false;
if (event.keyCode == 81)
{
trace("Q");
Pad7.enabled = true;
//Pad7.gotoAndPlay();
}
}
It seems like you have a class called Pad7 and then you also have an instance of that class called Pad7. At least make sure that your instance of Pad7 is named something that you can access. You probably meant to do something similar to this:
var myPad7Instance:Pad7;
function myInitFunction():void {
myPad7Instance = new Pad7();
stage.addEventListener(KeyboardEvent.KEY_DOWN, fl_KeyboardDownHandler);
}
function fl_KeyboardDownHandler(event:KeyboardEvent):void
{
myPad7Instance.enabled = false;
if (event.keyCode == 81)
{
trace("Q");
myPad7Instance.enabled = true;
//myPad7Instance.gotoAndPlay();
}
}

Is there a way to get a list of all skin classes in the current application?

Is there a way to get a list of all the skin classes that are in the current application? I'm using Flex 4.5.1.
Here is the loop that I'm using now to get all the skins,
for each (var item:Object in styleManager.typeHierarchyCache) {
for (label in item) {
if (label=="spark.components.supportClasses.Skin" ||
label=="spark.skins.mobile.supportClasses.MobileSkin") {
for (label in item) {
name = label.substr(label.lastIndexOf(".")+1);
vo = new SkinObject();
vo.name = name;
vo.qualifiedName = label;
dictionary[label] = vo;
}
break;
}
}
}
for each (item in dictionary) {
array.push(item);
}
The reason why is because I want to list all the skins in the application and then be able to apply them in real time so I can see what they look like. * I have this working but I was hoping for a better way.
You definitely could iterate through all objects on the screen and see if they're of type SparkSkin. Something like this:
private function findSkins():void
{
recurseComponent(FlexGlobals.topLevelApplication);
}
private function recurseComponent(parent:UIComponent):void
{
var child:UIComponent;
for(var i:uint = 0, len:uint = parent.numElements; i<len; i++)
{
child = parent.getElementAt(i) as UIComponent;
if(child && child is SparkSkin)
{
trace("Skin Found!"); // trace whatever you need here
}
recurseComponent(child);
}
}
But be warned that this solution is very expensive since it needs to iterate through all objects on the screen, which can go into several thousands. However, I really don't see what's the purpose of this and would definitely not recommend it other than for debugging/testing purposes.
Edit: Also, this will only work for skins on the display list. Skins mentioned in CSS will not be recognized and I'm fairly sure there's no way of figuring that out short of going through all the css and see if there's a skinClass property. But then it won't catch any default skins or skins set in actionscript or inline mxml.

How do I set the StripFormattingOnPaste property of a Telerik RadEditor with JavaScript?

I don't have access to the actual asp.net server tag itself, so I need to change the StripFormattingOnPaste property to the EditorStripFormattingOptions enum with JavaScript and I'm not sure how. I have some code that adds an OnClientLoad() and OnClientCommandExecuted() functions that works so I can add it in there, I'm just not sure where the property exists on the client-side and what the enum value would be:
// init OnClientLoad and OnClientCommandExecuted event handlers for all radeditors on the page
Sys.Application.add_load(function() {
if (typeof ($telerik) != "undefined") {
if ($telerik.radControls && Telerik.Web.UI.RadEditor) {
for (var i = 0, l = $telerik.radControls.length; i < l; i++) {
var control = $telerik.radControls[i];
if (Telerik.Web.UI.RadEditor.isInstanceOfType(control)) {
var editor = control;
// ??? editor._stripFormattingOptions = Telerik.Web.UI.StripFormattingOptions.NoneSupressCleanMessage
// editor already loaded, fire event
OnClientLoad(editor);
// attach event handler for paste commands
editor.add_commandExecuted(function(ed, args) {
return OnClientCommandExecuted(ed, args);
});
}
}
}
}
});
Update: I've discovered that the correct enum setting that I want is Telerik.Web.UI.StripFormattingOptions.NoneSupressCleanMessage.
Update #2: I see that the RadEditor JS object has a _stripFormattingOptions property, but I think it might just be for private use.
The Telerik controls are based on ASP.NET AJAX and use pretty much the same coding conventions - public properties have getters and setters methods. In this case you should use
editor.set_stripFormattingOptions(Telerik.Web.UI.StripFormattingOptions.NoneSupressCleanMessage);
To get the current value, use
var value = editor.get_stripFormattingOptions();
The property you saw (editor._stripFormattingOptions) is just used to store the value. Since its name starts with an underscore you are correct to assume that it is private and so you should not rely on it. The getter and setter methods are public and you are free to use them.

How do you add a row listener to a Flextable in GWT?

How do you add a row listener to a specific row, or all rows in a table? I need to add a type of "onMouseOver" listener to the rows so that when you hover over them, it changes the background color of the row, much like getRowFormatter will allow you to do.
// this is click
final FlexTable myTable = new FlexTable();
myTable.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
Cell cell = myTable.getCellForEvent(event);
int receiverRowIndex = cell.getRowIndex(); // <- here!
}
});
Supposing GWT 1.5.3:
CLICK EVENT HANDLING
If you are using FlexTable and you wanted a click event handler, you could use the FlexTable.addTableListener() and register your own TableListener. The TableListener object will need to implement the onCellClicked callback which would give you the row number.
OTHER EVENTS HANDLING (e.g. HOVER)
If you need to handle other type of events other than click (say, hover), GWT currently doesn't have a ready interface for that. You pretty much left on your own to implement them yourself. There's two ways of doing it that I can think of now:
The quick and dirty way, is probably by exploiting JSNI, which provides a means for you to inject Javascript into your GWT code. I didn't use much JSNI (apart from really hard workarounds which is not worth the effort writing it in pure GWT) in my code so I can't show you an example; but frankly I won't recommend this as it reduces maintainability and extensibility.
If you wanted a native, GWT interface, you can create a new class that inherits HTMLTable or FlexTable. At the constructor, call the sinkEvents function with your needed events. (e.g. for hover, you'll probably need sinkEvents(Event.ONMOUSEOVER)). Then you'll need the onBrowserEvent function that handles the mouseover.
A quick template of how the code should look like:
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FlexTable;
public class FlexTableWithHoverHandler
extends FlexTable
{
public FlexTableWithHoverHandler()
{
super();
sinkEvents(Event.ONMOUSEOVER);
}
#Override
public void onBrowserEvent(Event event)
{
switch(DOM.eventGetType(event))
{
case Event.ONMOUSEOVER:
// Mouse over handling code here
break;
default:
break;
}
}
}
The best of learning how to code this is by looking at the GWT source code itself (search for sinkEvent) and getting the feel on how to do it the GWT way.
I found it much simple to add javascript directly to the TR element. My code assumes that a widgets DOM parent is a TD and the grandparent is the TR so you need to be sure you know your DOM.
Here's my code. Nice and simple, no JSNI or GWT DOM event management required.
TableRowElement rowElement = (TableRowElement) checkbox.getElement().getParentElement().getParentElement();
rowElement.setAttribute("onMouseOver", "this.className='" + importRecordsResources.css().normalActive() + "'");
rowElement.setAttribute("onMouseOut", "this.className='" + importRecordsResources.css().normal() + "'");
I just did it this simple way:
protected void handleRowsSelectionStyles(ClickEvent event) {
int selectedRowIndex = fieldTable.getCellForEvent(event).getRowIndex();
int rowCount = fieldTable.getRowCount();
for (int row = 0; row < rowCount; row++) {
Element rowElem = fieldTable.getRowFormatter().getElement(row);
rowElem.setClassName(row == selectedRowIndex ? "row selected" : "row");
}
}
You call this method from the cells you want to be clickable
int row = 0;
for (final RowDataProxy rowData : rowDataList) {
Label fieldName = new Label(rowData.name());
fieldName.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
handleRowsSelectionStyles(event);
}
});
fieldTable.setWidget(row++, 0, fieldName);
}
Best Regards,
Zied Hamdi

Resources