I'm trying to create in-game window, using Table class. But when i added groups of images to that table, seems row() method has no influence to groups, they all are in the same place. Using Images instead of Groups works.
PS. I used Group to overlap images (kinda border for hover effect), don't know better way to do that.
Thanks
public class MyGroup extends Group{
public MyGroup(Image bg, Image thumb){
this.addActor(bg);
this.addActor(thumb);
}
}
public class ActionScreen extends Table {
MyGroup[] group =new MyGroup[8];
for (int i=0;i<8;i++){
group[i] = new MyGroup(new Image(skin.getDrawable("item-bg")),new Image(skin.getDrawable("item-bg-over")));
if (i==4){
row();
add(group[i]).top().padLeft(100);
}
else{
add(group[i]).top().padLeft(100);
}
}
Group's, by default, have zero size, so you have to manually set the size.
In your MyGroup constructor, you'd want to call something like this
this.setSize(bg.getWidth(), bg.getHeight());
Related
A frequent problem I encounter when programming is how to handle an unknown number of objects. By handling I mean referencing them, manipulating them etc. As for me, this would be when developing smaller games and programs.
Currently I am working on a score-keeping program, which should display the names of the players, their score as well and various other features. Furthermore, there should be two buttons that allow for adding and removing players from the score table which is what I'll be focusing on here. It might look something like this:
//A very limited version of my program
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class Application extends JFrame implements ActionListener{
//Fields, variables and components
Container mainCont = getContentPane(); //Main container, the window itself
private JPanel buttonPanel;
private JPanel namePanel;
private JButton addPlayerButton;
private JButton removePlayerButton;
//...
//Many more components
public Application(){
//Basic window initiation
setTitle("Score Keeper");
this.setSize(650, 700);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainCont.setBackground(Color.BLACK);
this.setContentPane(mainCont);
buttonPanel = new JPanel();
namePanel = new JPanel();
addPlayerButton = new JButton();
addPlayerButton.addActionListener(this);
buttonPanel.add(addPlayerButton);
removePlayerButton = new JButton();
removePlayerButton.addActionListener(this);
buttonPanel.add(removePlayerButton);
this.add(buttonPanel);
this.add(namePanel);
this.setVisible(true);
//Other code omitted for now
//Includes other graphic components, layout managers etc.
}
/*
* Action-Listener.
* Performs an event on an action.
*/
#Override
public void actionPerformed(ActionEvent event){
if(event.getSource() == addPlayerButton){
Application.Player newPlayer = this.new Player(); //Creates a new object, i.e. a new player
//See below for Player class
}
if(event.getSource() == removePlayerButton){
//******
// This is where the problem lies
}
}
//I use a nested class to create a new player
public class Player{
//Components etc.
private String name;
private JLabel nameLabel;
public Player(){
name = getName();
nameLabel = new JLabel(name);
namePanel.add(nameLabel);
}
public String getName(){
//This basically gets input from the user to assign a name to the new player
//Code omitted for now
}
}
}
So far all is good. This program basically only has two buttons, where the addPlayerButton adds a player object, which has a name that is displayed on the screen. Every time this button is pressed a new player is added to the screen. And this can be done an indefinite number of times.
The problem comes when we want to remove a player. How can we do that? We can't reference it by name, as all player objects are practically anonymous.
The alternative, of course, would be to pre-define a fixed amount of player objects:
class Application extends JFrame implements ActionListener{
//Fields, variables and components
Container mainCont = getContentPane(); //Main container, the window itself
private JPanel buttonPanel;
private JPanel namePanel;
private JButton addPlayerButton;
private JButton removePlayerButton;
private Player player1;
private Player player2;
private Player player3;
//...
//Etc.
Then we would be able to directly address each player object, but this is simply too impractical. We cannot add more players than the pre-defined amount, and if we want fewer players we have a bunch of player objects that are never used. Furthermore, we would have to hardcode every initiation of every player - every nameLabel would have to be manually added to the screen etc.
Please share your knowledge on how you handle this kind of problem, of how you deal with an unknown number of objects.
Thanks for taking the time and for the help!
P.S. I'm still pretty new to this forum. Please let me know if there is anything with this question I can change etc. I did my research and found no previous question that tackled this, but if there is one I missed feel free to let me know!
EDIT 1: Okay. There were a lot of great answers. I chose the one using hashmaps as the right solution, since I consider this the best solution for the premises I provided. The way I actually solved my problem is that I added, to the player object, a JButton that removes the player object it is stored in. I also scrapped the concept of using a nested class for the player and just implemented it in a separate class.
What I've learnt overall, though, is that when handling objects and you don't know the amount of objects it is generally best to store them in a collection of some sort. My preference is the Hashmap, as it provides an easy way of accessing the object based on one of its properties, like a String name or similar.
You can use a Map/Hashmap and each time you create a player, add them to the map.
You also have to change from directly drawing the player on the screen, probably to drawing all the players in the Map, that way when a player gets removed from the Map it would no longer be drawn.
You would do something like this:
Map<String, Player> map = new HashMap<>();
map.put(player.Name, player);
And then you would draw everything in that hashmap. To remove you just need to provide the name of the player to remove.
map.remove(player.Name);
And of course then you would change your code a bit to render everything inside the map, I believe you need a way to know which player is to be removed, you might want to add a text field to input the name of the player to be removed.
What you could do if you want to delete a Player based on it's name is the following:
// Create a list of players, which you can define globally
ArrayList<Player> players = new ArrayList<>();
// The name of the player to find
String name = "theNameOfThePlayerToFind";
// Loop through the players and remove the player with the given name
for (Player player : players) {
if (player.getName().equals(name)) {
players.remove(player);
}
}
You can also add new players to lists easily:
players.add(new Player());
I would #Katada Freije method of using a HashMap. Just to elaborate a little, you basically have a collection of Players with their names as a key. You then use the key to remove the Player.
But I might also avoid this as some scenarios have multiple Players with the same name. I'd go with a List<Player>. This way the Player will be defined by the index rather than the name. You'd then use the index to remove the player with some in inbuilt methods.
Let us assume that you are using a JList to display the current players. Java's Swing separates the model (where the objects that are displayed are actually stored) and the view and control (the JList that displays them). This design is called MVC, and is very common.
We have different ways of storing the actual Player objects. Which to choose depends on how you plan to manipulate your players. The most straightforward is to use an array, but that only works if you will never have too many players:
Player[] players = new Player[MAX_PLAYERS](); // define MAX_PLAYERS somewhere
int currentPlayers = 0; // always < MAX_PLAYERS
To expose this to the JList, you would use a custom adapter model as follows (in an inner class with access to the players array):
private final class PlayerListModel extends AbstractListModel<Player> {
#Override
Player getElementAt(int position) { return players[position]; }
#Override
int getSize() { return currentPlayers; }
}
You can then pass this to the JList at construction time:
private PlayerListModel playerListModel = new PlayerListModel();
private JList playersListView = new JList(playerListModel);
Now, to remove a player by name, you would first update the model, and then cause the view to be refreshed:
private void removePlayerByName(String name) {
int toRemove = -1;
for (int i=0; i<currentPlayers; i++) {
Player p = players[i];
if (p.getName().equals(name)) {
toRemove = i;
break;
}
}
if (toRemove != -1) {
// update model
currentPlayers --;
players[toRemove] = players[currentPlayers];
// update views
playerListModel.fireContentsChanged(this, toRemove, currentPlayers);
}
}
Instead of a players array, it would be much easier and safer to use an ArrayList<Player> players. However, if you are naming your variables player1, player2 and so on, I think that you should begin with arrays. If you want to have much faster lookup of players, then a TreeMap<String, Player> would keep them sorted by name and easy to find. You would, in both cases, have to update the model and the removePlayerByName function accordingly. For example, if using the TreeMap, it would be much shorter (and faster):
private void removePlayerByName(String name) {
if (players.containsKey(name)) {
players.remove(name);
playerListModel.fireContentsChanged(this, 0, currentPlayers);
}
}
On the other hand, it is far more common to find interfaces where you click on the player that you want to remove to select it, and then click the remove button to actually do so. You can know which player was selected with this code:
Player selected = playersListView.getSelectedValue();
If there is a selection (selected != null) you could either call removePlayerByName(selected.getName()), or even better, code a removePlayer(Player p) that did not rely on names, but on a (currently missing) implementation of Player.equals(Player another).
I'm trying to reproduce a piechart/ringplot produced by a different tool. Everything is fine except for the legend. I need to put values inside the graphical part of each LegendItem:
Image
I think that I have the outlines of a solution but would like you experienced jfreecharters to ack that I'm on the right track. I'm wondering if this couldn't be done in an easier way?
One way could be to subclass LegendTitle and override createLegendItemBlock(..). Copy most of the content but instead of contructing a LegendGraphic, construct a subclassed LegendGraphic which knows how to handle text inside the shape.
Any comments would be very welcome.
I implemented the solution outlined in the question and it works fine. If anyone else should come across the problem, here's the subclassed LegendGraphic which handles text. The subclassed LegendTitle and overridden createLegendItemBlock(..) method are straightforward.
class CustomLegendGraphic extends LegendGraphic {
String label;
public CustomLegendGraphic(Shape shape, Paint fillPaint, String label) {
super(shape, fillPaint);
this.label = label;
}
#Override
public Object draw(Graphics2D g2, Rectangle2D area, Object params) {
Object result = super.draw(g2, area, params);
area = trimMargin(area);
Point2D location = RectangleAnchor.coordinates(area, this.getShapeLocation());
TextBlock textBlock = TextUtilities.createTextBlock(label, getItemFont(), Color.white);
textBlock.draw(g2, (float)location.getX(), (float)location.getY(), TextBlockAnchor.CENTER);
return result;
}
}
I have a Cell Table that I am using to output some search results. The cell table uses a list data provider to update info. I want to separate different sections so I am attempting to add a custom row in between different sections that has one cell that spans all of the columns. I am extending AbstractCellTableBuilder to do this, but my issue comes when I use TableRowBuilder and startRow(), calling startRow() returns a null pointer exception, to AbstractCellTableBuilder.java:243, which refers to tbody. So this is leading me to believe that my cell table is not getting passed into AbstractCellTableBuilder properly. My understanding of gwt and java is pretty basic, so I might just not be understanding how exactly this is supposed to work, and the showcase example is pretty complicated for me to understand. If anyone can tell where I'm messing up or has any simpler examples of this that might help me I would appreciate it!
I had found a similar answer and tried to implement it, and that is how I came up with what I have, but it answer wasn't quite detailed enough for me to fully understand how it works. Here is what I referenced:
Building a custom row on demand with GWT CellTableBuilder
EDITED:
Basic format of how I add normal rows to the cell table
searchProvider = new ListDataProvider<SearchColumn>();
cellTable_2 = new CellTable<SearchColumn>();
//Add columns to the cellTable
searchProvider.addDataDisplay(cellTable_2);
//What I call when adding a row to the cellTable using the ListDataProvider
searchProvider.getList().add(new SearchColumn("",label,"","","","","","",""));
Adding the CustomCellTableBuilder to the cell table:
//Passing the CustomCellTableBuilder to the cell table
CustomCellTableBuilder buildRow = new CustomCellTableBuilder();
cellTable_2.setTableBuilder(buildRow);
The CustomCellTableBuilder for adding custom rows:
public class CustomCellTableBuilder extends AbstractCellTableBuilder<SearchColumn>{
public CustomCellTableBuilder() {
super(cellTable_2);
}
#Override
protected void buildRowImpl(SearchColumn rowValue, int absRowIndex){
//building main rows logic
if (labelrow == 1){
System.out.println("Going to build extra row if");
buildExtraRow(absRowIndex, rowValue);
}
else {
System.out.println("Getting into normal buildRow");
buildRow(rowValue,absRowIndex);
}
}
private void buildExtraRow(int absRowIndex, SearchColumn rowValue){
start(true);
TableRowBuilder row = startRow();
TableCellBuilder td = row.startTD().colSpan(getColumns().size());
td.text("Testing this out").endTD();
row.endTR();
}}
I think you should call start(true) before calling startRow() because tbody is initialized to null. Start() call will initialize tbody to HtmlBuilderFactory.get().createTBodyBuilder().
The source doesn't lie.
Just like that:
private void buildExtraRow(int absRowIndex, SearchColumn rowValue) {
start(true); // true makes builder to rebuild all rows
TableRowBuilder row = startRow();
// whatever
}
I'm using JXTable and I know how to do this based on DefaultRenderers for JTable, but I want to know how to do it in a way that's JXTable-friendly based on HighlighterPipeline.
I have a list of objects displayed in a table, and each row represents one object. I would like to color the rows displaying objects of a certain type a different color.
It looks like I should be using ColorHighlighter. But I can't find examples for this, other than the simple highlighters like "color every other row" or some such thing.
I need the row number since there's no such thing as a "row object" in the JTable/TableModel paradigm, but if I can do that, I can easily test a predicate and return true/false to tell the highlighter to kick in or not.
Can someone help me figure out the right direction to get this to work?
never mind, I figured it out. It was just hard to figure out the way to use ComponentAdapter propertly.
JXTable table = ...
final List<Item> itemList = ...
final HighlightPredicate myPredicate = new HighlightPredicate() {
#Override
public boolean isHighlighted(
Component renderer,
ComponentAdapter adapter) {
Item item = itemList.get(adapter.row);
return testItem(item);
}
public boolean testItem(Item item) { ... }
}
ColorHighlighter highlighter = new ColorHighlighter(
myPredicate,
Color.RED, // background color
null); // no change in foreground color
table.addHighlighter(highlighter);
Im trying to create a scrollPanel that holds a list of checkbox item. My main problem is constructing a CellList with CheckboxCell. Here is a snippet of whats causing the compile time error.
CheckboxCell testCheckBox = new CheckboxCell();
CellList<String> cellList = new CellList<String>(testCheckBox);
Error Message: The constructor CellList(CheckboxCell) is undefined.
If this is the wrong constructor, what is the correct way?
Try changing the type of CellList to Boolean.
CheckboxCell testCheckBox = new CheckboxCell();
CellList<Boolean> cellList = new CellList<Boolean>(testCheckBox);
update:
More examples on various cells (this is combined checkbox + picture, but you might want to replace picture with text):
http://gwt.google.com/samples/Showcase/Showcase.html#!CwCellTree
It's little trickier, but this showcase contains also sources so might want to dive into them.
PS: Lazier solution is not to use Cell Widgets and make own (extends Composite) combo/label and place it in say FlexTable :)
You can try something like that. You are going to need some extra native code to handle the "check" event.
public class StyleCell extends AbstractCell<Style> {
#Override
public void render(Context context, Style row, SafeHtmlBuilder sb) {
if (row == null) {
return;
}
sb.appendHtmlConstant("<INPUT TYPE=CHECKBOX NAME='property'>" + row.getProperty() + "</INPUT>");
}
}
StyleCell styleCell = new StyleCell();
CellList<Style> styleList = new CellList<Style>(styleCell);