I have not found a similar question anywhere, so I decided to post.
The problem is that texttooltip is not showing on element on android, though works perfectly on desktop launch. I added some sysouts and app seems to detect enter and exit events correctly(desktop shows same console output), but for some reason tt still wont popup.
The objective is so when user holds the element(touchable), app shows a texttooltip.
What may be the problem?
Edit: I have tried extending TextTooltip, overriding enter() and exit() methods and only adding sysout to them. Holding finger on button with my TextTooltip triggers enter() once and releasing a finger triggers exit() once. Like hovering a mouse on desktop, same output. Only difference is actual tooltip not showing up.
Okay I fixed this. Maybe it helps anyone with similar os same issue.
public class HoldTooltip extends ActorGestureListener {
Label tooltip_text;
Table tooltip_actor;
public HoldTooltip(String tooltip_text) {
this.tooltip_text = new Label(tooltip_text, skin);
tooltip_actor = new Table();
tooltip_actor.add(this.tooltip_text);
tooltip_actor.setSize(this.tooltip_text.getPrefWidth(), this.tooltip_text.getPrefHeight());
getGestureDetector().setLongPressSeconds(0.5f);
}
#Override
public boolean longPress(Actor actor, float x, float y) {
tooltip_actor.setPosition(x+50, y+50);
actor.getStage().addActor(tooltip_actor);
return super.longPress(actor, x, y);
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
tooltip_actor.remove();
super.touchUp(event, x, y, pointer, button);
}
Basically I just redone the stock TextTooltip, the difference being this one actually works as intended. If you want cool animations just add a sequence when adding or removing tooltip_actor to stage.
Related
I'm relatively new to java and android programming, and i wanted to get coordinates based on a point that i tapped on HERE maps. I really hoped you guys could help me out with this.
Edit :
This is the code that i tried to implement, however, it returned me with the error : Error:(354, 53) error: cannot find symbol variable PointF :
private void addDestination() {
image.setImageResource(R.drawable.marker);
GeoCoordinate endpoint = map.pixelToGeo(PointF);
MapMarker destination = new MapMarker(endpoint,image);
if (destination != null)
{
map.removeMapObject(destination);
}
else
{
map.addMapObject(destination);
}
}
PointF is a datatype, so calling "map.pixelToGeo(PointF)" doesn't make sense, you need to call it with concrete data.
In a short:
You need to listen for click events (or longpress, or whatever event you wanna handle), and you get PointF data that's reflecting the screen coordinates. Then you can convert the screen coordinates via pixelToGeo into geocoordinates that you can use to add mapmarker or whatever you wanna do with it on the map.
Some code to help you getting started:
Listening to click events on the map (to retrieve the PointF screencoordinates) are done via registering the gestureListener to your mapview. Means, after successfull mapengine init, you do something like that:
yourMapViewInstance.getMapGesture().addOnGestureListener(yourGestureHandlerImpementation, 10, true);
and in your gestureHandler implementation, you can override several events (click, longpress, etc.), so for example you can do for longpress the following:
private MapGesture.OnGestureListener yourGestureHandlerImpementation = new MapGesture.OnGestureListener.OnGestureListenerAdapter()
{
#Override
public boolean onLongPressEvent(PointF p) {
GeoCoordinate c = map.pixelToGeo(p);
// c is your geoccordinate on the map, where you clicked on the screen
// [...]
}
}
Having an issue with tables and updating a label! Here is the dilemma, I have a sell button in my game that is updating the player's coins whenever they sell an item, that part is working perfectly. The issue I am having is trying to get the coin value to update on the screen while there in this separate menu (see pic attached, coins in the top left). The problem is that the coin value is in another stage in another class. This is because I have different tables that pop up in the middle when I click the different buttons at the bottom. I have tried helper methods for going in and clearing that table and updating it and then sending me back to this item page but it is not working, I can post any code needed but this is more of a general question on how to update a label within a table in a stage.
Update: So to kinda sum up my question, I have a Screen and I have have three tables in it the bottom table the top left and the top right. Then I add the table to the stage in the middle when they press the inventory or shop button etc. What I am looking to do is to keep the item page open and simply just update the value of the Coin label, I know I can change the text using .setText(); Im just not sure how I can update that portion of the screen etc..
Update 2: If I just set the screen back to a new screen of this screen it updates the coin value but then I am not on the item page anymore which is not ideal.
Update 3: Thanks for the help so far guys, #John your answer is super helpful aswell. Im still not getting this working though here is a little bit of the code where the label is being handled.
playerCoinLabel = new Label(playerSave.getCoinsString(),skin,"defaultMiddle");
This is where it is getting added to the table.
tableLeft = new Table(skin);
stage.addActor(tableLeft);
tableLeft.setBounds(0,0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
tableLeft.setFillParent(true);
tableLeft.top().left();
tableLeft.add(healthNonButton).size(84,80).left().padLeft(10).padTop(5);
tableLeft.add(playerHealthLabel).left().padLeft(15);
tableLeft.row();
tableLeft.add(levelNonButton).size(74,70).center().padLeft(10);
tableLeft.add(playerLevelLabel).left().padLeft(19);
tableLeft.row();
tableLeft.add(coinNonButton).size(74,70).center().padLeft(10);
tableLeft.add(this.playerCoinLabel).left().padLeft(15); //This line
tableLeft.row();
Then I have this method for updating my label using the setText like you guys were telling me about.
public void updatePlayerCoins() {
playerCoinLabel.setText(playerSave.getCoinsString());
}
and if I call this method anywhere, render() or where im setting the new coin value it is not updating/changing the label in the top left of my screen. I can post all the code to a github if I need to just posted the things involving the label. This is just a project im working on to increase my skill set so sorry if I sound amateur, it is because I am!
Thanks everyone!
It seems like you're asking two things- how do I update a label? and How do I structure my code? It's hard to tell what's going wrong with the former since we can't see your code, but #Tenfour04 is right- you want to retain a reference to the label somewhere and call setText() when you want to change the amount.
As far as structuring your code, I would suggest a simple OOP design and then evolve it like so:
First, we need an object to represent the player:
class Player {
private int coins; // Pretend there are getters / setters.
private int health;
private int level;
}
Now you probably have more than one way that you want to represent this player information, so we'll split the rendering code into a separate class or set of classes:
class StatWidget {
private Stage stage;
private Player player;
private Label lblCoins;
public StatWidget(Player player) { // Pseudo-code
this.player = player;
this.stage = new Stage();
Table tbl = new Table();
this.lblCoins = new Label(); // Notice we keep a reference to the label
tbl.add( this.coins );
}
public void update() {
lblCoins.setText(player.getCoins());
}
}
Now you can sync the UI with your player object's state simply by calling Player#update(). But when do you call it?
You could call update() in your render method. This is a little inefficient because you're updating the object whether it needs to be updated or not, but it's dead simple, and if you're only updating a few UI elements this way it probably doesn't matter. Personally, I'd stop here.
If you want to be more precise, you would only call update() when you actually make a change to the Player's coins. You can do this by finding the places in your code where you set the player's coins and add the update call like so:
player.setCoins( A_LOT_OF_MONEY );
statWidget.update();
Problem is this gets more cumbersome as you add more widgets- all your game logic now has to know about StatWidget and make calls to it. We could cut this dependency a little bit by using an event-driven architecture. Essentially, whenever player's state changes, it would send an event to interested parties notifying them of the change. You could use the pseudo-code below:
interface Publisher {
void subscribe(Subscriber subby);
void unsubscribe(Subscriber subby);
}
class Player implements Publisher {
private List<Subscriber> subscribers;
private int coins;
// ...
public void setCoins(int amount) {
this.coins = amount;
for(Subscriber subscriber : subscribers) subscriber.notify("COINS", amount);
}
public void subscribe(Subscriber subby) {
this.subscribers.add(subby);
}
public void unsubscribe(Subscriber subby) {
this.subscribers.remove(subby);
}
}
interface Subscriber {
void notify(String event, int qty);
void dispose();
}
class StatWidget implements Subscriber {
private Publisher player;
private Label label;
// ...
public StatWidget(Player player) {
this.player = player;
this.player.addSubscriber(this);
void notify(String event, int qty) {
if(event.equals("COINS")) label.setText(qty);
}
void dispose() {
this.player.unsubscribe(this);
}
}
The event system above could certainly be polished, and you could likely do clever things with generics (or use a library that has thought all this out for your), but hopefully it illustrates the concepts.
I dont think my problem is that hard to solve but I have been searching for a while and cant figure it out.
I have two scene2d SelectBox widgets one above the other, in a table, on a stage. Let's call them A and B. Whatever is selected in A determines which list is shown in B. I implement this using a ChangeListener on A and all works fine (this isn't the problem).
However, my list A was getting extremely long (500+ items) so I wanted to add a TextField above it which would search and match the strings, replacing the old list of A with a shorter one, making it much easier to find what you are looking for. This works fine, I use a ChangeListener on the textfield to get the string, compare it to a main list of strings using a for loop and use aList.setItems(); to add the adjusted string to the SelectBox. The list displays (without a click, so I use aList.showList(); in the ChangeListener of the TextField) and I think this is where the problem occurs - instead of a click, showList() is called from elsewhere. Lets say I change my mind and want to select a different item from A, it will no longer drop down the menu on click. Yet if I change the text which is in the search bar, it displays the list. When the list is displayed, I can click an item and it hides as normal.
This might seems a bit confusing, so here is the code (edited for clarity, so if something is missing let me know)
SelectBox aSelect, bSelect;
TextField searchBar;
Stage stage;
Table table;
Skin skin;
ArrayList<String> completeAList;
ArrayList<String> abrevAList;
public chooseItemScreen()
{
stage = new Stage(new ScreenViewport());
skin = new Skin(Gdx.files.internal("uiskin.json"));
table = new Table();
table.setFillparent(true);
completeAList = new ArrayList<String>;
abrevAList = new ArrayList<String>;
aSelect = new SelectBox(skin);
//ItemList is a class with the list of strings as a static method
completeAList = ItemList.getAList();
aSelect.setItems(completeAList.toArray());
//bSelect omitted as is same as A
//aSelect changeListener also omitted as it is working fine
searchBar = new TextField("", skin);
searchBar.setMessageText("SEARCH LIST");
searchPokemon.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
updateASelect();
}
});
table.add(searchBar);
table.row();
table.add(aList);
stage.addActor(table);
Gdx.input.setInputProcessor(stage);
}
private void updateAList()
{
abrevAList.clear();
aSelect.clearItems();
aSelect.hideList()
for (String string: completeAList)
{
if (string.toLowerCase().startsWith(searchBar.getText().toLowerCase()))
{
abrevAList.add(string);
}
}
if (abrevAList.isEmpty())
{
abrevAList.add("NOT FOUND");
}
aSelect.setItems(abrevAList.toArray());
//It's at this point where I am no longer to click on aSelect
//I can still select an item from the drop down list, closing the list
//it's just I can't show list by clicking on the widget after that
aSelect.showList();
}
#Override
public void render(float delta) {
Gdx.gl20.glClearColor(0,0,0,0);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
I added the following listener to tell if the selectBox was being clicked (which it was). I gave all actors names
stage.getRoot().addCaptureListener(new InputListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
System.out.println(event.getTarget().getName());
return false;
}
});
The click is recognised, just the list doesn't show. In my opinion, it is a problem with calling showList() and changing the list at the same time.
Any help is appreciated, and if you need more code or any other information, let me know.
Thanks
Set a fixed size to the selectbox when adding it to the table, something like
table.add(selectBox).width(someValue);
or
table.add(selectBox).growX();
Also, after reviewing your code, I suggest you to remove
aSelect.clearItems();
aSelect.hideList();
And make ArrayList be just libgdx Array< String>, it will make things easier, wont cause allocation when iterating with ':' and you wont need .toArray() when setting the items of your selectboxes. You also can set SelectBox type with SelectBox< String>, and, you can add a row in the same line with table.add(something).row().
After changing the size of the selectbox cell your code worked just fine in my side.
Ok, so, what I've been trying to figure out is how I can make a custom MouseListener for all my buttons that would not require listing every single one of them in the Handler, because I'm going to have a lot of them. Here's the code I have in my Listener as of now:
package com.dinobuilding.handler;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import com.BLANK.BLANKScreen;
import com.BLANK.BLANKWindow;
import com.BLANK.menufeature.Button;
public class ButtonHandler implements MouseListener {
public BLANKWindow dbw;
public BLANK Screen dbs;
static Button button = new Button();
public int buttonX = button.x;
public int buttonY = button.y;
public int buttonSizeX = button.xSize;
public int buttonSizeY = button.ySize;
public ButtonHandler(BLANKWindow dbw, BLANKScreen dbs) {
this.dbw = dbw;
this.dbs = dbs;
}
public static void setButton(Button b) {
button = b;
}
public int mouseEventX;
public int mouseEventY;
Graphics g;
public void mouseClicked(MouseEvent e) {
mouseEventX = e.getLocationOnScreen().x;
mouseEventY = e.getLocationOnScreen().y;
if(mouseEventX <= buttonX && mouseEventX >= buttonX + buttonSizeX) {
if(mouseEventY <= buttonY && mouseEventY >= buttonY + buttonSizeY) {
button.onClicked(dbs, dbw, g);
}
}
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
And here's the code in the first button that I'm trying to implement:
package com.BLANK.menus;
import java.awt.Color;
import java.awt.Graphics;
import com.BLANK.BLANKScreen;
import com.BLANK.BLANKWindow;
import com.BLANK.handler.ButtonHandler;
import com.BLANK.menufeature.Button;
public class MainMenuPlayButton extends Button {
public static int x;
public static int y;
public static int xSize;
public static int ySize;
public static String s;
public static Graphics g;
public MainMenuPlayButton(int x, int y, int xSize, int ySize, String s, Graphics g) {
super(x, y, xSize, ySize, s, g);
this.x = x;
this.y = y;
this.xSize = xSize;
this.ySize = ySize;
this.s = s;
this.g = g;
setColor(new Color(0, 226, 26));
draw();
}
public MainMenuPlayButton() {
}
public static void draw() {
drawButton(x, y, xSize, ySize, g, s);
ButtonHandler.setButton(new MainMenuPlayButton());
}
public void onClicked(BLANKScreen dbs, BLANKWindow dbw, Graphics g) {
setColor(new Color(216, 0, 0));
}
I think my main problem is that the code in the ButtonHandler gets called before the code in the Button class and therefore the ButtonHandler is utilizing the Button class itself, not the MainMenuPlayButton class. If you need the Button class as well, simply tell me, however I can't imagine why. Thank you in advance!
Edit
Ok, after debugging some, I have found that I in fact have the opposite problem. The button is never being clicked. The getSource() method could work, however I don't really know how to use that and I don't think that I could use that without hardcoding every single button, which is really something I do not want to do.
EDIT 1:
Do you think maybe I could do use the MouseEvent's getX or getXOnScreen? By the way, I registered the ButtonHandler using frame.addMouseListener on my JFrame, so...
EDIT 2:
It would seem that the getX method does not work either. If you could help me on that, I would very much appreciate that.
If you want to get the object that was pressed and tripped the MouseListener, use the MouseEvent's getSource() method. For example, this might work:
public void mouseClicked(MouseEvent e) {
(YourButton) button = (YourButton) e.getSource();
button.onClicked(...);
}
Other bits:
Rename your class from Button to something else, since the Button name clashes with the java.awt.Button class, and this can cause difficult to debug errors.
I cringe any time I see a Graphics field declared in a class, as it suggests possible inappropriate painting. Make sure that you really know what you're doing if you ever use one of these as a field since it's easy to get image loss or a NullPointerException if not used correctly, since the Graphics object is frequently changed by Java, and this change is completely out of your (the programmer's) control. Don't say that you haven't been warned.
Edit
Regarding your comments:
Yes, I do know what I'm doing with the Graphics field, however, if it makes you feel better, know that it's only temporary and I will be changing it to something else later.
OK, I've just been burned on this before. As long as you get it from a BufferedImage and don't try to get it by calling getGraphics() on a component or by pulling it out of a paint or paintComponent method, then you might be OK.
Also, I'm pretty sure that I'm getting the object it clicked correctly, but I can't get it to access the correct subclass of Button. It's only getting the Button class itself, not the MainMenuPlayButton.
Sorry, but this doesn't make sense since you don't get "classes" when you obtain a reference, an object pure and simple, and in fact you would get the very same object that the ButtonListener was added to and that tripped the listener, and the class of this reference will be whatever class your button is. I am assuming that you're adding your MouseListener directly to your "Button" object, correct? Again, time to do some debugging.
Edit 2
Regarding the most recent edit to your question:
Ok, after debugging some, I have found that I in fact have the opposite problem. The button is never being clicked. The getSource() method could work, however I don't really know how to use that and I don't think that I could use that without hardcoding every single button, which is really something I do not want to do.
No, there is no need to hard-code each button, trust me. That's the whole reason for using listeners that are added to the buttons.
EDIT 1: Do you think maybe I could do use the MouseEvent's getX or getXOnScreen? By the way, I registered the ButtonHandler using frame.addMouseListener on my JFrame, so... the
There's one of your problems. If you want to listen to your buttons, you're going to want to be able to register listeners on the button itself. If you have an array or collection of them registering listeners is easy. And no, I don't recommend using x and y on screen since it makes your program extremely fragile. If you did this, any changes to the structure of your GUI would require subsequent hard-code changes to your x and y handling. Ugh.
This begs the question of why create your own Button class, and why not instead use JButtons or a subclass of JButtons. You appear to be re-inventing the wheel, but (sorry to be blunt) creating one that is square.
Edit 3
But you cast the variable to a button, meaning that if I have multiple buttons I have to cast each and every one of them to a different thing.
No absolutely not as the magic of polymorphism should work here. But they're objects of the same type, no? Or do you have many different subclasses of your Button class? And regardless, inside of the mouseClicked(...) method, you appear to want to call only one method on your button, onClicked(...), which I imagine has to be an object of the super class, right? So by calling this method on the current button, It should call its own correct code.
The problem I have with JButton is that they already exist. I can't edit them and I can't customize them, ...
This is patently not true. You can change their appearance and behaviors by many means, including by subclassing or by a factory creation method. Plus they already come with the machinery for being able to register listeners and respond to mouse actions.
...Also, would I have to register/make a new handler for each and every one of the buttons?
Again, you appear to be forgetting that polymorphism should take care of all of this. One handler should do, depending on how well-behaved your code is.
I am going to have a LOT of buttons, and I don't think that that would be a viable solution. If not the getX how would I get it to do something when the thing is clicked?
I've given you my recommendation, other than sometimes it is better to re-write sections of code if the design can be improved, meaning again you may want to consider retrofitting your code to use JButtons.
I don't quite get how this bit of code works. I understand the outcome (to add a new object using the mouse coordinates), but can you explain to me how the lines beginning with 'MouseInfo...' and 'addObject..' work? Is a new MouseInfo object created for each click event called 'mouse'?
public void act()
{
// Add your action code here.
if( Greenfoot.mouseClicked(this)) {
MouseInfo mouse = Greenfoot.getMouseInfo();
addObject( new Frog(), mouse.getX(), mouse.getY());
}
}
When you invoke Greenfoot.getMouseInfo() you receive a MouseInfo object from the Greenfoot class. It could be a new Object for every click or one that gets reused and updated as the user clicks.
The MouseInfo object has the methods getX() and getY() which return the coordinates of the click. Finally the addObject method adds a new frog at the specified position.