Anyone succeeded in changing text in nifty programatically?

I can change my nifty screen controls by using onFocus, onClick, etc, but I have yet to see a successful change triggered by Java from outside nifty’s screen controller.



Anyone could share their knowledge of how they did it?



One note though: At one point the whole nifty screen will change but it’s not smooth. Let me explain in details.



As the user click “Whatever”, the button calls a method. That method, outside nifty, does stuff. It’s not important what it does except the part where, for example, it notifies the nifty screen to change a <text … > tag to inform the user of what’s going on. This, of course, should happen in real time as the outside method goes through its things, changing the text tag, this should update as it happens.



For me, the above happens at the end. At that point, only the latest change is displayed of course. There is also the problem where the control doesn’t come back to the nifty’s method where everything was spawned.



Here’s the nifty’s screenController’s method attached to the button:

[java]

public void genGalaxy() throws GameExceptions, IOException, InterruptedException {



getElement(“layer_menu”).hide();

getElement(“galGenLayer”).show();

makeWorld();

Game.isRunning = true;

Game.isWorldDone = true;

Game.doStart = true;

nifty.exit();

}

[/java]



When I click the button, the first two lines work without a problem but anything after makeWorld isn’t run, in fact the game never returns ever from calling makeWorld().



So, if anyone has succeeded in doing that, I’d be grateful if they could share how they did it.

1 Like

To answer your question in the topic:



[java]Element e;

e.getRenderer(TextRenderer.class).setText(“Hello”);[/java]



The reason your program stops running is (most likely) that it encounters a “null” somewhere. I’ve noticed it doesn’t throw an exception, but it will say something in the logs about it.



If i understand your main concern correctly:

If you want it to continuosly update nifty, you’ll need to implement some kind of listener interface.

I do this actually:



[java]screen.findElementByName(“hint_text”).getRenderer(TextRenderer.class).changeText(message);[/java]



As I said, it works. But only, after nifty has gotten “stuck” in a loop or whatever that happens. But then at that point it’s too late. The screen don’t even go away.



As far as the listener part of it, I did that yesterday. With mitigated success. Messages go back and forth but pretty much the same thing happen, no update on the screen.



I will check what you said about the logs, maybe there’s something there that I overlooked.

It turned out there’s an error. I guess it didn’t help that I was discarding all errors except SEVERE. :frowning:



So now I can pinpoint a probable cause.



I’ve commented out pretty much everything until I would get the guilty line that would make nifty spews the

error code below:



[java]Nov 19, 2010 11:29:10 AM de.lessvoid.nifty.NiftyMethodInvoker callMethod

WARNING: error: null[/java]



This is what is causing the problem:

[java] Material mat = new Material(assetManager, “Common/MatDefs/Misc/SolidColor.j3md”);[/java]



When stepped into, I get into Material.java where the following method doesn’t agree with nifty (that’s on lines 151-153).

[java] public Material(AssetManager contentMan, String defName){

this( (MaterialDef) contentMan.loadAsset(new AssetKey(defName)) );

}

[/java]

While in debug, it says contentMan is null.



That’s where I’ll get the error quoted above.



That’s the extend of what I can do. Anyone with enough knowledge can shed some light on that?

Well, I could help, I suppose but that would require that I understand the problem :slight_smile:



I can’t check at the moment because I don’t have the sources available right now but that Material line is from the JME3 Nifty renderer, right?



Can you verify that you’re using the same Nifty instance and that this instance has been initialized correctly? When you have a Nifty instance you should be able to do anything with Nifty. It’s not at all bound to the ScreenController.



In your original example I suppose that genGalaxy() is called by some Nifty onClick() method, right? So what is happening in makeWorld() that might be triggering a NPE?



Maybe some high level overview of the things you’re trying to do might help me to understand (and probably help you)?

Can you verify that you’re using the same Nifty instance and that this instance has been initialized correctly?


This is something i had problems with today. If you're using a java instanced instance of the controller, it's not necessarily the same as the one instanced from nifty, even with registerController(), it seems. bind() will help with that.
1 Like

Thanks for taking the time void.



Just finished doing some additional tests. Here is the result. But first, let me paste you the ScreenController’s code.



[java]package gui;



import error.GameExceptions;

import stellarconquest.Game;

import de.lessvoid.nifty.EndNotify;

import de.lessvoid.nifty.Nifty;

import de.lessvoid.nifty.elements.Element;

import de.lessvoid.nifty.elements.render.TextRenderer;

import de.lessvoid.nifty.screen.Screen;

import de.lessvoid.nifty.screen.ScreenController;

import event.EventSubject;

import java.io.IOException;

/**

*

  • @author Dany

    */

    public class LoadingScreen extends Game implements ScreenController {

    private Nifty nifty;

    private Screen screen;

    protected TextRenderer eHintText;

    ProgBarControl pbar;



    public void genGalaxy() throws GameExceptions, IOException, InterruptedException {

    changeHint(“Starting Galaxy generation…”);

    getElement(“layer_menu”).setVisible(false);

    getElement(“galGenLayer”).setVisible(true);

    float damnLong = 50001f;

    for (float i=0.1f;i<damnLong;i+=.1f) {

    updateProBar(i);

    }

    // makeWorld();

    // Game.isRunning = true;

    // Game.isWorldDone = true;

    // Game.doStart = true;

    // nifty.exit();

    }



    @Override

    public void bind(final Nifty niftyBind, final Screen niftyScreen) {

    this.nifty = niftyBind;

    this.screen = niftyScreen;



    eHintText = screen.findElementByName(“hint_text”).getRenderer(TextRenderer.class);

    pbar = screen.findControl(“my-progress”, ProgBarControl.class);

    //registerListeners();

    }



    @Override

    public void onStartScreen() {

    eHintText = screen.findElementByName(“hint_text”).getRenderer(TextRenderer.class);

    pbar = screen.findControl(“my-progress”, ProgBarControl.class);

    screen.findElementByName(“galGenLayer”).hide();

    pbar = screen.findControl(“my-progress”, ProgBarControl.class);

    }



    @Override

    public void onEndScreen() {}



    public void bye() {

    nifty.createPopup(“popupExit”);

    nifty.showPopup(screen, “popupExit”, null);

    }



    public void updateHintText(String text) {

    System.out.println(text);

    eHintText.setText(text);

    }



    private void updateProBar(float add){

    //screen = nifty.getScreen(“start”);

    pbar.setProgress(add);

    }



    public void saveGame() {

    eHintText.setText(“Cannot save games right now.”);

    }



    public void changeHint(String newHint) {

    eHintText.setText(newHint);

    }



    public void loadGame() {

    eHintText.setText(“Cannot load games right now.”);

    }



    private Element getElement(final String id) {

    return nifty.getCurrentScreen().findElementByName(id);

    }



    /**
  • popupExit.
  • @param exit exit string

    */

    public void popupExit(final String exit) {

    nifty.closePopup(“popupExit”, new EndNotify() {

    @Override

    public void perform() {

    if (“yes”.equals(exit)) {

    nifty.setAlternateKey(“fade”);

    nifty.exit();

    Game.quit();

    }

    }

    }

    );

    }



    public void onEvent(String updateThis, String message) {

    if (updateThis.equals(“Hint”)) {

    updateHintText(message);

    } else if (updateThis.equals(“Progress”)) {

    updateProBar(1f);

    }

    }



    private void registerListeners() {

    //Game.gameEvents.addEventListener(this);

    }



    @Override

    public void onEvent(EventSubject e, String updateWhat, String message) {

    throw new UnsupportedOperationException(“Not supported yet.”);

    }

    }

    [/java]



    As you can see in the constructor, the commented out lines are what it’s supposed to do. For the test I was talking about above, I simply decided to use a counter to augment the progress on the Progressbar. As I stated, it works, but only displays at the END. Nothing updates while it happens.



    On the other buttons, Save and Load, it does what it’s supposed to do. Those work. But as soon as I get out of the ScreenController, it freezes until whatever code that runs has finished. It’s ONLY at that point that the screen updates.


n your original example I suppose that genGalaxy() is called by some Nifty onClick() method, right?

Yes. As shown above.

So what is happening in makeWorld() that might be triggering a NPE?

There are no exception thrown or raised except for the "null" shown by the Logger. makeWorld() is a method that I use where I call different methods to create a galaxy, fill an Octree, create the player's ship, pin the stars to the canvas, etc.

The goal is to have nifty on top and inform the users of what's going on.

Can you verify that you’re using the same Nifty instance and that this instance has been initialized correctly? When you have a Nifty instance you should be able to do anything with Nifty. It’s not at all bound to the ScreenController.

As far as I know there's only 1 instance. For that latest test I dropped using an isolated class to call the screen. I do that now directly from the game's code.

Hopefully we can find the solution to that problem, which is probably my fault.

Your genGalaxy() progressbar won’t work this way because there is no one rendering the screen while you keep updating your progressbar :slight_smile:



I think that might explain some other issues you experience. A Nifty method call currently comes directly out of the Nifty render() method! So there won’t be anybody rendering the GUI elements you’ve updated.



That will explain the freezing too when you do some longer action in a button onClick() callback. You’ll need to find a way to do that somewhere else and not directly in a method callback triggered by Nifty by an onClick() callback.

When you have the Nifty instance somewhere outside of the ScreenController available you should be able to update the Nifty elements which then would be rendered the next time jme calls the Nifty.render() method…

void256 said:
When you have the Nifty instance somewhere outside of the ScreenController available you should be able to update the Nifty elements which then would be rendered the next time jme calls the Nifty.render() method...


I'd swear that's the way it was before I did my test... I'll move those into the instancing class I had and see what happens. But it'll have to wait until after dinner.
void256 said:
Your genGalaxy() progressbar won't work this way because there is no one rendering the screen while you keep updating your progressbar :)


Ok. I get that.

You'll need to find a way to do that somewhere else and not directly in a method callback triggered by Nifty by an onClick() callback.


Care to throw a suggestion at me? I don't see how I can wait for an user input and not use that input to trigger an event... That baffles me.

You can do the loading in another thread.

Momoko_Fan said:
You can do the loading in another thread.

So you're basically saying I should spawn a thread using the onClick event that will update the screen loader?

I guess I could use the custom internal event manager I made yesterday with that click. Then go on from there... For some reason I doubt that'll work. But let's give it a try. Who knows.

Hopefully that won't give me the same result I already get by starting makeWorld() method. That's what I'm fearing.

You can use the assetManager to load your world and construct it (AssetManager is thread-safe), but once you want to attach it to your root node, you have to do that in the rendering thread using a Callable.

If you look at the fourth post above, as soon as I hit a line of code that involves assetManager the thing “hangs”. It goes round and round into a loop and never gets out back from where it was called. Only hitting ESC or closing the app stops it.



EDIT: Fourth post. Not first.

Yeah, thats why you do it in another thread, so it doesn’t block your rendering thread

madjack said:
void256 said:You’ll need to find a way to do that somewhere else and not directly in a method callback triggered by Nifty by an onClick() callback.

Care to throw a suggestion at me? I don't see how I can wait for an user input and not use that input to trigger an event... That baffles me.


Well, where do you update your usual in-game state stuff? When using the jme SimpleApplication framework then this usually happens in the simpleUpdate() method I suppose.

You'd need to trigger a state change from the Nifty onClick() that puts your application in the "whatever-you-want-to-do" state and then react/change things accordingly in simpleUpdate() or in whatever game state update loop you usually do things!?

Took a while but I succeeded yesterday in having nifty cooperate with the rest of the game. It updates (although it’s not quite the way I want it, it does what it’s asked to do).



Now, I don’t want to sound like a vinegar pisser, but I’m wondering about certain things. Don’t take it as me being rude please, I’m only trying to understand. There are many many … many things I don’t yet get with Java, so that’ll hopefully be a leaning experience too.



After reading several tutorials and how-tos about synchronization and threading and what-have-you, I’m wondering why nifty itself can’t update controls from modifications coming from outside the ScreenController (or any “nifty” screen really). Why is it my job to do that? I’m not really complaining here. I’m trying to understand why nifty doesn’t, itself, spawn a separate rendering-pathway so it can update those changes. Maybe a daemon thread or something that would essentially do what we have to implement ourselves. I mean, nifty is aware of what’s on the screen, it knows the placement of each control. That’s why we define classes telling it how we set our things up right? So why? Is that unnecessary from some standpoint? Too complicated? Planned for the future?



If there were one major improvement I’d love to see in nifty/jME3, that’s that. I’m sure I wouldn’t be alone in that boat. I’ve seen numerous people posting about nifty’s somewhat difficult implementation. But again, what’s not to love about nifty? It looks great, it’s expandable and it’s just plain cool.



So, in a nutshell, that’s it.



I wish I was more advanced with Java, jME3 and nifty. I would do what I’m suggesting myself. But alas, I’m already way over my head as it is.



So thanks to everyone who helped me in this thread. I really appreciate it. :slight_smile:

Because this never really occured as a problem to me, I suppose.



The idea was from the beginning that one would be able to add Nifty to any kind of rendering system or game as easy as possible. Somewhere in your rendering loop you would simply call Nifty.render() and Nifty will render itself at this point. Done. If you don’t want the GUI then you won’t call nifty.render(). Done. If you want to display the GUI you decide when you want to render the GUI and when not. Native Nifty will require you for instance that you’ll need to setup the OpenGL render state to something appropriate to render the GUI, usually called 2d ortho mode and so on.



So, I supposed that people are smart enough to know the implications and that they understand that f.i. any nifty.render() method will trigger all of the onClick() callbacks and that you’d not start any long running things. Simply because you’d stall the rendering thread that had called you in the first place :slight_smile: This worked fine for native lwjgl or slick2d applications.



With JME it’s now a somewhat different issue because the details of rendering the GUI are hidden from you. So from that perspective your problems are understandable. We’ll think about what we can do to improve the situation tho.

1 Like

I guess on that angle it makes sense.



Multi-platform development is a hassle (even for Java sometimes), so I can’t even imagine to support multi-rendering systems.



Hopefully down the line we’ll get served. :wink:



Thanks again for your help void!