i am having the same problem as this guy - my bar chart will only accept a fixed height in dp. If I use Fill-Parent, match_parent or wrap_content, the chart will be flat with a height of zero. And working with fixed sizes will not work on different screen sizes.
While this question is already floating around the internet (f.i. here), no one seems to have a decent solution. Any ideas?
android:fillViewport="true" did not help either.
My XML:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
tools:context="com.example.myself.myroom.Frontend.StatisticFragment">
<com.github.mikephil.charting.charts.BarChart
android:id="#+id/testchart"
android:layout_width="fill_parent"
android:layout_height="fill_parent"(or fixed number of dp) />
</FrameLayout> </layout>
the according fragment(only the chart part):
protected void onPostExecute(List<ItemS> result) {
// update the UI after background processes completes
List<ItemS> dataObjects = result;
List<BarEntry> entries = new ArrayList<BarEntry>();
final List<String> labels = new ArrayList<String>();
Integer testdummy = 0;
for (ItemS data : dataObjects) {
// turn your data into Entry objects
entries.add(new BarEntry( testdummy, data.get_dAmount().floatValue() ));
labels.add(data.getiCatID().toString());
testdummy++;
}
BarData data = new BarData(new BarDataSet(entries, "Labelerik"));
IAxisValueFormatter formatter = new IAxisValueFormatter() {
#Override
public String getFormattedValue(float value, AxisBase axis) {
return labels.get((int) value);
}
// we don't draw numbers, so no decimal digits needed
//#Override
//public int getDecimalDigits() { return 0; }
};
data.setBarWidth(0.9f); // set custom bar width
oBinding.testchart.setData(data);
oBinding.testchart.setFitBars(true); // make the x-axis fit exactly all bars
oBinding.testchart.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM);
oBinding.testchart.getXAxis().setGranularity(1f); // minimum axis-step (interval) is 1
oBinding.testchart.getXAxis().setValueFormatter(formatter);
oBinding.testchart.invalidate(); // refresh
}
Thanks for reading!
Related
change child framelayout height,width,gravity programmatically?
I have linearlayout as parent and framelayout as child now I want to change height and width of framelayout programmatically
code I tried but does not effect at all
public void frame_params(FrameLayout bottomFrameLayout, int weight, int height) {
bottomFrameLayout = new FrameLayout(context);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(weight, height);
lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
bottomFrameLayout.setLayoutParams(lp);
}
xml
<LinearLayout
android:orientation="horizontal"
android:id="#+id/relativelayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/hv_effect"
android:layout_below="#+id/effect_hedaer_toolbar">
<FrameLayout
android:id="#+id/FrameLayout"
android:layout_width="280dp"
android:layout_height="300dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_centerInParent="true"
android:layout_gravity="bottom|left">
</FrameLayout>
</Linearlayout>
I believe this line is your problem:
bottomFrameLayout = new FrameLayout(context);
In the frame_params method, you receive a FrameLayout. But, then, you instantiate a NEW one with that line. So, indeed, the FrameLayout inside the LinearLayout will continue the same way, because you are not changing it, you are creating a new FrameLayout and you're setting the parameters to it. Just try removing the aforementioned line, like this:
public void frame_params(FrameLayout bottomFrameLayout, int weight, int height) {
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(weight, height);
lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
bottomFrameLayout.setLayoutParams(lp);
}
And, then, pass the correct FrameLayout (the one with the id "FrameLayout", as specified in your xml), it should work.
Let me know if it worked, and, if it did, remember to upvote/select as the correct answer, cheers : )
I have following MAP which is populating my dropdown list; however, it changes the order of the options.
public static final Map SIZE = new TreeMap(){
{
put("-1"," ");
put("100","100m2");
put("200","200m2");
put("300","300m2");
put("400","400m2");
put("500","500m2");
put("600","600m2");
put("700","700m2");
put("800","800m2");
put("900","900m2");
put("1000","1000m2");
}
;
};
<s:select name="size" label="Size" list="#com.example.Lists#SIZE"/>
Options in dropbox
100m2
1000m2
200m2
300m2
....
TreeMap is sorted based on the natural order of the keys. Try changing your keys to integer:
public static final Map SIZE = new TreeMap(){
{
put(-1," ");
put(100,"100m2");
put(200,"200m2");
put(300,"300m2");
put(400,"400m2");
put(500,"500m2");
put(600,"600m2");
put(700,"700m2");
put(800,"800m2");
put(900,"900m2");
put(1000,"1000m2");
}
;
};
<s:select name="size" label="Size" list="#com.example.Lists#SIZE"/>
I'm trying to make a custom GTK widget in Vala, but I'm already failing at the very first basic attempt, so I'd like some help in knowing where I'm going wrong. I feel like I must be missing something painstakingly obvious, but I just can't see it.
I have three files with the following contents:
start.vala:
using Gtk;
namespace WTF
{
MainWindow main_window;
int main(string[] args)
{
Gtk.init(ref args);
main_window = new MainWindow();
Gtk.main();
return 0;
}
}
main_window.vala:
using Gtk;
namespace WTF
{
public class MainWindow : Window
{
public MainWindow()
{
/* */
Entry entry = new Entry();
entry.set_text("Yo!");
this.add(entry);
/* */
/*
CustomWidget cw = new CustomWidget();
this.add(cw);
/* */
this.window_position = WindowPosition.CENTER;
this.set_default_size(400, 200);
this.destroy.connect(Gtk.main_quit);
this.show_all();
}
}
}
custom_widget.vala:
using Gtk;
namespace WTF
{
public class CustomWidget : Bin
{
public CustomWidget()
{
Entry entry = new Entry();
entry.set_text("Yo");
this.add(entry);
this.show_all();
}
}
}
As you can see, in main_window.vala, I have two sets of code. One that adds the Entry widget directly, and one that adds my custom widget. If you run the one that adds the Entry widget directly, you get this result:
If you run the one with the custom widget, however, you get this result:
Just for the record, this is the complication command I use:
valac --pkg gtk+-2.0 start.vala main_window.vala custom_widget.vala -o wtf
EDIT:
Following user4815162342's suggestion, I implemented the size_allocate method on my custom Bin widget, like so:
public override void size_allocate(Gdk.Rectangle r)
{
stdout.printf("Size_allocate: %d,%d ; %d,%d\n", r.x, r.y, r.width, r.height);
Allocation a = Allocation() { x = r.x, y = r.y, width = r.width, height = r.height };
this.set_allocation(a);
stdout.printf("\tHas child: %s\n", this.child != null ? "true" : "false");
if (this.child != null)
{
int border_width = (int)this.border_width;
Gdk.Rectangle cr = Gdk.Rectangle()
{
x = r.x + border_width,
y = r.y + border_width,
width = r.width - 2 * border_width,
height = r.height - 2 * border_width
};
stdout.printf("\tChild size allocate: %d,%d ; %d, %d\n", cr.x, cr.y, cr.width, cr.height);
this.child.size_allocate(cr);
}
}
It writes the following in the console:
Size_allocate: 0,0 ; 400,200
Has child: true
Child size allocate: 0,0 ; 400, 200
And the window renders thusly:
GtkBin is an abstract single-child container, typically intended to decorate the child widget in some way, or change its visibility or size. Without some added value, a single-child container would be indistinguishable from the widget it contains and therefore not very useful.
Since GtkBin doesn't know what kind of decorations you will draw around the child, it expects you to implement your own size_allocate. A simple implementation is available in gtk_event_area_size_allocate, a more complex one in gtk_button_size_allocate.
This answer shows a minimal size_allocate implementation in PyGTK which should be straightforward to port to Vala. If you do anything more complex than that, you will need to also implement expose, and possibly other methods, but this will get you started.
I have 2 flex datagrids on a screen. The user can select one or more rows from either datagrid and move them to the other datagrid. The lower table is empty when entering the application. For example:
Item Color Price
--------------------
item57 red $5.55
item62 blue $5.29
item808 green $2.21
Row Item Color Price
---------------------------
Note there is a column that numbers the rows on the bottom datagrid (only).
When I enter the application and move, for example, 3 rows from the top to bottom grid, the row numbers are fine (they show rows 1, 2, and 3). For example:
Item Color Price
--------------------
Row Item Color Price
---------------------------
1 item57 red $5.55
2 item62 blue $5.29
3 item808 green $2.21
If I then move, for example, row 1 in the bottom grid back to the top...
Item Color Price
--------------------
item57 red $5.55
Row Item Color Price
---------------------------
1 item62 blue $5.29
2 item808 green $2.21
and then back again to the bottom grid...
Item Color Price
--------------------
Row Item Color Price
---------------------------
1 item62 blue $5.29
2 item808 green $2.21
1 item57 red $5.55
the row number is supposed to display 3 because it inserts into the bottom grid at the end of the list, but when it does this, it displays the (old) row number value of 1.
When I debug and look at the dataprovider = _myData, I see the rowNumber value for the row in question (for item57 above) equals 3 (as it should). However, it is displayed in the lower datagrid as 1.
How can the dataprovider value be different than what is displayed in the DataGrid?
[I can also debug and look at gridLower column information, and it also shows the correct value of 3 for rowNumber for the data in question.]
The lower datagrid is similar to the following (although I'm using a custom itemRenderer, removed for simplicity here):
[Bindable]
private var _myData:ListCollectionView=new ListCollectionView(new ArrayList());
...
<s:DataGrid dataProvider="{_myData}">
<s:columns>
<fx:Array>
<s:GridColumn id="gridLower" headerText="myHeader" dataField="rowNumber"/>
...
The function that adds the upper table's row(s) to the lower table is:
private function addRow():void {
var selectedIndices:Object=gridUpper.grid.selectedIndices;
for (var i:int=selectedIndices.length-1;i>=0;i--) {
var item:Object=_upperTableData.removeItemAt(selectedIndices[i]);
item.rowNumber=_myData.length+1;
_myData.list.addItem(item);
}
// I tried adding "_myData.refresh();" here and it had no effect
// I tried adding "ListCollectionView(gridLower.dataProvider).refresh();" and it had no effect
// I tried adding "grid2.dataProvider.refresh();" here but it had no effect
}
UPDATE 1: If I re-sort any column in the lower table, the correct values appear. I seem to be observing what's reported in this link:
http://www.barneyb.com/barneyblog/2007/06/23/another-flex-weirdnessgotcha/
Haven't found a solution yet though. See attempts in my addRow() function above. Am I on the right track?
UPDATE 2: While re-sorting manually corrects the data in the lower grid, I haven't found a way to do this programmatically. I tried inserting:
_myData.sort=null;
var complete:Boolean=_myData.refresh();
just before the end of addRow() function above, but it didn't resolve my issue. When debugging, complete is true, but still the lower grid displays the stale data.
New answer :) I will delete the old one if this helps.
I haven't used Spark DataGrid yet, was expecting it to behave like a List.
Found this in this in some comments in the source for this method of DataGrid:
public function invalidateCell(rowIndex:int, columnIndex:int):void
You can invalidate an entire row/col by passing -1 for the other value. In the quote from the docs below, you can also use dataProvider.itemUpdated()
If the specified cell is visible, it is redisplayed. If
variableRowHeight=true, then doing so may cause the height of the
corresponding row to change. If columnIndex is -1, then the entire row
is invalidated. Similarly if rowIndex is -1, then the entire column is
invalidated.
This method should be called when there is a change to any aspect of
the data provider item at rowIndex that might have some impact on the
way the specified cell is displayed. Calling this method is similar to
calling the dataProvider.itemUpdated() method, which advises the Grid
that all rows displaying the specified item should be redisplayed.
Using this method can be relatively efficient, since it narrows the
scope of the change to a single cell.
Now I finally know where the itemUpdated() method on collections (ArrayCollection, ListCollectionView) can actually be used!
[edit]
Give your grid an id:
<s:DataGrid id="lowerDataGrid" dataProvider="{_myData}">
Then you should be able to do this in your addRow() method after updating the collection:
lowerDataGrid.invalidateCell(item.rowNmber -1, 1); // assuming rowNumbers are 0 based
In my case, in my main class that contains the grid as an element, whenever I want to force a refresh of all the cells:
gridsDataProvider.addItemAt(new Object(), 0);
gridsDataProvider.removeItemAt(0);
But my GridItemRenderer needs to cater for the change in the data. So I created an updateDisplay method:
private function updateDisplay() : void {
if (transWindow != null) {
if (data == transWindow.total) {
if (field != "vat" && field != "total") {
textInput.visible = false;
} else {
line.visible = true;
textInput.enabled = false;
textInput.setStyle("fontWeight", "bold");
textInput.setStyle("fontSize", 14);
}
} else {
line.visible = false;
textInput.visible = true;
textInput.enabled = true;
textInput.setStyle("fontWeight", "normal");
textInput.setStyle("fontSize", 12);
}
}
}
This method is called from both the creationComplete handler ...
protected function init(event:FlexEvent):void
{
getTransWindow(event.target.automationOwner);
updateDisplay();
}
... well as the data setter of the GridItemRenderer
override public function set data(v:Object):void {
super.data = v;
if (v == null) {
textInput.text = "";
return;
}
var value : * = v[field];
if (value == null || value == undefined) {
textInput.text = "";
return;
}
if (value is Number)
textInput.text = Number(value).toFixed(2);
else
textInput.text = ""+value;
updateDisplay();
}
The mxml body of my renderer is quite simple:
<s:Line id="line" width="100%" visible="false" yFrom="1" yTo="1">
<s:stroke>
<s:SolidColorStroke color="0" weight="0"/>
</s:stroke>
</s:Line>
<s:TextInput id="textInput" y="2" restrict="0123456789." width="100%" height="100%" minWidth="10" borderVisible="false" textAlign="right"/>
O, in case you wondered, the getTransWindow method is just a method to retrieve the main calling class that contains the grid:
private function getTransWindow(par : *) : void {
if (transWindow != null)
return;
transWindow = par;
while (!(transWindow is TransactionWindow)) {
transWindow = transWindow.parent;
}
}
Hope this saves someone some time
Regards
Christo
I'm setting selected element in s:List component with Actionscript, it works, but List doesn't scroll to selected item -- need to scroll with scrollbar or mouse. Is it possible to auto-scroll to selected item ? Thanks !
Try the s:List method ensureIndexIsVisible(index:int):void.
For Spark:
list.ensureIndexIsVisible(index);
This function will scroll to the top of the list in Flex 4+. It takes in account the height of the item, so it will work for lists with different items with different height.
private function scrollToIndex(list:List,index:int):void
{
if (!list.layout)
return;
var dataGroup:DataGroup = list.dataGroup;
var spDelta:Point = dataGroup.layout.getScrollPositionDeltaToElement(index);
if (spDelta)
{
dataGroup.horizontalScrollPosition += spDelta.x;
//move it to the top if the list has enough items
if(spDelta.y > 0)
{
var maxVSP:Number = dataGroup.contentHeight - dataGroup.height;
var itemBounds:Rectangle = list.layout.getElementBounds(index);
var newHeight:Number = dataGroup.verticalScrollPosition + spDelta.y
+ dataGroup.height - itemBounds.height;
dataGroup.verticalScrollPosition = Math.min(maxVSP, newHeight);
}
else
{
dataGroup.verticalScrollPosition += spDelta.y;
}
}
}
//try this
this.callLater(updateIndex);//where you want to set the selectedIndex
private function updateIndex():void
{
list.selectedIndex = newIndex;
list.ensureIndexIsVisible(newIndex);
}
In flex-3 there is a scrollToIndex method and hence you can call
list.scrollToIndex(list.selectedIndex);
I believe this should work in flex-4 too.
This worked for me. had to use the callLater.
list.selectedItem = "MyTestItem"; //or list.selectedIndex = 10;
this.callLater(updateIndex); //dispatch an update to list
private function updateIndex():void {
list.ensureIndexIsVisible(list.selectedIndex);
}
I saw this basic idea here...
http://arthurnn.com/blog/2011/01/12/coverflow-layout-for-flex-4/
public function scrollGroup( n : int ) : void
{
var scrollPoint : Point = theList.layout.getScrollPositionDeltaToElement( n );
var duration : Number = ( Math.max( scrollPoint.x, theList.layout.target.horizontalScrollPosition ) - Math.min( scrollPoint.x, theList.layout.target.horizontalScrollPosition )) * .01;
Tweener.addTween(theList.layout,{ horizontalScrollPosition: scrollPoint.x , time:duration});
}
protected function theList_caretChangeHandler(event:IndexChangeEvent):void
{
scrollGroup( event.newIndex );
event.target.invalidateDisplayList();
}
You'll probably want to access the List's scroller directly and do something like:
list.scroller.scrollRect.y = list.itemRenderer.height * index;
You can multiply the height of an element by its index and pass this value to:
yourListID.scroller.viewport.verticalScrollPosition
It is a bug - you can see the demonstration and a workaround at the https://issues.apache.org/jira/browse/FLEX-33660
This custom List component extension worked for me:
<s:List
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
valueCommit="callLater(ensureIndexIsVisible, [selectedIndex])">
</s:List>
I recently accomplished this in one of my projects by having a defined size for my items in the group..
<s:Scroller x="940" y="0" maxHeight="465" maxWidth="940" horizontalScrollPolicy="off" verticalScrollPolicy="off">
<s:HGroup id="tutPane" columnWidth="940" variableColumnWidth="false" gap="0" x="0" y="0">
</s:HGroup>
</s:Scroller>
Following this my button controls for manipulation worked by incrementing a private "targetindex" variable, then I called a checkAnimation function, which used the Animate class, in combo with a SimpleMotionPath and a comparison between tutpane.firstIndexInView and target index. This modified the "horizontalScrollPosition" of the group.
This allowed separate controls to essentially act as a scroll bar, but I had the requirement of sliding the control to view the selected item.. I believe this technique could work for automated selection of items as well