Haxe/OpenFL - Check if sprite is clicked - haxe

I am trying to create a sprite and if the sprite is clicked it prints out a message. I created a sprite but when I added a listener it gives me the errors:
src/Main.hx:26: characters 39-44 : Void -> Void should be Dynamic -> Void
src/Main.hx:26: characters 39-44 : For function argument 'listener'
I removed the listener and then it worked just fine what is the problem?
My main class:
package;
import openfl.display.Sprite;
import openfl.events.MouseEvent;
import openfl.display.SimpleButton;
class Main extends Sprite {
private var button:SimpleButton;
private var s:Spritetest;
public function new () {
super ();
this.mouseChildren = false;
this.buttonMode = true;
init();
}
public function init() {
fillBackGround(0xff00ff, 640, 960);
s = new Spritetest();
s.addEventListener(MouseEvent.CLICK, click);
addChild(s);
}
public function fillBackGround(color:Int, w:Int, h:Int) {
this.graphics.beginFill(color);
this.graphics.drawRect(0, 0, w, h);
this.graphics.endFill();
}
public function click() {
trace("test");
}
}
my Sprite class:
package;
import openfl.display.Sprite;
class Spritetest extends Sprite {
public function new() {
super();
this.graphics.beginFill(0xffffff);
this.graphics.drawRect(20 , 20, 40, 40);
this.graphics.endFill();
}
}

The listener function signature must be Dynamic -> Void, because an Event (or MouseEvent) object will be passed as argument when you click.
Thus it should be like that:
public function click(e:Dynamic) {
trace('test');
}
The OpenFL API mimics Flash's, and thus the addEventListener function works pretty much like documented here :
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/EventDispatcher.html#addEventListener()

Related

How is IClock resolved with SystemClock in this example?

I am trying to learn IOC principle from this screencast
Inversion of Control from First Principles - Top Gear Style
I tried do as per screencast but i get an error while AutomaticFactory try create an object of AutoCue. AutoCue class has contructor which takes IClock and not SystemClock. But my question is , in screencast IClock is resolved with SystemClock while inside AutomaticFactory .But in my code , IClock does not get resolved . Am i missing something ?
class Program
{
static void Main(string[] args)
{
//var clarkson = new Clarkson(new AutoCue(new SystemClock()), new Megaphone());
//var clarkson = ClarksonFactory.SpawnOne();
var clarkson = (Clarkson)AutomaticFactory.GetOne(typeof(Clarkson));
clarkson.SaySomething();
Console.Read();
}
}
public class AutomaticFactory
{
public static object GetOne(Type type)
{
var constructor = type.GetConstructors().Single();
var parameters = constructor.GetParameters();
if (!parameters.Any()) return Activator.CreateInstance(type);
var args = new List<object>();
foreach(var parameter in parameters)
{
var arg = GetOne(parameter.ParameterType);
args.Add(arg);
}
var result = Activator.CreateInstance(type, args.ToArray());
return result;
}
}
public class Clarkson
{
private readonly AutoCue _autocue;
private readonly Megaphone _megaphone;
public Clarkson(AutoCue autocue,Megaphone megaphone)
{
_autocue = autocue;
_megaphone =megaphone;
}
public void SaySomething()
{
var message = _autocue.GetCue();
_megaphone.Shout(message);
}
}
public class Megaphone
{
public void Shout(string message)
{
Console.WriteLine(message);
}
}
public interface IClock
{
DateTime Now { get; }
}
public class SystemClock : IClock
{
public DateTime Now { get { return DateTime.Now; } }
}
public class AutoCue
{
private readonly IClock _clock;
public AutoCue(IClock clock)
{
_clock = clock;
}
public string GetCue()
{
DateTime now = _clock.Now;
if (now.DayOfWeek == DayOfWeek.Sunday)
{
return "Its a sunday!";
}
else
{
return "I have to work!";
}
}
}
What you basically implemented is a small IoC container that is able to auto-wire object graphs. But your implementation is only able to create object graphs of concrete objects. This makes your code violate the Dependency Inversion Principle.
What's missing from the implementation is some sort of Register method that tells your AutomaticFactory that when confronted with an abstraction, it should resolve the registered implementation. That could look as follows:
private static readonly Dictionary<Type, Type> registrations =
new Dictionary<Type, Type>();
public static void Register<TService, TImplementation>()
where TImplementation : class, TService
where TService : class
{
registrations.Add(typeof(TService), typeof(TImplementation));
}
No you will have to do an adjustment to the GetOne method as well. You can add the following code at the start of the GetOne method:
if (registrations.ContainsKey(type))
{
type = registrations[type];
}
That will ensure that if the supplied type is registered in the AutomaticFactory as TService, the mapped TImplementation will be used and the factory will continue using this implementation as the type to build up.
This does mean however that you now have to explicitly register the mapping between IClock and SystemClock (which is a quite natural thing to do if you're working with an IoC container). You must make this mapping before the first instance is resolved from the AutomaticFactory. So you should add the following line to to the beginning of the Main method:
AutomaticFactory.Register<IClock, SystemClock>();

Drawing in MvxTableViewCell

I would like to draw a rectangle in every tablevievcell of my MvxTableViewController.
I have a custom cellLabel extending UIView
namespace Next.Client.Application.iOS.Views.UI
{
[Register("CellLabel")]
public class CellLabel : UIView
{
public CellLabel()
{
Initialize();
}
public CellLabel(RectangleF bounds)
: base(bounds)
{
Initialize();
}
void Initialize()
{
BackgroundColor = UIColor.Red;
}
public override void Draw(RectangleF rect)
{
base.Draw(rect);
//get graphics context
using (CGContext gc = UIGraphics.GetCurrentContext())
{
//set up drawing attributes
gc.SetLineWidth(1);
UIColor.Blue.SetFill();
UIColor.Red.SetStroke();
//create geometry
var path = new CGPath();
path.AddLines(new PointF[]{
new PointF (0, 45),
new PointF (80, 45),
new PointF (90, 50),
new PointF (0, 50)
});
path.CloseSubpath();
//add geometry to graphics context and draw it
gc.AddPath(path);
gc.DrawPath(CGPathDrawingMode.FillStroke);
}
}
}
}
and a custom cell where to draw in
namespace Next.Client.Application.iOS
{
public partial class ObservationCell : MvxTableViewCell
{
public static readonly UINib Nib = UINib.FromName ("ObservationCell", NSBundle.MainBundle);
public static readonly NSString Key = new NSString ("ObservationCell");
private CellLabel _labelView;
public ObservationCell (IntPtr handle) : base (handle)
{
_labelView = new CellLabel();
this.AddSubview(_labelView);
this.DelayBind(() => {
var set = this.CreateBindingSet<ObservationCell, Observation>();
set.Bind(MainLbl).To(observation => observation.BrutText);
set.Bind(SubLeftLbl).To(observation => observation.Praticien.Personne.DisplayFullName);
set.Bind(SubRightLbl).To(observation => observation.DateTimeHumanShort);
set.Apply();
});
}
public static ObservationCell Create ()
{
return (ObservationCell)Nib.Instantiate (null, null) [0];
}
}
}
but nothing show up :/
any ideas ?
Your CellLabel doesn't currently seem to have any Frame - so it's probably being drawn inside (0,0,0,0)
Try:
_labelView = new CellLabel(new RectangleF(0,0,320,100));
this.AddSubview(_labelView);
If you add a CellLabel(IntPtr) constructor, then you can also use the CellLabel as a type in the XIB editor - it won't fully draw within the editor, but the editor will allow you to specify it as the type and it will get correctly loaded at runtime.
One final note... I don't think I'd call it a Label - could be confusing to people who read the code later.

How to reflect changes in viewmodel to tableviewcell view with binding in MVVMcross

Am a little stuck with getting changes reflected from the ViewModel to the View when used in a MvxBindableTableViewCell. I am using the vNext branch of MvvmCross on iOS.
Everything is set up properly and the initial values are visible when loading/showing the list for the first time. The list is a ObservableCollection<T> and the ViewModels inherit from MvxViewModel (thus implements INotifyPropertyChanged).
The main ViewModel looks like this:
public abstract class BaseViewModel : MvxViewModel, IMvxServiceConsumer
{
//... just regular implementation
}
public class UploadListViewModel: BaseViewModel
{
private readonly IUploadItemTasks uploadItemTasks;
private readonly IPhotoPickerService photoPickerService;
public IObservableCollection<UploadItemViewModel> Uploads { get { return this.LoadUploadItems(); } }
public UploadListViewModel()
{
this.uploadItemTasks = this.GetService<IUploadItemTasks>();
this.photoPickerService = this.GetService<IPhotoPickerService>();
}
private IObservableCollection<UploadItemViewModel> LoadUploadItems()
{
using (var unitOfWork = UnitOfWork.Start ())
{
return new SimpleObservableCollection<UploadItemViewModel>(uploadItemTasks.GetAll());
}
}
public void StartUpload ()
{
if (this.Uploads == null || this.Uploads.Count == 0) {
ReportError("Error", "No images to upload");
return;
}
this.Uploads.ForEach (uploadItem => PostCallback (uploadItem));
}
private void PostCallback (UploadItemViewModel uploadAsset)
{
IProgressReporter progressReporter = uploadAsset;
this.photoPickerService.GetAssetFullImage(uploadAsset.ImageUrl,
(image) => {
UIImage fullImage = image;
NSData jpeg = fullImage.AsJPEG();
byte[] jpegBytes = new byte[jpeg.Length];
System.Runtime.InteropServices.Marshal.Copy(jpeg.Bytes, jpegBytes, 0, Convert.ToInt32(jpeg.Length));
MemoryStream stream = new MemoryStream(jpegBytes);
Uri destinationUrl = new Uri(uploadAsset.DestinationUrl + "&name=" + uploadAsset.Name + "&contentType=image%2FJPEG");
//TO DO: Move this to plugin
var uploader = new Uploader().UploadPicture (destinationUrl, stream, UploadComplete, progressReporter);
uploader.Host = uploadAsset.Host;
ThreadPool.QueueUserWorkItem (delegate {
uploader.Upload ();
jpeg = null;
});
});
}
private void UploadComplete (string name)
{
if (name == null){
ReportError("Error","There was an error uploading the media.");
} else
{
//ReportError("Succes", name);
}
}
The item ViewModel looks like:
public interface IProgressReporter
{
float Progress { get; set;}
}
public abstract class BaseAssetViewModel: BaseViewModel, IBaseAssetViewModel
{
//... just regular properties
}
public class UploadItemViewModel: BaseAssetViewModel, IProgressReporter
{
public UploadItemViewModel(): base()
{
}
private float progress;
public float Progress {
get {
return this.progress;
}
set {
this.progress = value;
this.RaisePropertyChanged(() => Progress);
}
}
}
The View for the items inherits from MvxBindableTableViewCell and has the property:
private float progress;
public float ProgressMarker {
get {
return progress;
}
set {
progress = value;
// change progressbar or textfield here
}
}
The tableviewcell is bounded to the UploadItemViewModel via the BindingText:
public const string BindingText = #"ProgressMarker Progress, Converter=Float;";
The Uploader class mentioned in the snippet of UploadListViewModel implements a private method which tries to set the progress on the IProgressReporter.
float progressValue;
void SetProgress (float newvalue)
{
progressValue = newvalue;
this.dispatcher.InvokeOnMainThread (delegate {
if (ProgressReporter != null)
ProgressReporter.Progress = progressValue;
});
}
During the first viewing of the list I can see that the properties in both the ViewModel and View are being hit but when I update the ViewModel via the interface IProgressReporter with a new value in Progress the View in the tableviewcell is not updated nor the property is being called.
What am I doing wrong or what am I missing here?
UPDATE: Check the answer to this question.
I found why the binding didn't work. I was replacing the ObservableCollection over and over again.. I changed that piece of code as stated below and now it reflects the changes made to the UploadItemViewModel in the View of the cell.
private IObservableCollection<UploadItemViewModel> uploads;
private IObservableCollection<UploadItemViewModel> LoadUploadItems()
{
if (uploads == null)
{
using (var unitOfWork = UnitOfWork.Start ())
{
uploads = new SimpleObservableCollection<UploadItemViewModel>(uploadItemTasks.FindAll());
}
}
return uploads;
}

Displaying a message box or notification bar in java apps?

In my J2ME app, I have some forms, and some threads running on background. If in any of these threads I decide to display a message box or notification bar on top of the app, I have the problem of not knowing in which form I am, therefore I don't know which form to show after the messagebox or notification bar is hidden.
Does anyone have any suggestions?
You can get current form that is already displaying with "Display.getCurrent()".For example this canvas is a SplashScreen that get current form before displays in the screen:
import javax.microedition.lcdui.Canvas;
/* */ import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Form;
/* */ import javax.microedition.lcdui.Graphics;
/* */ import javax.microedition.lcdui.Image;
public class StaticSplashScreen extends Canvas
implements Runnable {
private HelloMIDlet mainMidlet;
private boolean isSplashOver;
private long currentTime;
private long previousTime;
private Form currentForm;
public StaticSplashScreen(HelloMIDlet mid) {
this.mainMidlet = mid;
currentForm = (Form) this.mainMidlet.getDisplay().getCurrent();
this.previousTime = System.currentTimeMillis();
new Thread(this).start();
}
protected void paint(Graphics g) {
g.setColor(255, 255, 255);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(0, 0, 0);
g.drawString("In the name of God", 40, 70, 0);
}
public void run() {
while (!this.isSplashOver) {
this.currentTime = System.currentTimeMillis();
if (this.currentTime - this.previousTime >= 10000L) {
this.isSplashOver = true;
}
}
this.mainMidlet.getDisplay().setCurrent(currentForm);
}
}
In this midlet you can see two forms with some commands.When you press "help" in each form,method() calls and SplashScreen diplays and after 10 seconds you can see the form that launched it again:
public class HelloMIDlet extends MIDlet implements CommandListener {
...
public void commandAction (Command command, Displayable displayable) {
...
if (command == helpCommand) {
method ();
}
...
}
public Form getForm () {
if (form == null) {
form = new Form ("Welcome");
form.addCommand (getHelpCommand());
form.setCommandListener (this);
}
return form;
}
public void method () {
if (true) {
StaticSplashScreen sss = new StaticSplashScreen(this);
this.getDisplay().setCurrent(sss);
} else {
}
}
public Form getForm1 () {
if (form1 == null) {
form1 = new Form ("form1");
form1.addCommand (getHelpCommand ());
form1.setCommandListener (this);
}
return form1;
}
}
A ticker is an object that provides scrolling text across the top of the display. A Ticker is associated with the display, not with the screen. You place a Ticker on a screen using the Screen.setTicker(Ticker t) method, as shown in the code below.
You can associate the same Ticker object with multiple screens, however. The implementation renders the Ticker on some constant portion of the display, in this case at the top of the display. Ticker is not an Item. Its derivation directly from java.lang.Object gives you a clue as to why a Ticker can be tied to the display and not to a screen. It doesn't need to be derived from Item, because it really is not something that is placed in a Form.
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Ticker;
import javax.microedition.lcdui.Form;
/**
This class demonstrates use of the Ticker MIDP UI
component class.
#see javax.microedition.lcdui.Gauge
*/
public class TickerDemo extends Form
implements CommandListener
{
private String str =
"This text keeps scrolling until the demo stops...";
private Ticker ticker = new Ticker(str);
private Command back = new Command("Back", Command.BACK, 1);
private static Displayable instance;
/**
Constructor.
*/
public TickerDemo()
{
super("Ticker demo");
instance = this;
addCommand(back);
setTicker(ticker);
setCommandListener(this);
}
...
}
Hope this will help you. Thanks

Trying to create a embedded web page on black berry and cannot set starting url

I’m trying to make an embedded web page on my blackberry app, and I'm having trouble setting the starting URL.
I can only set the URL when I do it from a callback from a TextField. When I try to do it after I push the new screen on, the app no longer works (it does nothing when you try to run it.
The code that works is the following:
protected boolean keyChar(char key, int status, int time)
{
if ( key == Characters.ENTER )
{
Application.getApplication().invokeLater( new Runnable()
{
public void run() {
//progressBar.reset("", 0, 100, 0);
browserField.requestContent(locationBar.getText().trim());
}
});
return true;
}
return super.keyChar(key, status, time);
}
When I try to set it automatically after everything is created, nothing happens when I run the app.
Code snippet
public MyApp()
{
pushScreen(new BrowserFieldScreen());
// if I have this here, the app will not open
Application.getApplication().invokeLater( new Runnable()
{
public void run() {
gBrowserField.requestContent("http://google.com");
}
});
}
The complete program:
package mypackage;
import java.util.Enumeration;
import java.util.Hashtable;
import net.rim.device.api.browser.field.ContentReadEvent;
import net.rim.device.api.browser.field2.BrowserField;
import net.rim.device.api.browser.field2.BrowserFieldListener;
import net.rim.device.api.system.Application;
import net.rim.device.api.system.Characters;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.GaugeField;
import net.rim.device.api.ui.component.TextField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;
import net.rim.device.api.ui.decor.BackgroundFactory;
import org.w3c.dom.Document;
/**
* BrowserField2ProgressTracker
* - A BrowserField2 Mini-browser application that keeps track of page-loading progress
* and displays progress information to the user.
*/
public class MyApp extends UiApplication {
static BrowserField gBrowserField;
public static void main(String[] args){
MyApp theApp = new MyApp();
theApp.enterEventDispatcher();
}
public MyApp() {
pushScreen(new BrowserFieldScreen());
/*
if I have this hear, the ap will not open
Application.getApplication().invokeLater( new Runnable() {
public void run() {
gBrowserField.requestContent("http://google.com");
}
});
}
*/
}
/**
* BrowserFieldScreen
* - A screen that contains a location bar, a progress bar, and a browser field
*/
class BrowserFieldScreen extends MainScreen {
// The location bar where URL will be typed in
private TextField locationBar;
// The BrowserField
private BrowserField browserField;
public BrowserFieldScreen() {
// progressTracker = new BrowserFieldLoadProgressTracker(10f);
createGUI();
}
private void createGUI() {
VerticalFieldManager mainManager = new VerticalFieldManager(Field.USE_ALL_WIDTH | Field.USE_ALL_HEIGHT | Manager.VERTICAL_SCROLLBAR | Manager.HORIZONTAL_SCROLLBAR );
locationBar = new TextField() {
protected boolean keyChar(char key, int status, int time) {
if ( key == Characters.ENTER ) {
Application.getApplication().invokeLater( new Runnable() {
public void run() {
//progressBar.reset("", 0, 100, 0);
browserField.requestContent(locationBar.getText().trim());
}
});
return true;
}
return super.keyChar(key, status, time);
}
};
locationBar.setBackground(BackgroundFactory.createSolidBackground(Color.BEIGE));
locationBar.setText("http://google.com");
browserField = new BrowserField();
MyApp.gBrowserField=browserField;
mainManager.add(locationBar);
mainManager.add(browserField);
add(mainManager);
}
}
I don't think you can call invokeLater() until your app, theApp has enter the main event thread. Which is done by calling theApp.enterEventDispatcher()
instead try changing your BrowserFieldScreen constructor to:
public BrowserFieldScreen() {
// progressTracker = new BrowserFieldLoadProgressTracker(10f);
createGUI();
browserField.requestContent("http://google.com");
}

Resources