Vaadin Grid Detail doesn't show Image correctly - java

I have a Problem with my Vaadin Grid.
Its a rather simple Grid that just shows some cars with name, model, ps, etc.
If you click on one of the rows, the grid detail opens, and shows a picture of the car.
If you click on the first row in the grid, the Image is cut of and you cant scroll.
But if you click around a bit, for example you click on the 6th row , then the Picture is fine.
Also then you can scroll and if you click on the first row, the image is now shown correctly.
Is this a mistake by me or is this a bug?
public FahrzeugView()
{
final Grid<Fahrzeug> grid = new Grid<>(Fahrzeug.class, false);
grid.setWidthFull();
grid.setHeight("800px");
grid.addColumn(Fahrzeug::getId).setHeader("Id").setSortable(true);
grid.addColumn(Fahrzeug::getMarke).setHeader("Marke").setSortable(true);
grid.addColumn(Fahrzeug::getModell).setHeader("Modell").setSortable(true);
grid.addColumn(Fahrzeug::getPs).setHeader("Ps").setSortable(true).setId("ps");
grid.setItemDetailsRenderer(this.createFahrzeugDetailsRenderer());
final List<Fahrzeug> fahrzeuge = Fahrzeug.setData();
grid.setItems(fahrzeuge);
this.add(grid);
}
private Renderer<Fahrzeug> createFahrzeugDetailsRenderer()
{
return new ComponentRenderer<>(FahrzeugDetailLayout::new,
FahrzeugDetailLayout::setFahrzeug);
}
}
public class FahrzeugDetailLayout extends FormLayout
{
private final Image image = new Image("", "");
public FahrzeugDetailLayout()
{
setResponsiveSteps(new ResponsiveStep("0", 1));
setColspan(this.image, 1);
this.add(this.image);
}
public void setFahrzeug(final Fahrzeug fahrzeug)
{
this.image.setAlt("Bild wird nicht angezeigt!");
this.image.setSrc(fahrzeug.getUrl());
}
}
I dont understand why it is only cut of when you first open the detail and not when you click around and click on it again.
I dont really know what to try to fix this, because i dont know what is causing it to happen.
I tryed google for it but this Problem is very specific.
Thankfull for all the help!

Related

Libgdx updating a label in a table

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.

JavaFX setGraphic() not displaying icon in MenuItem

I need an icon for my MenuItem's.
This is like a "worker class" to get the ImageView of the icon :
public class IconFactory {
private static ImageView HLP_BOOK_JFX;
public enum ICONS {
BASCET_REMOVE, BASCET_PUT, SAVE, OPEN, ARROW_RIGHT, ARROW_LEFT, ARROW_UP, ARROW_DOWN, CLOCK, ANALOG_SIGNAL, DIGITAL_SIGNAL, REFRESH, GREEN_PLUS, NETWORK, OK, CANCEL, RIGHT_NAV2, LEFT_NAV2, PLAY, PAUSE, LIST_ADD, PAGE_FIND, SET_PARAM, DOWNLOAD, UPLOAD, LOG_FILE, WARNING, INFO, LOG_DIAG, DATA_TRANS, TREE, FILTER, SEARCH, PARAM, ERASE, RESETDEF, RESETDEF2, DEBUG_BUG, INTERNATIONAL, CLOSE, HLP_BOOK
}
public static ImageView getImage(ICONS en) {
switch (en) {
case HLP_BOOK:
if (HLP_BOOK_JFX == null)
HLP_BOOK_JFX = new ImageView(new Image(IconFactory.class.getResourceAsStream("help_book.png")));
return HLP_BOOK_JFX;
}
return null;
}
When I use myMenuItem.setGraphic(IconFactory.getImage(ICONS.HLP_BOOK)) for a single menu item it works perfectly.
But then, when I want to generate two menus in a loop and set the same graphic, one MenuItem has no icon displayed. (the first one in loop in the code below).
My code:
while (keys.hasMoreElements()) {
// that will do 2 loops, do not care about how
MenuItem subMenuHelp = new MenuItem("MenuItem");
subMenuHelp.setGraphic(IconFactory.getImage(ICONS.HLP_BOOK));
subMenuHelp.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// do not care
openHelpFile(link);
}
});
System.out.println(((ImageView) subMenuHelp.getGraphic()).toString());
myMenu.getItems().add(subMenuHelp);
}
As you can see, I added a System.out.println to see if a graphic was set for the current item.
Result in console : both lines (MenuItem) with the same ImageView:
ImageView#79814766[styleClass=image-view]
ImageView#79814766[styleClass=image-view]
I did exactly the same in Swing (but with Icons and .setIcons() function) and it worked very well. I've also looked for a "repaint" function to force displaying but no way.
Hope you can help me!
This is because the same Node cannot be attached to the scene-graph multiple times and - as you even state - you are adding the same ImageView object.
From the documentation of Node:
If a program adds a child node to a Parent (including Group, Region,
etc) and that node is already a child of a different Parent or the
root of a Scene, the node is automatically (and silently) removed from
its former parent.
The solution is to modify getImage method of IconFactory to return a new ImageView instance on each call or to return Image instances rather than ImageView instances (the second one fits better to the name "IconFactory" I think).
You could store the Image instance instead of storing the ImageView to avoid re-loading the Image itself. You could check this question as reference: Reusing same ImageView multiple times in the same scene on JavaFX
A possible update on IconFactory:
public class IconFactory {
private static HashMap<ICON, Image> images = new HashMap<ICON, Image>();
public enum ICON {
BASCET_REMOVE, BASCET_PUT, SAVE, OPEN, ARROW_RIGHT, ARROW_LEFT, ARROW_UP, ARROW_DOWN, CLOCK, ANALOG_SIGNAL, DIGITAL_SIGNAL, REFRESH, GREEN_PLUS, NETWORK, OK, CANCEL, RIGHT_NAV2, LEFT_NAV2, PLAY, PAUSE, LIST_ADD, PAGE_FIND, SET_PARAM, DOWNLOAD, UPLOAD, LOG_FILE, WARNING, INFO, LOG_DIAG, DATA_TRANS, TREE, FILTER, SEARCH, PARAM, ERASE, RESETDEF, RESETDEF2, DEBUG_BUG, INTERNATIONAL, CLOSE, HLP_BOOK
}
public static Image getImage(ICON en) {
if (!images.containsKey(en)) {
switch (en) {
case HLP_BOOK:
images.put(en, new Image(IconFactory.class.getResourceAsStream("help_book.png"))); break;
default:
return null;
}
}
return images.get(en);
}
}
Usage after the update:
subMenuHelp.setGraphic(new ImageView(IconFactory.getImage(ICONS.HLP_BOOK)));

In LibGDX scene2d, after changing the items of a selectbox, it no longer has a default listener

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.

Adding row to a TableView from a different controller in JavaFX

In this app that i am building i have in one stage a TableView and a few buttons. When i click on one of the buttons it opens a new window that is made of TextFields and a "OK" button. When i click on the OK, i need to insert that data into a Table.
So, i know how to insert a row into a TableView from a controller that controlles that TableView, but now i need to insert it from controller of another window. I tried everything, and it doesent work. I tried to get an instance of TableController and pass the data to its method, then i tried to pass ObservableList to a NewWindowController, and that also doesent work. I'm out of ideas. Can someone help me with this, i would appreciate it. Thank you.
Part of the code:
public class MainController {
#FXML public TableView<Film> tabel;
public TableView<Film> getTabel(){
return tabel;
}
}
newWindow'sController:
public UnosController(){
#FXML protected void insert(ActionEvent e){
Film film = new Film(funosNaziv.getText(), funosZanr.getText(),Integer.valueOf(funosGodina.getText()));
TableView<Film> tabel = mainController.getTabel();
ObservableList<Film> data = tabel.getItems();
data.add(film);
}
}
That is my last try. Doesent work.

Creating a GWT iFrame like screen

I have been developing an app with Java + GAE (1.8.6) + GWT (2.5.1) and now, as per a requirement of my client, i need to create a screen layout divided in two parts (25%,75%), being in the left side the options, and in the other 75% of the screen, the result of the option clicked (like a screen set as an iFrame).
I have tried to use a DockLayoutPanel with west and center panel added to them, but i cant manage to load the contents of each link placed in the west panel on the center panel.
I have been Google'ing for a solution or some code to adapt it to my needs, but so far I havent had much success.
¿Could you please help me out?. I bought also GWT in Action by Manning ed. but havent found much about this matter there.
Meanwhile i will keep looking around / trying to find a solution on my own.
Thank you in advance,
Kind regards,
The solution i found was:
//define framedPanel for later use
private FramedPanel fupanel;
//Instantiate the widget i want to add when the option is clicked
final FileUp fileUp = new FileUp();
//Create the HtmlLayoutContainer in which add the widget later on
HtmlLayoutContainer conEnlaces = new HtmlLayoutContainer(getTablaEnlaces());
public Widget asWidget() {
if (fupanel == null) {
fupanel = new FramedPanel();
fupanel.setHeadingText("Administración");
(some other code here)
VerticalLayoutContainer p = new VerticalLayoutContainer();
conEnlaces.setWidth(Window.getClientWidth());
fupanel.add(p);
p.add(conEnlaces);
Hyperlink fileUph = new Hyperlink();
fileUph.setText("- Importación de CSV");
conEnlaces.add(fileUph, new HtmlData(".fileUph"));
filexh.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
conEnlaces.add(filex, new HtmlData(".resultado"));
}
});
fupanel.add(conEnlaces);
}
return fupanel;
}
private native String getTablaEnlaces() /*-{
return [ '<table border="0" cellspacing="0" cellpadding="0">',
'<tr><td>',
'<table border="0" width="75%">',
'<tr><td class=fileUph></td></tr>',
'</table></td>',
'<td><table border="0" style="margin-left: 25px;">',
'<tr><td class=resultado></td></tr>',
'</table>',
'</td></tr></table>'
].join("");
}-*/;
public void onModuleLoad() {
RootPanel.get().add(asWidget());
}
And like this my problem has been solved. I have shown you my code because i get angry at times when using stackoverflow forums, and people say to have reached a solution, but dont explain how.
Thank you for your response and time,

Categories