I have a map route shown in my map view, and I've set up the delegate and delegate methods as per the instructions. But when I tap on the route, nothing happens. However, the delegate method fires fine when I tap on a map circle.
Are routes not tappable?
Yes, NMAMapRoutes is tappable.
Follow below code, to solved your issue
-(void)mapView:(NMAMapView *)mapView didSelectObjects:(NSArray *)objects
{
for (int j=0; j<[objects count]; j++) {
if ([[objects objectAtIndex:j] isKindOfClass:[NMAMapRoute class]]) {
NSLog(#"NMAMapRoute:");
}
}
}
Related
Is it possible to pin a tab with Qt?
I want a tab to always stay in place (index 0) while still able to move other tabs.
So far I tried to listen to QTabBar::tabMoved and revert the move but that's too late. I don't want it even to attempt to move.
Worst case for me would be to be forced to change the mouse handling. Let me know please if there is an other way.
I have never found a nice way to do that. But, I used the fact that you can store raw data in the QTabBar to pin the tabs and undo a move if it was a pinned tab. It's not perfect and I still have some ugly behavior, but I didn't want to use mouse events, neither.
First, create a struct to store the current state of a tab:
struct PinnedTab
{
bool isPinned;
int currentIndex;
};
Q_DECLARE_METATYPE(PinnedTab); // For QVariant
Then, create a custom QTabBar to handle the move and use QTabWidget to replace the current tab bar (you have to do that before inserting the tabs):
class Bar: public QTabBar
{
public:
void pin(int const index)
{
PinnedTab info;
info.isPinned = true;
info.currentIndex = index; // TODO: move the tab to the left and do not use current index
setTabData(index, QVariant::fromValue(info));
}
Bar(QWidget* parent=nullptr): QTabBar(parent)
{}
virtual void tabLayoutChange() override
{
for (int i = 0; i != count(); ++i) // Check if a pinned tab has moved
{
if (tabData(i).isValid())
{
PinnedTab const info = tabData(i).value<PinnedTab>();
if (info.isPinned == true && i != info.currentIndex) {
rollbackLayout();
return;
}
}
}
for (int i = 0; i != count(); ++i)
{
if (tabData(i).isValid())
{
PinnedTab info = tabData(i).value<PinnedTab>();
info.currentIndex = i;
setTabData(i, QVariant::fromValue(info));
}
else
{
PinnedTab info;
info.isPinned = false;
info.currentIndex = i;
setTabData(i, QVariant::fromValue(info));
}
}
}
void rollbackLayout() {
for (int i = 0; i != count(); ++i)
{
if (tabData(i).isValid())
{
PinnedTab const info = tabData(i).value<PinnedTab>();
if (i != info.currentIndex) {
moveTab(i, info.currentIndex);
}
}
}
}
};
tabLayoutChange is called when the layout has changed. So, it will be called when you move a tab.
the rollbackLayout method is used to move each tab to the last position stored in the tab data.
Call pin to pin a tab with the given index.
I simplified my code for more clarity and you may have to redefine some behavior (for now, if you pin a tab, it will keep its current position and it will not handle the insert/remove tabs).
I am trying to find a way to detect (or receive notification) that a Node has been added to a Scene and is visible.
I am creating Node objects off the main JavaFx thread and add them to the Stage and Scene using Platform.runLater(). However I would like the Node object to receive notification that is has been added to the Scene and is visible, for example I wish to trigger an animation to start.
I can't seem to find any property or method to add a listener to capture such an event. Any suggestions?
The third-party JavaFX library ReactFX has a mechanism for this, and this exact use case is cited in the blog. In short, you can do
Val<Boolean> showing = Val.flatMap(node.sceneProperty(), Scene::windowProperty)
.flatMap(Window::showingProperty);
and then of course
showing.addListener((obs, wasShowing, isNowShowing) -> {
if (isNowShowing) {
// node is showing
} else {
// node is not showing
}
});
The standard library has a version of this, but it is very badly written. (It is not typesafe, has no compile-time checking that the properties exist, and also pipes a lot of unnecessary warnings to standard error if any of the properties in the "chain" are null, even though the API docs indicate this is a supported use case.) If you want to do this with the standard JavaFX library, you can do
BooleanBinding showing = Bindings.selectBoolean(node.sceneProperty(), "window", "showing");
and then use the binding the same way as above.
Finally, you could do all this by hand, but it gets a bit ugly to manage the listeners properly:
BooleanProperty showing = new SimpleBooleanProperty();
ChangeListener<Window> windowListener = (obs, oldWindow, newWindow) -> {
showing.unbind();
if (newWindow != null) {
showing.bind(newWindow.showingProperty());
} else {
showing.set(false);
}
};
ChangeListener sceneListener = (obs, oldScene, newScene) -> {
showing.unbind();
if (oldScene != null) {
oldScene.windowProperty().removeListener(windowListener);
}
if (newScene == null) {
showing.set(false);
} else {
newScene.windowProperty().addListener(windowListener);
if (newScene.getWindow() == null) {
showing.set(false);
} else {
showing.bind(newScene.getWindow().showingProperty());
}
}
};
node.sceneProperty().addListener(sceneListener);
if (node.getScene() == null) {
showing.set(false);
} else {
node.getScene().windowProperty().add(windowListener);
if (node.getScene().getWindow() == null) {
showing.set(false);
} else {
showing.bind(node.getScene().getWindow().showingProperty());
}
}
You can add a listener to the children property of container node into which you are adding the new node.
grid.getChildren().addListener((ListChangeListener<? super Node>) change -> {
System.out.println(change.getList().get(0).getTypeSelector());
});
change.getList().get(0) returns the first node that is added to grid object.
After James's comment, I have looked up and yes, it is possible to do it from node's perspective as well. You can listen to parentProeprty's changes on the node. Following snippet shows the way to do it.
Button b = new Button("Test");
b.parentProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("added to a container " + newValue);
});
answerPane.getChildren().add(b);
Which method does Page class invoke to instantiate its controls? I want to override it so as to be able to instantiate only certain controls.
there is a nice explanation here: ASP.NET Page Life Cycle Overview
an article like this is a must read if you do ASP.NET web form development.
just that you have some background before just palying around with Page_Load and Page_Init without a clue, in the article there is a table with the list of all events in the right order and full explanation for each of them.
if you open reflector it has a function called :
loadControlRecursivly ( or something like that) - thats where he laods it.
here it is :
internal virtual void LoadRecursive()
{
if (this._controlState < ControlState.Loaded)
{
if (this._adapter != null)
{
this._adapter.OnLoad(EventArgs.Empty);
}
else
{
this.OnLoad(EventArgs.Empty);
}
}
if ((this._occasionalFields != null) && (this._occasionalFields.Controls != null))
{
string errorMsg = this._occasionalFields.Controls.SetCollectionReadOnly("Parent_collections_readonly");
int count = this._occasionalFields.Controls.Count;
for (int i = 0; i < count; i++)
{
this._occasionalFields.Controls[i].LoadRecursive();
}
this._occasionalFields.Controls.SetCollectionReadOnly(errorMsg);
}
if (this._controlState < ControlState.Loaded)
{
this._controlState = ControlState.Loaded;
}
}
If your controls are not dynamically instantiated then you can't in the normal page lifecycle.
I am trying to write an application, but it is constantly crashing when using the uiimagepickercontroller. I thought that it might be because I was not disposing of the picker after each use, but it will often freeze up on first run as well. Usually I'll take a picture and it just freezes, never asking to "use" the picture.
Do you have any suggestions? Here is my code. Has anyone gotten this to work?
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
myPicker = new UIImagePickerController();
myPicker.Delegate = new myPickerDelegate(this);
myAlbumButton.Clicked += delegate {
if(UIImagePickerController.IsSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary)){
myPicker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
myPicker.AllowsEditing = true;
this.PresentModalViewController (myPicker, true);
}else{
Console.WriteLine("cannot get album");
}
};
myCameraButton.Clicked += delegate {
if(UIImagePickerController.IsSourceTypeAvailable(UIImagePickerControllerSourceType.Camera)){
myPicker.SourceType = UIImagePickerControllerSourceType.Camera;
//myPicker.AllowsEditing = true;
this.PresentModalViewController (myPicker, true);
}else{
Console.WriteLine("cannot get camera");
}
};
}
private class myPickerDelegate : UIImagePickerControllerDelegate
{
private TestView _vc;
public myPickerDelegate ( TestView controller):base()
{
_vc = controller;
}
public override void FinishedPickingImage (UIImagePickerController myPicker, UIImage image, NSDictionary editingInfo)
{
// TODO: Implement - see: http://go-mono.com/docs/index.aspx?link=T%3aMonoTouch.Foundation.ModelAttribute
_vc.myImageView.Image = image;
myPicker.DismissModalViewControllerAnimated(true);
}
}
Try to call your event handlers code from the main thread by using BeginInvokeOnMainThread().
So my issue was very similar.
Instead of having a delegate class, I had the delegates inline for the picker.
For some reason the app froze every time after talking the image, not stopping in any breakpoint after that.
The solution that worked for me was to use this book:
http://www.scribd.com/doc/33770921/Professional-iPhone-Programming-with-MonoTouch-and-NET-C
This question doesn't relate only to MouseEvent.CLICK event type but to all event types that already exist in AS3. I read a lot about custom events but until now I couldn't figure it out how to do what I want to do. I'm going to try to explain, I hope you understand:
Here is a illustration of my situation:
for(var i:Number; i < 10; i++){
var someVar = i;
myClips[i].addEventListener(MouseEvent.CLICK, doSomething);
}
function doSomething(e:MouseEvent){ /* */ }
But I want to be able to pass someVar as a parameter to doSomething. So I tried this:
for(var i:Number; i < 10; i++){
var someVar = i;
myClips[i].addEventListener(MouseEvent.CLICK, function(){
doSomething(someVar);
});
}
function doSomething(index){ trace(index); }
This kind of works but not as I expect. Due to the function closures, when the MouseEvent.CLICK events are actually fired the for loop is already over and someVar is holding the last value, the number 9 in the example. So every click in each movie clip will call doSomething passing 9 as the parameter. And it's not what I want.
I thought that creating a custom event should work, but then I couldn't find a way to fire a custom event when the MouseEvent.CLICK event is fired and pass the parameter to it. Now I don't know if it is the right answer.
What should I do and how?
You really need to extend the event class to create your own event with extra parameters. Placing functions inside the addEventListener (anonymous functions) is a recipe for memory leaks, which is not good.
Take a look at the following.
import flash.events.Event;
//custom event class to enable the passing of strings along with the actual event
public class TestEvent extends Event
{
public static const TYPE1 :String = "type1";
public static const TYPE2 :String = "type2";
public static const TYPE3 :String = "type3";
public var parameterText:String;
public function TestEvent (type:String, searchText:String)
{
this.parameterText = searchText;
super(type);
}
}
when you create a new event such as
dispatchEvent(new TestEvent(TestEvent.TYPE1, 'thisIsTheParameterText'))" ;
you can then listen for that event like this
someComponent.addEventListener(TestEvent.TYPE1, listenerFunction, true , 0, true);
and inside the function 'listenerFunction' event.parameterText will contain your parameter.
so inside your myClips component you would fire off the custom event and listen for that event and not the Click event.
Without knowing more about your application, it seems more like you should use the target to pass parameters, or extend MouseEvent. The former would be more in line with common practice, though. So for example, if you exposed an integer public property on your "clip" object (whatever it is):
public class MyClip
{
public var myPublicProperty:int;
public function MyClip() { //... }
}
for (var i:int = 0; i < 10; i++)
{
myClips[i].myPublicProperty = i;
myClips[i].addEventListener(MouseEvent.CLICK, doSomething);
}
... and then, in your event listener, you could retrieve that property using either the target or currentTarget property of the event (probably currentTarget, in your case):
function doSomething(event:MouseEvent):void
{
trace(event.currentTarget.myPublicProperty.toString());
}
That ought to do it! Good luck.
private function myCallbackFunction(e:Event, parameter:String):void
{
//voila, here's your parameter
}
private function addArguments(method:Function, additionalArguments:Array):Function
{
return function(event:Event):void {method.apply(null, [event].concat(additionalArguments));}
}
var parameter:String = "A sentence I want to pass along";
movieClip.addEventListener(Event.COMPLETE, addArguments(myCallbackFunction, [parameter] ) );
Take advantage of the dynamic function construction in AS3.
You can accomplish this by getting your handler out of a function that gives the variable closure, like this:
for (var i=0; i<5; i++) {
myClips[i].addEventListener( MouseEvent.CLICK, getHandler(i) );
}
function getHandler(i) {
return function( e:MouseEvent ) {
test(i);
}
}
function test( j ) {
trace("foo "+j);
}
Also, as for why this creates a new closure, you might want to check the explanation in the accepted answer to this similar question.
Thanks so much for this usefull tips, this technique is better to understand than classes explanation.
for me I just started new code algorithm using this technique to solve link relation between timers array and viewports array, and update status by change text inside them frequently, by passing ID's with timers events.
like this:
var view:Object=[];
for(var i:uint=0;i<Camera.names.length;i++){
view[i]=getChildByName("Cam"+i);
//_________ Add Text _________
var tf:TextField = new TextField();
tf.autoSize = TextFieldAutoSize.LEFT;
tf.textColor=0xffffff;
view[i].tf=view[i].addChild(tf);
//_________ Add Timer _________
var t:Timer = new Timer(1000);
view[i].timer=t;
view[i].timer.start();
view[i].timer.addEventListener(TimerEvent.TIMER, addArg(i));
}
function addArg(adi:uint):Function {
return function(event:TimerEvent):void {
updatecamstatus(adi);
}
}
function updatecamstatus(vH:uint):void {
with (view[vH]){
tf.text="Cam" + vH + "\n";
tf.appendText("activityLevel: " + videosource.activityLevel + "\n");
tf.appendText("motionLevel: " + videosource.motionLevel + "\n");
}
}
I see your main goal isn't actually to create a custom MouseEvent.CLICK, but to pass a parameter to the function. You don't need to complicatedly create or extend anything. There's a simple and closure-trouble-free way to do it.
Just make your function like this:
function doSomething(index:Number):Function {
return function(e:MouseEvent):void {
// Use "e" and "index" here. They'll be unique for each addEventListener()
trace(index);
}
}
This technique can relate to any AS3 event type you can use addEventListener on.
And now you can add it like this:
var functionsDoSomething:Object;
for (var i:Number = 0; i < 10; i++) {
var someVar:Number = i;
functionsDoSomething[i] = doSomething(someVar);
myClips[i].addEventListener(MouseEvent.CLICK, functionsDoSomething[i]);
}
The doSomething(someVar) can be used directly on addEventListener(), but it's better to keep it in a variable because you'll be able to remove it later the same fashion you added it:
for (i = 0; i < 10; i++) {
myClips[i].removeEventListener(MouseEvent.CLICK, functionsDoSomething[i]);
}
The commonly used e.currentTarget.someCustomProperty works for dynamic objects (i.e. MovieClip), but will let you down at anything else (i.e. Sprite), forcing you to build a whole custom extended object/event for every type.
This solution deals with every "listenable" object and event. And this answer has more details and examples on it.