How do I get libvlc_media_player_get_time() to return a more accurate result? - libvlc

With libvlc, how do I get libvlc_media_player_get_time() to return a more accurate result? With 60fps video the value it returns is only updated a few times per second at most. Is there any way to get frame accurate timing?

This issue says that there is no way to get more accurate result from libvlc.
But you can interpolate it:
private long lastPlayTime = 0;
private long lastPlayTimeGlobal = 0;
/**
* Get current play time (interpolated)
* #see https://github.com/caprica/vlcj/issues/74
* #return
*/
public float getCurrentTime(){
long currentTime = directMediaPlayer.getTime();
if (lastPlayTime == currentTime && lastPlayTime != 0){
currentTime += System.currentTimeMillis() - lastPlayTimeGlobal;
} else {
lastPlayTime = currentTime;
lastPlayTimeGlobal = System.currentTimeMillis();
}
return currentTime * 0.001f; //to float
}

Related

Convert a haxe.Int64 to a Float?

How can I convert a haxe.Int64 to a Float?
I've got something like
var x = haxe.Int64.parseString("1000000000000");
and I'd like to convert that to a Float. I've looked in the Int64 api docs, have found fromFloat, ofInt, and toInt, but there's no toFloat method in there.
I cannot see that functionality in the Haxe standard library either, I checked Int64 and Int64Helper.
However the MIT-licensed thx.core library does include an implementation, see below: https://github.com/fponticelli/thx.core/blob/master/src/thx/Int64s.hx#L137
using haxe.Int64;
class Int64s {
static var zero = Int64.make(0, 0);
static var one = Int64.make(0, 1);
static var min = Int64.make(0x80000000, 0);
/**
Converts an `Int64` to `Float`;
Implementation by Elliott Stoneham.
*/
public static function toFloat(i : Int64) : Float {
var isNegative = false;
if(i < 0) {
if(i < min)
return -9223372036854775808.0; // most -ve value can't be made +ve
isNegative = true;
i = -i;
}
var multiplier = 1.0,
ret = 0.0;
for(_ in 0...64) {
if(i.and(one) != zero)
ret += multiplier;
multiplier *= 2.0;
i = i.shr(1);
}
return (isNegative ? -1 : 1) * ret;
}
}
Using the library method worked for me, tested on the JavaScript target like so:
import haxe.Int64;
import thx.Int64s;
class Main {
public static function main():Void {
var x:Int64 = haxe.Int64.parseString("1000000000000");
var f:Float = thx.Int64s.toFloat(x);
trace(f); // Prints 1000000000000 to console (on js target)
}
}
Alternatively, you can convert Int64 to Float yourself by combining high/low halves:
class Test {
static function main() {
var x = haxe.Int64.parseString("1000000000000");
var f = x.high * 4294967296. + (x.low >>> 0);
trace("" + x);
trace(f);
}
}
Here,
4294967296. is a float literal for unsigned 2^32;
>>> 0 is required because the lower half can be signed.
Or, for a naive conversion method, you can use:
var f = Std.parseFloat(haxe.Int64.toStr(x));
You may want to try to use FPHelper class. It contains a set of methods to convert Int types to Float / Double.
import haxe.io.FPHelper;
class Test {
static function main() {
var x = haxe.Int64.parseString("1000000000000");
var f = FPHelper.i64ToDouble(x.low, x.high);
trace(f);
}
}
See https://try.haxe.org/#CDa93

Resize GameObject over time [duplicate]

I made a test game in unity that makes it so when I click on a button, it spawns a cylinder created from a factory class. I'm trying to make it so when I create the cylinder, its height shrinks over the next 20 seconds. Some methods I found are difficult to translate into what I'm doing. If you could lead me to the right direction, I'd very much appreciate it.
Here's my code for the cylinder class
public class Cylinder : Shape
{
public Cylinder()
{
GameObject cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
cylinder.transform.position = new Vector3(3, 0, 0);
cylinder.transform.localScale = new Vector3(1.0f, Random.Range(1, 2)-1*Time.deltaTime, 1.0f);
cylinder.GetComponent<MeshRenderer>().material.color = Random.ColorHSV();
Destroy(cylinder, 30.0f);
}
}
This can be done with the Time.deltaTime and Vector3.Lerp in a coroutine function. Similar to Rotate GameObject over time and Move GameObject over time questions. Modified it a little bit to do just this.
bool isScaling = false;
IEnumerator scaleOverTime(Transform objectToScale, Vector3 toScale, float duration)
{
//Make sure there is only one instance of this function running
if (isScaling)
{
yield break; ///exit if this is still running
}
isScaling = true;
float counter = 0;
//Get the current scale of the object to be moved
Vector3 startScaleSize = objectToScale.localScale;
while (counter < duration)
{
counter += Time.deltaTime;
objectToScale.localScale = Vector3.Lerp(startScaleSize, toScale, counter / duration);
yield return null;
}
isScaling = false;
}
USAGE:
Will scale GameObject within 20 seconds:
StartCoroutine(scaleOverTime(cylinder.transform, new Vector3(0, 0, 90), 20f));
Check out Lerp. A general example of how to use it would be something like this:
float t = 0;
Update()
{
t += Time.deltaTime;
cylinder.localScale = new Vector3(1, Mathf.Lerp(2f, 1f, t/3f), 1); // shrink from 2 to 1 over 3 seconds;
}
You will create a new monobehaviour script and add it to your primitive. Then you wil use "Update" method of monobehaviour (or use coroutine) for change object over time.
Monobehaviour must be look like this:
public class ShrinkBehaviour : MonoBehaviour
{
bool isNeedToShrink;
Config currentConfig;
float startTime;
float totalDistance;
public void StartShrink(Config config)
{
startTime = Time.time;
currentConfig = config;
totalDistance = Vector3.Distance(currentConfig.startSize, currentConfig.destinationSize);
isNeedToShrink = true;
transform.localScale = config.startSize;
}
private void Update()
{
if (isNeedToShrink)
{
var nextSize = GetNextSize(currentConfig);
if (Vector3.Distance(nextSize, currentConfig.destinationSize) <= 0.05f)
{
isNeedToShrink = false;
return;
}
transform.localScale = nextSize;
}
}
Vector3 GetNextSize(Config config)
{
float timeCovered = (Time.time - startTime) / config.duration;
var result = Vector3.Lerp(config.startSize, config.destinationSize, timeCovered);
return result;
}
public struct Config
{
public float duration;
public Vector3 startSize;
public Vector3 destinationSize;
}
}
For using this, you must do next:
public Cylinder()
{
GameObject cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
var shrink = cylinder.AddComponent<ShrinkBehaviour>();
shrink.StartShrink(new ShrinkBehaviour.Config() { startSize = Vector3.one * 10, destinationSize = Vector3.one * 1, duration = 20f });
cylinder.transform.position = new Vector3(3, 0, 0);
cylinder.GetComponent<MeshRenderer>().material.color = Random.ColorHSV();
Destroy(cylinder, 30.0f);
}
You must remember, monobehaviour-script must be in separate file, and must have name similar to monobehaviour-class name. For example, ShrinkBehaviour.cs;

Stream.CopyTo(newStream) return Length 0

I try to make some concatenation of buffers which are saved in a memory streams. Then, when I'm trying to play the whole buffer it gives an exception:
An exception of type 'System.ArgumentException' occurred in
Microsoft.Xna.Framework.ni.dll but was not handled in user code
Additional information: Ensure that the buffer length is non-zero and
meets the block alignment requirements for the audio format.
When I debug the mStrm is still remains 0, can't find why.
private void mySendClick(object sender, RoutedEventArgs e)
{
var mStrmStartDelimiter = new MemoryStream();
var mStrmEndDelimiter = new MemoryStream();
BinaryWriter writer1 = new BinaryWriter(mStrmStartDelimiter);
Sinus(6500, 200, writer1, 32767);
BinaryWriter writer2 = new BinaryWriter(mStrmEndDelimiter);
Sinus(6800, 200, writer2, 32767);
var mStrm = new MemoryStream();
mStrmStartDelimiter.CopyTo(mStrm);
//ToDO
mStrmEndDelimiter.CopyTo(mStrm);
mStrm.Seek(0, SeekOrigin.Begin);
SoundEffect mySoundPlay = new SoundEffect(mStrm.ToArray(), 16000, AudioChannels.Mono);
mySoundPlay.Play();
}
public static void Sinus(double frequency, int msDuration, BinaryWriter writer, int volume)
{
double TAU = 2 * Math.PI;
double samplesPerSecond = 16000;
double theta = frequency * TAU / (double)samplesPerSecond;
int samples = (int)((decimal)samplesPerSecond * msDuration / 1000);
// 'volume' is UInt16 with range 0 thru Uint16.MaxValue ( = 65 535)
// we need 'amp' to have the range of 0 thru Int16.MaxValue ( = 32 767)
double amp = volume >> 2; // so we simply set amp = volume / 2
for (int step = 0; step < samples; step++)
{
short s = (short)(amp * Math.Sin(theta * (double)step));
writer.Write(s);
}
}
I'm targeting windows phone 8.1 silverlight platform
I got the solution for the problem: do the following before calling CopyTo()
mStrmStartDelimiter.Position = 0;
mStrmEndDelimiter.Position = 0;

JavaFX 2.x : Logarithmic scale on Y axis

As from this very good post here
Logarithmic scale in Java FX 2
I have changed this class to get log scale on Y axis, and it works fine. The only problem I have is that there are very few horizontal grid lines and scale always start ranges from 0 or near zero.
Here is what I get
I would like to have tick values grid also in the min and max range of my data serie, in this case min = 19,35 max = 20,35; as of now all 10 horizontal grid lines are all plotted outside this range.
How to accomplish this?
Thanks all, here is my log code for Y axis
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.chart.ValueAxis;
//http://blog.dooapp.com/logarithmic-scale-strikes-back-in-javafx-20
public class LogarithmicAxis extends ValueAxis<Number> {
//Create our LogarithmicAxis class that extends ValueAxis<Number> and define two properties that will represent the log lower and upper bounds of our axis.
private final DoubleProperty logUpperBound = new SimpleDoubleProperty();
private final DoubleProperty logLowerBound = new SimpleDoubleProperty();
//
//we bind our properties with the default bounds of the value axis. But before, we should verify the given range according to the mathematic logarithmic interval definition.
public LogarithmicAxis() {
super(1, 100);
bindLogBoundsToDefaultBounds();
}
public LogarithmicAxis(double lowerBound, double upperBound) {
super(lowerBound, upperBound);
try {
validateBounds(lowerBound, upperBound);
bindLogBoundsToDefaultBounds();
} catch (IllegalLogarithmicRangeException e) {
}
}
/**
* Bind our logarithmic bounds with the super class bounds, consider the base 10 logarithmic scale.
*/
private void bindLogBoundsToDefaultBounds() {
logLowerBound.bind(new DoubleBinding() {
{
super.bind(lowerBoundProperty());
}
#Override
protected double computeValue() {
return Math.log10(lowerBoundProperty().get());
}
});
logUpperBound.bind(new DoubleBinding() {
{
super.bind(upperBoundProperty());
}
#Override
protected double computeValue() {
return Math.log10(upperBoundProperty().get());
}
});
}
/**
* Validate the bounds by throwing an exception if the values are not conform to the mathematics log interval:
* ]0,Double.MAX_VALUE]
*
* #param lowerBound
* #param upperBound
* #throws IllegalLogarithmicRangeException
*/
private void validateBounds(double lowerBound, double upperBound) throws IllegalLogarithmicRangeException {
if (lowerBound < 0 || upperBound < 0 || lowerBound > upperBound) {
throw new IllegalLogarithmicRangeException(
"The logarithmic range should be include to ]0,Double.MAX_VALUE] and the lowerBound should be less than the upperBound");
}
}
//Now we have to implement all abstract methods of the ValueAxis class.
//The first one, calculateMinorTickMarks is used to get the list of minor tick marks position that you want to display on the axis. You could find my definition below. It's based on the number of minor tick and the logarithmic formula.
#Override
protected List<Number> calculateMinorTickMarks() {
Number[] range = getRange();
List<Number> minorTickMarksPositions = new ArrayList<>();
if (range != null) {
Number lowerBound = range[0];
Number upperBound = range[1];
double logUpperBound = Math.log10(upperBound.doubleValue());
double logLowerBound = Math.log10(lowerBound.doubleValue());
int minorTickMarkCount = getMinorTickCount();
for (double i = logLowerBound; i <= logUpperBound; i += 1) {
for (double j = 0; j <= 10; j += (1. / minorTickMarkCount)) {
double value = j * Math.pow(10, i);
minorTickMarksPositions.add(value);
}
}
}
return minorTickMarksPositions;
}
//Then, the calculateTickValues method is used to calculate a list of all the data values for each tick mark in range, represented by the second parameter. The formula is the same than previously but here we want to display one tick each power of 10.
#Override
protected List<Number> calculateTickValues(double length, Object range) {
List<Number> tickPositions = new ArrayList<Number>();
if (range != null) {
Number lowerBound = ((Number[]) range)[0];
Number upperBound = ((Number[]) range)[1];
double logLowerBound = Math.log10(lowerBound.doubleValue());
double logUpperBound = Math.log10(upperBound.doubleValue());
System.out.println("lower bound is: " + lowerBound.doubleValue());
for (double i = logLowerBound; i <= logUpperBound; i += 1) {
for (double j = 1; j <= 10; j++) {
double value = (j * Math.pow(10, i));
tickPositions.add(value);
}
}
}
return tickPositions;
}
//The getRange provides the current range of the axis. A basic implementation is to return an array of the lowerBound and upperBound properties defined into the ValueAxis class.
#Override
protected Number[] getRange() {
return new Number[] { lowerBoundProperty().get(), upperBoundProperty().get() };
}
//The getTickMarkLabel is only used to convert the number value to a string that will be displayed under the tickMark. Here I choose to use a number formatter.
#Override
protected String getTickMarkLabel(Number value) {
NumberFormat formatter = NumberFormat.getInstance();
formatter.setMaximumIntegerDigits(6);
formatter.setMinimumIntegerDigits(1);
return formatter.format(value);
}
//The method setRange is used to update the range when data are added into the chart. There is two possibilities, the axis is animated or not. The simplest case is to set the lower and upper bound properties directly with the new values.
#Override
protected void setRange(Object range, boolean animate) {
if (range != null) {
Number lowerBound = ((Number[]) range)[0];
Number upperBound = ((Number[]) range)[1];
try {
validateBounds(lowerBound.doubleValue(), upperBound.doubleValue());
} catch (IllegalLogarithmicRangeException e) {
}
lowerBoundProperty().set(lowerBound.doubleValue());
upperBoundProperty().set(upperBound.doubleValue());
}
}
//We are almost done but we forgot to override 2 important methods that are used to perform the matching between data and the axis (and the reverse).
#Override
public Number getValueForDisplay(double displayPosition) {
double delta = logUpperBound.get() - logLowerBound.get();
if (getSide().isVertical()) {
return Math.pow(10, (((displayPosition - getHeight()) / -getHeight()) * delta) + logLowerBound.get());
} else {
return Math.pow(10, (((displayPosition / getWidth()) * delta) + logLowerBound.get()));
}
}
#Override
public double getDisplayPosition(Number value) {
double delta = logUpperBound.get() - logLowerBound.get();
double deltaV = Math.log10(value.doubleValue()) - logLowerBound.get();
if (getSide().isVertical()) {
return (1. - ((deltaV) / delta)) * getHeight();
} else {
return ((deltaV) / delta) * getWidth();
}
}
/**
* Exception to be thrown when a bound value isn't supported by the logarithmic axis<br>
*
*
* #author Kevin Senechal mailto: kevin.senechal#dooapp.com
*
*/
public class IllegalLogarithmicRangeException extends Exception {
/**
* #param string
*/
public IllegalLogarithmicRangeException(String message) {
super(message);
}
}
}
We too had these problems with the suggested implementation of logarithmicaxis, here is the complete code with fixes that worked for us..
import com.sun.javafx.charts.ChartLayoutAnimator;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.chart.ValueAxis;
import javafx.util.Duration;
//http://blog.dooapp.com/logarithmic-scale-strikes-back-in-javafx-20
//Edited by Vadim Levit & Benny Lutati for usage in AgentZero ( https://code.google.com/p/azapi-test/ )
public class LogarithmicNumberAxis extends ValueAxis<Number> {
private Object currentAnimationID;
private final ChartLayoutAnimator animator = new ChartLayoutAnimator(this);
//Create our LogarithmicAxis class that extends ValueAxis<Number> and define two properties that will represent the log lower and upper bounds of our axis.
private final DoubleProperty logUpperBound = new SimpleDoubleProperty();
private final DoubleProperty logLowerBound = new SimpleDoubleProperty();
//
//we bind our properties with the default bounds of the value axis. But before, we should verify the given range according to the mathematic logarithmic interval definition.
public LogarithmicNumberAxis() {
super(1, 10000000);
bindLogBoundsToDefaultBounds();
}
public LogarithmicNumberAxis(double lowerBound, double upperBound) {
super(lowerBound, upperBound);
validateBounds(lowerBound, upperBound);
bindLogBoundsToDefaultBounds();
}
public void setLogarithmizedUpperBound(double d) {
double nd = Math.pow(10, Math.ceil(Math.log10(d)));
setUpperBound(nd == d ? nd * 10 : nd);
}
/**
* Bind our logarithmic bounds with the super class bounds, consider the
* base 10 logarithmic scale.
*/
private void bindLogBoundsToDefaultBounds() {
logLowerBound.bind(new DoubleBinding() {
{
super.bind(lowerBoundProperty());
}
#Override
protected double computeValue() {
return Math.log10(lowerBoundProperty().get());
}
});
logUpperBound.bind(new DoubleBinding() {
{
super.bind(upperBoundProperty());
}
#Override
protected double computeValue() {
return Math.log10(upperBoundProperty().get());
}
});
}
/**
* Validate the bounds by throwing an exception if the values are not
* conform to the mathematics log interval: ]0,Double.MAX_VALUE]
*
* #param lowerBound
* #param upperBound
* #throws IllegalLogarithmicRangeException
*/
private void validateBounds(double lowerBound, double upperBound) throws IllegalLogarithmicRangeException {
if (lowerBound < 0 || upperBound < 0 || lowerBound > upperBound) {
throw new IllegalLogarithmicRangeException(
"The logarithmic range should be in [0,Double.MAX_VALUE] and the lowerBound should be less than the upperBound");
}
}
//Now we have to implement all abstract methods of the ValueAxis class.
//The first one, calculateMinorTickMarks is used to get the list of minor tick marks position that you want to display on the axis. You could find my definition below. It's based on the number of minor tick and the logarithmic formula.
#Override
protected List<Number> calculateMinorTickMarks() {
List<Number> minorTickMarksPositions = new ArrayList<>();
return minorTickMarksPositions;
}
//Then, the calculateTickValues method is used to calculate a list of all the data values for each tick mark in range, represented by the second parameter. The formula is the same than previously but here we want to display one tick each power of 10.
#Override
protected List<Number> calculateTickValues(double length, Object range) {
LinkedList<Number> tickPositions = new LinkedList<>();
if (range != null) {
double lowerBound = ((double[]) range)[0];
double upperBound = ((double[]) range)[1];
for (double i = Math.log10(lowerBound); i <= Math.log10(upperBound); i++) {
tickPositions.add(Math.pow(10, i));
}
if (!tickPositions.isEmpty()) {
if (tickPositions.getLast().doubleValue() != upperBound) {
tickPositions.add(upperBound);
}
}
}
return tickPositions;
}
/**
* The getRange provides the current range of the axis. A basic
* implementation is to return an array of the lowerBound and upperBound
* properties defined into the ValueAxis class.
*
* #return
*/
#Override
protected double[] getRange() {
return new double[]{
getLowerBound(),
getUpperBound()
};
}
/**
* The getTickMarkLabel is only used to convert the number value to a string
* that will be displayed under the tickMark. Here I choose to use a number
* formatter.
*
* #param value
* #return
*/
#Override
protected String getTickMarkLabel(Number value) {
NumberFormat formatter = NumberFormat.getInstance();
formatter.setMaximumIntegerDigits(10);
formatter.setMinimumIntegerDigits(1);
return formatter.format(value);
}
/**
* The method setRange is used to update the range when data are added into
* the chart. There is two possibilities, the axis is animated or not. The
* simplest case is to set the lower and upper bound properties directly
* with the new values.
*
* #param range
* #param animate
*/
#Override
protected void setRange(Object range, boolean animate) {
if (range != null) {
final double[] rangeProps = (double[]) range;
final double lowerBound = rangeProps[0];
final double upperBound = rangeProps[1];
final double oldLowerBound = getLowerBound();
setLowerBound(lowerBound);
setUpperBound(upperBound);
if (animate) {
animator.stop(currentAnimationID);
currentAnimationID = animator.animate(
new KeyFrame(Duration.ZERO,
new KeyValue(currentLowerBound, oldLowerBound)
),
new KeyFrame(Duration.millis(700),
new KeyValue(currentLowerBound, lowerBound)
)
);
} else {
currentLowerBound.set(lowerBound);
}
}
}
/**
* We are almost done but we forgot to override 2 important methods that are
* used to perform the matching between data and the axis (and the reverse).
*
* #param displayPosition
* #return
*/
#Override
public Number getValueForDisplay(double displayPosition) {
double delta = logUpperBound.get() - logLowerBound.get();
if (getSide().isVertical()) {
return Math.pow(10, (((displayPosition - getHeight()) / -getHeight()) * delta) + logLowerBound.get());
} else {
return Math.pow(10, (((displayPosition / getWidth()) * delta) + logLowerBound.get()));
}
}
#Override
public double getDisplayPosition(Number value) {
double delta = logUpperBound.get() - logLowerBound.get();
double deltaV = Math.log10(value.doubleValue()) - logLowerBound.get();
if (getSide().isVertical()) {
return (1. - ((deltaV) / delta)) * getHeight();
} else {
return ((deltaV) / delta) * getWidth();
}
}
/**
* Exception to be thrown when a bound value isn't supported by the
* logarithmic axis<br>
*
*
* #author Kevin Senechal mailto: kevin.senechal#dooapp.com
*
*/
public class IllegalLogarithmicRangeException extends RuntimeException {
/**
* #param string
*/
public IllegalLogarithmicRangeException(String message) {
super(message);
}
}
}
I think your problem is this:
super(1, 100);
From the documentation:
Create a non-auto-ranging ValueAxis with the given upper & lower bound
Try using a constructor without parameters, which will make the boundaries auto-ranging.
You should end up with a constructor looking like this:
public LogarithmicAxis() {
// was: super(1, 100);
super();
bindLogBoundsToDefaultBounds();
}

How to implement date picker in lwuit?

I'm developing a mobile app using j2me and lwuit.
There is a lcdui DateField (act as date picker) in j2me. Like that there is any component or item in lwuit.
How to implement the date picker (Similar to lcdui DateField) in lwuit.
The calendar (in lwuit) object is not user friendly. If phone screen size is small then it will not be correctly shown. In normal j2me (lcdui) the datefield has very good look. I want to create a component/item like that in lwuit (using lwuit in j2me).
You can use lcdui DateField in lwuit. I do it by this way:
import java.util.Calendar;
import java.util.Date;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.DateField;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import com.sun.lwuit.Button;
import com.sun.lwuit.Display;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.events.ActionListener;
import com.sun.lwuit.plaf.UIManager;
public class DatePicker extends Button implements ActionListener {
private static final String OK = "ok";
private static final String CANCEL = "cancel";
private Date date;
public DatePicker() {
setUIID("TextArea");
addActionListener(this);
}
public Date getDate() {
return date;
}
public void actionPerformed(ActionEvent evt) {
final Form dateForm = new Form();
final DateField dateField = new DateField(null, DateField.DATE);
if (date != null) {
dateField.setDate(date);
}
dateForm.append(dateField);
final javax.microedition.lcdui.Command acceptCommand = new javax.microedition.lcdui.Command(UIManager.getInstance().localize(OK, OK),
javax.microedition.lcdui.Command.OK, 0);
final javax.microedition.lcdui.Command cancelCommand = new javax.microedition.lcdui.Command(UIManager.getInstance().localize(CANCEL, CANCEL), javax.microedition.lcdui.Command.CANCEL, 0);
dateForm.addCommand(acceptCommand);
dateForm.addCommand(cancelCommand);
CommandListener commandListener = new CommandListener() {
public void commandAction(javax.microedition.lcdui.Command command, Displayable displayable) {
if (command == acceptCommand && dateField.getDate() != null) {
DatePicker.this.date = dateField.getDate();
DatePicker.this.setText(DatePicker.toString(DatePicker.this.date));
}
Display.init(Application.getInstance().midlet); // You have to save your midlet
Application.getInstance().mainForm.show(); // and the last lwuit Form
}
};
dateForm.setCommandListener(commandListener);
javax.microedition.lcdui.Display.getDisplay(Application.getInstance().midlet).setCurrent(dateForm); // Application.getInstance().midlet - your j2me application midlet
}
}
So now you can use it like lwuit Component, but on the actionPerformed it will open lcdui native Form with DateField on the top.
I have developed a calender extending component and it work fine in LWUIT and the code I used as follows
public class Calendar extends Container {
private ComboBox month;
private ComboBox year;
private MonthView mv;
private static final String[] MONTHS = new String[]{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
private static final String[] DAYS = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
private static final String[] LABELS = {"Su", "M", "Tu", "W", "Th", "F", "Sa"};
static final long MINUTE = 1000 * 60;
static final long HOUR = MINUTE * 60;
static final long DAY = HOUR * 24;
static final long WEEK = DAY * 7;
private EventDispatcher dispatcher = new EventDispatcher();
private EventDispatcher dataChangeListeners = new EventDispatcher();
private long[] dates = new long[42];
private boolean changesSelectedDateEnabled = true;
private TimeZone tmz;
private static ComboListCellRenderer comboListCellRenderer = new ComboListCellRenderer();;
private int[] bgColorArray = new int[]{0x2E9AFE, 0x39FEB6, 0x39FEB6};
/**
* Creates a new instance of Calendar set to the given date based on time
* since epoch (the java.util.Date convention)
*
* #param time time since epoch
*/
public Calendar(int[] bgColorArray, ListCellRenderer listCellRenderer, long time) {
this(bgColorArray, listCellRenderer, time, java.util.TimeZone.getDefault());
}
/**
* Constructs a calendar with the current date and time
*/
public Calendar(int[] bgColorArray, ListCellRenderer listCellRenderer) {
this(bgColorArray, listCellRenderer, System.currentTimeMillis());
}
/**
* Constructs a calendar with the current date and time
*/
public Calendar() {
this(null, comboListCellRenderer, System.currentTimeMillis());
}
/**
* Creates a new instance of Calendar set to the given date based on time
* since epoch (the java.util.Date convention)
*
* #param time time since epoch
* #param tmz a reference timezone
*/
public Calendar(int[] bgColorArray, ListCellRenderer listCellRenderer, long time, TimeZone tmz) {
super(new BorderLayout());
if(bgColorArray != null)
this.bgColorArray = bgColorArray;
this.tmz = tmz;
setUIID("Calendar");
Container upper = new Container(new FlowLayout(Component.CENTER));
month = new ComboBox();
year = new ComboBox();
mv = new MonthView(time);
Vector months = new Vector();
for (int i = 0; i < MONTHS.length; i++) {
months.addElement("" + getLocalizedMonth(i));
}
ListModel monthsModel = new DefaultListModel(months);
int selected = months.indexOf(getLocalizedMonth(mv.getMonth()));
month.setModel(monthsModel);
month.setSelectedIndex(selected);
month.addActionListener(mv);
if(listCellRenderer != null){
month.setListCellRenderer(listCellRenderer);
year.setListCellRenderer(listCellRenderer);
}
month.getSelectedStyle().setBgColor(bgColorArray[1]);
month.getUnselectedStyle().setBgColor(bgColorArray[0]);
month.getPressedStyle().setBgColor(bgColorArray[2]);
year.getSelectedStyle().setBgColor(bgColorArray[1]);
year.getUnselectedStyle().setBgColor(bgColorArray[0]);
year.getPressedStyle().setBgColor(bgColorArray[2]);
/* month.getSelectedStyle().setBgColor(0xff00000);
year.getSelectedStyle().setBgColor(0xff00000);
ComboListCellRenderer comboListCellRenderer = new ComboListCellRenderer();
*/
java.util.Calendar cal = java.util.Calendar.getInstance(tmz);
cal.setTime(new java.util.Date(time));
month.getStyle().setBgTransparency(0);
int y = cal.get(java.util.Calendar.YEAR);
Vector years = new Vector();
for (int i = 2100; i > 1900; i--) {
years.addElement("" + i);
}
ListModel yearModel = new DefaultListModel(years);
selected = years.indexOf("" + y);
year.setModel(yearModel);
year.setSelectedIndex(selected);
year.getStyle().setBgTransparency(0);
year.addActionListener(mv);
Container cnt = new Container(new BoxLayout(BoxLayout.X_AXIS));
cnt.setRTL(false);
Container dateCnt = new Container(new BoxLayout(BoxLayout.X_AXIS));
dateCnt.setUIID("CalendarDate");
dateCnt.addComponent(month);
dateCnt.addComponent(year);
cnt.addComponent(dateCnt);
upper.addComponent(cnt);
addComponent(BorderLayout.NORTH, upper);
addComponent(BorderLayout.CENTER, mv);
}
/**
* Returns the time for the current calendar.
*
* #return the time for the current calendar.
*/
public long getSelectedDay() {
return mv.getSelectedDay();
}
private String getLocalizedMonth(int i) {
Hashtable t = UIManager.getInstance().getResourceBundle();
String text = MONTHS[i];
if (t != null) {
Object o = t.get("Calendar." + text);
if (o != null) {
text = (String) o;
}
}
return text;
}
void componentChanged() {
java.util.Calendar cal = java.util.Calendar.getInstance(tmz);
cal.set(java.util.Calendar.YEAR, mv.getYear());
cal.set(java.util.Calendar.MONTH, mv.getMonth());
cal.set(java.util.Calendar.DAY_OF_MONTH, mv.getDayOfMonth());
month.getParent().revalidate();
}
/**
* Return the date object matching the current selection
*
* #return the date object matching the current selection
*/
public Date getDate() {
return new Date(mv.getSelectedDay());
}
/**
* Sets the current date in the view and the selected date to be the same.
*
* #param d new date
*/
public void setDate(Date d) {
mv.setSelectedDay(d.getTime());
mv.setCurrentDay(mv.currentDay, true);
componentChanged();
}
/**
* This method sets the Calendar selected day
* #param d the selected day
*/
public void setSelectedDate(Date d){
mv.setSelectedDay(d.getTime());
}
/**
* Sets the Calendar view on the given date, only the the month and year
* are being considered.
*
* #param d the date to set the calendar view on.
*/
public void setCurrentDate(Date d){
mv.setCurrentDay(d.getTime(), true);
componentChanged();
}
/**
* Sets the Calendar timezone, if not specified Calendar will use the
* default timezone
* #param tmz the timezone
*/
public void setTimeZone(TimeZone tmz){
this.tmz = tmz;
}
/**
* Gets the Calendar timezone
*
* #return Calendar TimeZone
*/
public TimeZone getTimeZone(){
return tmz;
}
/**
* Sets the selected style of the month view component within the calendar
*
* #param s style for the month view
*/
public void setMonthViewSelectedStyle(Style s) {
mv.setSelectedStyle(s);
}
/**
* Sets the un selected style of the month view component within the calendar
*
* #param s style for the month view
*/
public void setMonthViewUnSelectedStyle(Style s) {
mv.setUnselectedStyle(s);
}
/**
* Gets the selected style of the month view component within the calendar
*
* #return the style of the month view
*/
public Style getMonthViewSelectedStyle() {
return mv.getSelectedStyle();
}
/**
* Gets the un selected style of the month view component within the calendar
*
* #return the style of the month view
*/
public Style getMonthViewUnSelectedStyle() {
return mv.getUnselectedStyle();
}
/**
* Fires when a change is made to the month view of this component
*
* #param l listener to add
*/
public void addActionListener(ActionListener l) {
mv.addActionListener(l);
}
/**
* Fires when a change is made to the month view of this component
*
* #param l listener to remove
*/
public void removeActionListener(ActionListener l) {
mv.removeActionListener(l);
}
/**
* Allows tracking selection changes in the calendar in real time
*
* #param l listener to add
*/
public void addDataChangeListener(DataChangedListener l) {
mv.addDataChangeListener(l);
}
/**
* Allows tracking selection changes in the calendar in real time
*
* #param l listener to remove
*/
public void removeDataChangeListener(DataChangedListener l) {
mv.removeDataChangeListener(l);
}
/**
* This flag determines if selected date can be changed by selecting an
* alternative date
*
* #param changesSelectedDateEnabled if true pressing on a date will cause
* the selected date to be changed to the pressed one
*/
public void setChangesSelectedDateEnabled(boolean changesSelectedDateEnabled) {
this.changesSelectedDateEnabled = changesSelectedDateEnabled;
}
/**
* This flag determines if selected date can be changed by selecting an
* alternative date
*
* #return true if enabled
*/
public boolean isChangesSelectedDateEnabled() {
return changesSelectedDateEnabled;
}
/**
* This method creates the Day Button Component for the Month View
*
* #return a Button that corresponds to the Days Components
*/
protected Button createDay() {
Button day = new Button();
day.setAlignment(CENTER);
day.setUIID("CalendarDay");
day.setEndsWith3Points(false);
day.setTickerEnabled(false);
return day;
}
/**
* This method creates the Day title Component for the Month View
*
* #param day the relevant day values are 0-6 where 0 is sunday.
* #return a Label that corresponds to the relevant Day
*/
protected Label createDayTitle(int day) {
String value = UIManager.getInstance().localize("Calendar." + DAYS[day], LABELS[day]);
Label dayh = new Label(value, "CalendarTitle");
dayh.setEndsWith3Points(false);
dayh.setTickerEnabled(false);
return dayh;
}
/**
* This method updates the Button day.
*
* #param dayButton the button to be updated
* #param day the new button day
*/
protected void updateButtonDayDate(Button dayButton, int currentMonth, int day) {
dayButton.setText("" + day);
}
class MonthView extends Container implements ActionListener{
private long currentDay;
private Button[] buttons = new Button[42];
private Button selected;
private long selectedDay = -1;
public MonthView(long time) {
super(new GridLayout(7, 7));
setUIID("MonthView");
for (int iter = 0; iter < DAYS.length; iter++) {
addComponent(createDayTitle(iter));
}
for (int iter = 0; iter < buttons.length; iter++) {
buttons[iter] = createDay();
addComponent(buttons[iter]);
if (iter <= 7) {
buttons[iter].setNextFocusUp(year);
}
buttons[iter].addActionListener(this);
}
setCurrentDay(time);
}
public void setCurrentDay(long day){
setCurrentDay(day, false);
}
private void setCurrentDay(long day, boolean force) {
repaint();
java.util.Calendar cal = java.util.Calendar.getInstance(tmz);
cal.setTime(new Date(currentDay));
cal.set(java.util.Calendar.HOUR, 1);
cal.set(java.util.Calendar.HOUR_OF_DAY, 1);
cal.set(java.util.Calendar.MINUTE, 0);
cal.set(java.util.Calendar.SECOND, 0);
cal.set(java.util.Calendar.MILLISECOND, 0);
int yearOld = cal.get(java.util.Calendar.YEAR);
int monthOld = cal.get(java.util.Calendar.MONTH);
int dayOld = cal.get(java.util.Calendar.DAY_OF_MONTH);
cal.setTime(new Date(day));
cal.set(java.util.Calendar.HOUR, 1);
cal.set(java.util.Calendar.HOUR_OF_DAY, 1);
cal.set(java.util.Calendar.MINUTE, 0);
cal.set(java.util.Calendar.SECOND, 0);
cal.set(java.util.Calendar.MILLISECOND, 0);
int yearNew = cal.get(java.util.Calendar.YEAR);
int monthNew = cal.get(java.util.Calendar.MONTH);
int dayNew = cal.get(java.util.Calendar.DAY_OF_MONTH);
year.setSelectedItem("" + yearNew);
month.setSelectedIndex(monthNew);
if (yearNew != yearOld || monthNew != monthOld || dayNew != dayOld || force) {
currentDay = cal.getTime().getTime();
if(selectedDay == -1){
selectedDay = currentDay;
}
int month = cal.get(java.util.Calendar.MONTH);
cal.set(java.util.Calendar.DAY_OF_MONTH, 1);
long startDate = cal.getTime().getTime();
int dow = cal.get(java.util.Calendar.DAY_OF_WEEK);
cal.setTime(new Date(cal.getTime().getTime() - DAY));
cal.set(java.util.Calendar.HOUR, 1);
cal.set(java.util.Calendar.HOUR_OF_DAY, 1);
cal.set(java.util.Calendar.MINUTE, 0);
cal.set(java.util.Calendar.SECOND, 0);
cal.set(java.util.Calendar.MILLISECOND, 0);
int lastDay = cal.get(java.util.Calendar.DAY_OF_MONTH);
int i = 0;
if(dow > java.util.Calendar.SUNDAY){
//last day of previous month
while (dow > java.util.Calendar.SUNDAY) {
cal.setTime(new Date(cal.getTime().getTime() - DAY));
dow = cal.get(java.util.Calendar.DAY_OF_WEEK);
}
int previousMonthSunday = cal.get(java.util.Calendar.DAY_OF_MONTH);
for (; i <= lastDay - previousMonthSunday; i++) {
buttons[i].setUIID("CalendarDay");
buttons[i].setEnabled(false);
buttons[i].setText("" + (previousMonthSunday + i));
}
}
//last day of current month
cal.set(java.util.Calendar.MONTH, (month + 1) % 12);
cal.set(java.util.Calendar.DAY_OF_MONTH, 1);
cal.setTime(new Date(cal.getTime().getTime() - DAY));
lastDay = cal.get(java.util.Calendar.DAY_OF_MONTH);
int j = i;
for (; j < buttons.length && (j - i + 1) <= lastDay; j++) {
buttons[j].setEnabled(true);
dates[j] = startDate;
if(dates[j] == selectedDay){
buttons[j].setUIID("CalendarSelectedDay");
selected = buttons[j];
}else{
buttons[j].setUIID("CalendarDay");
}
buttons[j].getSelectedStyle().setBgColor(bgColorArray[1]);
buttons[j].getUnselectedStyle().setBgColor(bgColorArray[0]);
buttons[j].getPressedStyle().setBgColor(bgColorArray[2]);
buttons[j].getStyle().setFont(Font.createSystemFont(
Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_SMALL));
buttons[j].getSelectedStyle().setFont(Font.createSystemFont(
Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_SMALL));
buttons[j].getUnselectedStyle().setFont(Font.createSystemFont(
Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_SMALL));
buttons[j].getPressedStyle().setFont(Font.createSystemFont(
Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL));
updateButtonDayDate(buttons[j], month, j - i + 1);
startDate += DAY;
}
int d = 1;
for (; j < buttons.length; j++) {
buttons[j].setUIID("CalendarDay");
buttons[j].setEnabled(false);
buttons[j].setText("" + d++);
buttons[j].getStyle().setFont(Font.createSystemFont(
Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_SMALL));
buttons[j].getSelectedStyle().setFont(Font.createSystemFont(
Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_SMALL));
buttons[j].getUnselectedStyle().setFont(Font.createSystemFont(
Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_SMALL));
buttons[j].getPressedStyle().setFont(Font.createSystemFont(
Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL));
}
}
}
public int getDayOfMonth() {
java.util.Calendar cal = java.util.Calendar.getInstance(tmz);
cal.setTime(new Date(currentDay));
return cal.get(java.util.Calendar.DAY_OF_MONTH);
}
public int getMonth() {
java.util.Calendar cal = java.util.Calendar.getInstance(tmz);
cal.setTime(new Date(currentDay));
return cal.get(java.util.Calendar.MONTH);
}
public void incrementMonth() {
int month = getMonth();
month++;
int year = getYear();
if (month > java.util.Calendar.DECEMBER) {
month = java.util.Calendar.JANUARY;
year++;
}
setMonth(year, month);
}
private long getSelectedDay() {
return selectedDay;
}
public void setSelectedDay(long selectedDay){
java.util.Calendar cal = java.util.Calendar.getInstance(tmz);
cal.setTime(new Date(selectedDay));
cal.set(java.util.Calendar.HOUR, 1);
cal.set(java.util.Calendar.HOUR_OF_DAY, 1);
cal.set(java.util.Calendar.MINUTE, 0);
cal.set(java.util.Calendar.SECOND, 0);
cal.set(java.util.Calendar.MILLISECOND, 0);
this.selectedDay = cal.getTime().getTime();
}
private void setMonth(int year, int month) {
java.util.Calendar cal = java.util.Calendar.getInstance(tmz);
cal.setTimeZone(TimeZone.getDefault());
cal.set(java.util.Calendar.MONTH, month);
cal.set(java.util.Calendar.DAY_OF_MONTH, 1);
cal.set(java.util.Calendar.YEAR, year);
Date date = cal.getTime();
long d = date.getTime();
// if this is past the last day of the month (e.g. going from January 31st
// to Febuary) we need to decrement the day until the month is correct
while (cal.get(java.util.Calendar.MONTH) != month) {
d -= DAY;
cal.setTime(new Date(d));
}
setCurrentDay(d);
}
public void decrementMonth() {
int month = getMonth();
month--;
int year = getYear();
if (month < java.util.Calendar.JANUARY) {
month = java.util.Calendar.DECEMBER;
year--;
}
setMonth(year, month);
}
public int getYear() {
java.util.Calendar cal = java.util.Calendar.getInstance(tmz);
cal.setTime(new Date(currentDay));
return cal.get(java.util.Calendar.YEAR);
}
public void addActionListener(ActionListener l) {
dispatcher.addListener(l);
}
public void removeActionListener(ActionListener l) {
dispatcher.removeListener(l);
}
/**
* Allows tracking selection changes in the calendar in real time
*
* #param l listener to add
*/
public void addDataChangeListener(DataChangedListener l) {
dataChangeListeners.addListener(l);
}
/**
* Allows tracking selection changes in the calendar in real time
*
* #param l listener to remove
*/
public void removeDataChangeListener(DataChangedListener l) {
dataChangeListeners.removeListener(l);
}
protected void fireActionEvent() {
componentChanged();
super.fireActionEvent();
dispatcher.fireActionEvent(new ActionEvent(Calendar.this));
}
public void actionPerformed(ActionEvent evt) {
Object src = evt.getSource();
if(src instanceof ComboBox){
setMonth(Integer.parseInt((String)year.getSelectedItem()),
month.getSelectedIndex());
componentChanged();
return;
}
if(changesSelectedDateEnabled){
System.out.println("ttttttttttttttttttttttttttttt");
for (int iter = 0; iter < buttons.length; iter++) {
if (src == buttons[iter]) {
selected.setUIID("CalendarDay");
buttons[iter].setUIID("CalendarSelectedDay");
selectedDay = dates[iter];
selected.getSelectedStyle().setBgColor(bgColorArray[1]);
selected.getUnselectedStyle().setBgColor(bgColorArray[0]);
selected.getPressedStyle().setBgColor(bgColorArray[2]);
selected = buttons[iter];
selected.getSelectedStyle().setBgColor(bgColorArray[1]);
selected.getUnselectedStyle().setBgColor(bgColorArray[0]);
selected.getPressedStyle().setBgColor(bgColorArray[2]);
fireActionEvent();
if (!getComponentForm().isSingleFocusMode()) {
setHandlesInput(false);
}
return;
}
}
}
}
}
}

Resources