No Javafx-2 event when a scene is shown - event-handling

I can't seem to find a way to register an event listener of a scene or node class that would get dispatched when that scene is shown.
I want my Scene classes to be self-contained so I can use a builder class to construct them and have any of their animations fire when they are shown. For example, I'd like to be able to do something like the following in my Application class...
public void start(Stage primaryStage) {
primaryStage.setScene(AnimatedLoginSceneBuilder.create()
.width(1024)
.height(768)
.frameRate(25)
.build();
)
primaryStage.show();
}
My AnimatedLoginSceneBuilder class creates a scene and an animation which it binds to some nodes within the scene. I can only return the scene with the build method however (not the animation class). For example it looks something like this...
public class AnimatedLoginSceneBuilder implements Builder<Scene> {
// private members such as width, height and framerate
// methods to set width, height and framerate (e.g. width(double width))
public Scene build() {
DoubleProperty x = new SimpleDoubleProperty();
Text node = TextNodeBuilder...
node.xProperty().bind(x);
final Timeline animation = TimelineBuilder... // animate x
return SceneBuilder.create()
. // create my scene using builders (bar the node above)
.build();
}
}
But I have no way to play the animation and so I'd like to have some hook like...
public class AnimatedLoginSceneBuilder ... {
...
public Scene build() {
...
final Timeline animation = TimelineBuilder... // animate x
return SceneBuilder.create()
. // create scene declaratively
.onShow(new EventHandler<SomeEvent>() {
#Overide public void handleSomeEvent() {
animation.play();
}
.build()
}
Then when the scene is shown, it will play automatically. Too much to ask?
One alternative would be to have the builder class return both the scene and the animation wrapped in an object and do something like...
public void start(Stage primaryStage) {
WrapperObj loginSceneWrapper = AnimatedLoginSceneBuilder.create()
.width(1024)
.height(768)
.frameRate(25)
.build();
primaryStage.setScene(wrapperObj.getScene());
primaryStage.show();
wrapperObj.getAnimation().play();
But this isn't what I want because I want to be able to change to a new scene from within an existing one and make no assumptions. For example I'd like to be able to have an event-handler in the scene be able to get the stage to transition to a new scene and as such, I'd just like to be able to call primaryStage.setScene(new scene I want to go to).
Any ideas?
The closest I've seen is How to listen for WindowEvent.WINDOW_SHOWN in the nodes of the scene graph? but that won't work for this case.

"Showing" event is fired when the javafx.​stage.Window is shown. You can set the listeners for the appropriate events with window.setOnShowing() and window.setOnShown(). Scene is a container for the scene graph and has no logic about showing/hiding.
I suggest to store animated root nodes (extended from Parent or its sub classes) of scenes instead of scenes. And add listener to the root changed event like
stage.getScene().rootProperty().addListener(new ChangeListener<MyAnimatedParent>() {
#Override
public void changed(ObservableValue<? extends MyAnimatedParent> observable, MyAnimatedParent oldValue, MyAnimatedParent newValue) {
newValue.animate();
}
});

Related

AudioSource attached button doesnt work in another scene

public AudioSource menumusic;
public Button SoundButton;
public Sprite Soundoff;
public Sprite SoundOn;
bool isClicked = true;
private void Awake()
{
DontDestroyOnLoad(this.gameObject);
SoundButton.image.sprite = SoundOn;
}
// Start is called before the first frame update
void Start()
{
menumusic = GetComponent<AudioSource>();
}
// Update is called once per frame
void Update()
{
SoundButton.onClick.AddListener(BtnOnClick);
}
void BtnOnClick()
{
changeState();
}
private void changeState()
{
isClicked = !isClicked;
if(isClicked)
{
SoundButton.image.sprite = SoundOn;
menumusic.Play();
}
else
{
SoundButton.image.sprite = Soundoff;
menumusic.Stop();
}
}
I have script like this And I am using on menu scene but when I switch to game scene with other button , this script works in there to except that he can not find soundbutton , how can I link to sound button from another scene should I create same to game scene too ? , sorry I am new on unity.
It looks like you're setting the reference to your "SoundButton" object in the inspector. When you change scenes, you'll need to update the reference on this script to refer to the new button.
There are many ways to do this. You could just tag the soundButtons with "soundButton".
Then, wherever you're loading a new scene, update the reference by searching for the tag.
SoundButton = GameObject.FindObjectWithTag("soundButton").GetComponent<Button>();
It would also be possible to have a SoundButton script which you place on every sound button. This could then reference a static SoundManager object, and tell it to toggle the sound on or off when clicked. This is probably a cleaner way to do it.
Also note: You're adding a listener to the soundButton in Update() (i.e. every frame). This is unnecessary. Add the listener one time in Start(), or when you change Scenes, and it will trigger the event whenever the button is clicked. There is no need to use Update() for this process.
If it still isn't working, you can also check the variable before using it, and get the reference again if it's null:
if(soundButton == null)
{
SoundButton = GameObject.FindObjectWithTag("soundButton").GetComponent<Button>();
}

Menu item not cast node javafx scene

I am making a JavaFX app. I have create a Menuitem About. Upon clicking on the About Menuitem it will display a new window with some info about my app. The window is a Anchor Pane with custom close button. I have set the stage undercoated at run time. I want to close this window without closing my main application. I don't want to set its visibility turn off on method call. I see some solution in net like Window existingWindow = ((Node) event.getSource()).getScene().getWindow(); but i can't use this as am getting error similar to this Menu item not cast node javafx scene. How can I achieve this goal?
Actually this is not my own answer, but I managed to understand #James_D. I usually create to manage open windows, otherwise I have to write a lot of code And this is solution code.
In your controller class:
#FXML
void openAnotherWindow(ActionEvent actionEvent) {
try {
OpenWindow.openWindowMenuItem(someLabel, "views/some.fxml", "Title", 600, 400,
false, "resources/pictures/some_icon.png");
} catch (IOException e) {
e.printStackTrace();
}
}
And OpenWindow class
public class OpenWindow {
public static void openWindowMenuItem(Node label, String recource, String title,
int width, int height, boolean resizeable, String icon) throws IOException {
Parent root = FXMLLoader.load(Objects.requireNonNull(OpenWindow.class.getClassLoader().getResource(recource)));
Stage stage = new Stage();
Scene scene = new Scene(root, width, height);
if (icon != null) {
stage.getIcons().add(new Image(icon));
}
stage.setTitle(title);
stage.setResizable(resizeable);
stage.setScene(scene);
stage.show();
// close current window
label.getScene().getWindow().hide(); // this is key point
}
}
You can do it event without extra class. Hope it will help and again thanks to #James_D

How to display a name and score list for players using happyfuntimes and unity3d

This is related to happyfuntimes plugin if you have used it .
I am trying to make a game on it and stuck at a point of displaying score along with name to display on large screen while user is playing on his mobile.(i have already tried to display name and score on mobile screens have seen in sample do not need that ). Please suggest how can this be done if you have used happyfuntimes plugin.
I could see the HFTgamepad input having public GameObject player name which I am trying to access ,do I have to make array ?
public string playerName;
I am trying to put these name on array.
Displaying anything in unity is really normal unity issue and not special to happyfuntimes. Games display highscore lists, item lists, inventory lists, etc... A list of players is no different
Use the GUI system display text.
According to the docs if you want to generate UI dynamically you should make a prefab
So basically you'd make a UI hierarchy in the scene. When a player is added to the game Instantiate your name-score prefab, search for the UI hierarchy gameObject (do that at init time), then set the parent of the preafab you just instantiated so it's in the UI hierarchy.
Look up the UI.Text components that represent name and score and set their text properties.
There's various auto layout components to help layout your scores
When a player disconnects Destroy the prefab you instantiated above.
OR ...
Conversely you can use the old immediate mode GUI. You'd make a GameObject, give it a component that has a OnGUI function. Somewhere keep a list of players. Add players to the list as they connect and remove them from the list as they disconnect. In your OnGUI function loop over the list of players and call the GUI.Label function or similar to draw each name and score
Here's a hacked up example.
Assuming you have a PlayerScript script component that's on each player that has a public accessor PlayerName for getting the player's name then you can make a GameObject and put a script like this on it.
using UnityEngine;
using System.Collections.Generic;
public class ExamplePlayerListGUI : MonoBehaviour
{
static ExamplePlayerListGUI s_instance;
List<PlayerScript> m_players = new List<PlayerScript>();
static public ExamplePlayerListGUI GetInstance()
{
return s_instance;
}
void Awake()
{
if (s_instance != null)
{
Debug.LogError("there should only be one ExamplePlayerListGUI");
}
s_instance = this;
}
public void AddPlayer(PlayerScript bs)
{
m_players.Add(bs);
}
public void RemovePlayer(PlayerScript bs)
{
m_players.Remove(bs);
}
public void OnGUI()
{
Rect r = new Rect(0, 0, 100, m_players.Count * 20);
GUI.Box(r, "");
r.height = 20;
foreach(var player in m_players)
{
GUI.Label(r, player.PlayerName);
r.y += 20;
}
}
}
PlayerScript can then call ExamplePlayerListGUI.GetInstance().AddPlayer in its Start function and ExamplePlayerListGUI.GetInstance().RemovePlayer in it's OnDestroy function
public PlayerScript : MonoBehaviour
{
private string m_playerName;
...
public string PlayerName
{
get
{
return m_playerName;
}
}
void Start()
{
...
ExamplePlayerListGUI playerListGUI = ExamplePlayerListGUI.GetInstance();
// Check if it exists so we can use it with or without the list
if (playerListGUI != null)
{
playerListGUI.AddPlayer(this);
}
}
void OnDestroy()
{
...
ExamplePlayerListGUI playerListGUI = ExamplePlayerListGUI.GetInstance();
if (playerListGUI != null)
{
playerListGUI.RemovePlayer(this);
}
}
}

Unity3D Programmatically Assign EventTrigger Handlers

In the new Unity3D UI (Unity > 4.6), I'm trying to create a simple script I can attach to a UI component (Image, Text, etc) that will allow me to wedge in a custom tooltip handler. So what I need is to capture a PointerEnter and PointerExit on my component. So far I'm doing the following with no success. I'm seeing the EVentTrigger component show up but can't get my delegates to fire to save my life.
Any ideas?
public class TooltipTrigger : MonoBehaviour {
public string value;
void Start() {
EventTrigger et = this.gameObject.GetComponent<EventTrigger>();
if (et == null)
et = this.gameObject.AddComponent<EventTrigger>();
EventTrigger.Entry entry;
UnityAction<BaseEventData> call;
entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerEnter;
call = new UnityAction<BaseEventData>(pointerEnter);
entry.callback = new EventTrigger.TriggerEvent();
entry.callback.AddListener(call);
et.delegates.Add(entry);
entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerExit;
call = new UnityAction<BaseEventData>(pointerExit);
entry.callback = new EventTrigger.TriggerEvent();
entry.callback.AddListener(call);
et.delegates.Add(entry);
}
private void pointerEnter(BaseEventData eventData) {
print("pointer enter");
}
private void pointerExit(BaseEventData eventData) {
print("pointer exit");
}
}
Also... the other method I can find when poking around the forums and documentations is to add event handlers via interface implementations such as:
public class TooltipTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler {
public string value;
public void OnPointerEnter(PointerEventData data) {
Debug.Log("Enter!");
}
public void OnPointerExit(PointerEventData data) {
Debug.Log("Exit!");
}
}
Neither of these methods seems to be working for me.
Second method (implementation of IPointerEnterHandler and IPointerExitHandler interfaces) is what you're looking for. But to trigger OnPointerEnter and OnPointerExit methods your scene must contain GameObject named "EventSystem" with EventSystem-component (this GameObject created automatically when you add any UI-element to the scene, and if its not here - create it by yourself) and components for different input methods (such as StandaloneInputModule and TouchInputModule).
Also Canvas (your button's root object with Canvas component) must have GraphicRaycaster component to be able to detect UI-elements by raycasting into them.
I just tested code from your post and its works just fine.

how to smooth scroll listview like ios in android?

I am use data from web using XML parser and setting data using custom adapter for this use asyncTask .
My problem is that some devices like Samsang duos,gallaxy work perfectly but on micromax devices it will not work properly.
My adapter is
public class HallBookingAdapter extends ArrayAdapter<MyHall> {
private Context context;
private ArrayList<MCCIAHall> halls;
private int resource;
MyHall objHall;
public int count;
View view;
public static Boolean isScrollingHalls=true;
LayoutInflater inflater;
static class HallBookingHolder
{
public TextView txtTitle,txtLocation,txtCapacity,txtCapacityTitle;
public ImageView imgHall;
public LinearLayout hallBookingLayout;
}
public HallBookingAdapter(Context context, int resource, ArrayList<MyHall> halls) {
super(context, resource, halls);
this.context=context;
this.halls=halls;
this.resource=resource;
inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
count=halls.size();
return halls.size();
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
view=convertView;
objHall=halls.get(position);
HallBookingHolder holder=new HallBookingHolder();
if (convertView==null) {
view = inflater.inflate(resource, null);
holder.txtTitle=(TextView)view.findViewById(R.id.txtListHallTitle);
holder.txtLocation=(TextView)view.findViewById(R.id.txtListHallLocation);
holder.txtCapacity=(TextView)view.findViewById(R.id.txtListHallCapacity);
holder.txtCapacityTitle=(TextView)view.findViewById(R.id.txtListHallCapacityHeadding);
holder.imgHall=(ImageView)view.findViewById(R.id.imgListHall);
view.setTag(holder);
}
else
{
holder = (HallBookingHolder)convertView.getTag();
}
//Creating the Font to the text
Typeface tfLight = Typeface.createFromAsset(context.getAssets(),"OpenSans-Light.ttf");
Typeface tfRegular = Typeface.createFromAsset(context.getAssets(),"OpenSans-Regular.ttf");
Typeface tfsemiBold = Typeface.createFromAsset(context.getAssets(),"OpenSans-Semibold.ttf");
//Setting the font
holder.txtTitle.setTypeface(tfRegular);
holder.txtLocation.setTypeface(tfLight);
holder.txtCapacity.setTypeface(tfsemiBold);
holder.txtCapacityTitle.setTypeface(tfLight);
//Setting data to textview and image
holder.txtTitle.setText(objHall.hallName);
holder.txtLocation.setText(objHall.location);
holder.txtCapacity.setText(objHall.capacity);
//Using Guild Library Image Load using image web url
String imgurl=objHall.getImageUrl();
Glide.load(imgurl).centerCrop().into(holder.imgHall);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(context, HallDetailsActivity.class);
intent.putExtra("position", position);
context.startActivity(intent);
}
});
return view;
}
}
read it listview smooth-scrolling
Using a background thread ("worker thread") removes strain from the
main thread so it can focus on drawing the UI. In many cases, using
AsyncTask provides a simple way to perform your work outside the main
thread. AsyncTask automatically queues up all the execute() requests
and performs them serially. This behavior is global to a particular
process and means you don’t need to worry about creating your own
thread pool.
check this too http://www.itworld.com/development/380008/how-make-smooth-scrolling-listviews-android
Put all your font styles in the if (convertView==null) {} block to set them only once. Now you are setting them every time a new row is created.
Here is a list of quick tips to help you.
Reduce the number of conditions used in the getView of your adapter.
Check and reduce the number of garbage collection warnings that you get in the logs
If you're loading images while scrolling, get rid of them.
Set scrollingCache and animateCache to false (more on this later)
Simplify the hierarchy of the list view row layout
Use the view holder pattern
Here is a link to help you implement these tips. Link