Force an actor to obey the width set in table.add(actor).width() - libgdx

I am setting the width of actor in table.add(actor).width(width). The padding is set to 1% of screen width. This is the result I get:
As you can see, spacing between actors is way beyond 1% . I tried using fill() methods but it didn't work. I also tried setFillParent(true) on the actor, no success. What is going on here? This is the complete code. The only spacing between actors should be the one I set with padding. How do I achieve this?
private void createScrollPane(){
texture=new Texture("badlogic.jpg");
ImageButton.ImageButtonStyle fibs=new ImageButton.ImageButtonStyle();
fibs.imageUp=new TextureRegionDrawable(new TextureRegion(texture));
button1= new ImageButton(fibs);
button2= new ImageButton(fibs);
button3= new ImageButton(fibs);
button1.setPosition(0, 0);
button2.setPosition(0, 0);
button3.setPosition(0, 0);
scrollTable=new Table();
scrollTable.setBounds(Gdx.graphics.getWidth()*0.03f,0,Gdx.graphics.getWidth()*0.94f, Gdx.graphics.getHeight());
scrollTable.setPosition(Gdx.graphics.getWidth() * 0.03f, 50);
scrollTable.add(button1).width(Gdx.graphics.getWidth() * 0.3f).padLeft(Gdx.graphics.getWidth() * 0.01f).fill();
scrollTable.add(button2).width(Gdx.graphics.getWidth() * 0.3f).padLeft(Gdx.graphics.getWidth() * 0.01f).padRight(Gdx.graphics.getWidth() * 0.01f).fillX();
scrollTable.add(button3).width(Gdx.graphics.getWidth() * 0.3f).padRight(Gdx.graphics.getWidth() * 0.01f).fill();
stage.addActor(scrollTable);
}

ImageButton is a Button with an Image on top of it. If you just want a button then use the Button class and set the up drawable to the drawable you want it to be. Note that you can enable debug drawing of the stage or table to visualize what is going on.

Your function calls are affecting the Table's cells, not the actors in the cells.
Call scrollTable.setDebug(true) to see the cells, padding, etc. You'll be happy to find your function calls are working, just on the cells rather than their contents.
The next step is to build a composite layout with widgets which allow you to expand the buttons but maintain them in a horizontal alignment. You might be able to accomplish that with just a table if you battle the cells hard enough, I'm not sure.
What I did was to use a Table, then add a HorizontalGroup. The HorizontalGroup goes within a cell on the Table. Inside the HorizontalGroup I add my buttons. Laying out the buttons the way I want within the HorizontalGroup is far easier than doing it via the Table.
For an ImageButton you can explicitly set the minHeight and minWidth of the style, which will forcibly scale the attached Image.

Related

LibGDX - Get width of label cell in ImageTextButton

I have ImageTextButtons within a container Table. I would like to dynamically change the width of this table and have the ImageTextButtons respond in a particular manner. What I would like them to do is fade in the label text depending on the percentage of the text shown.
I believe I am dynamically setting the table width and contents correctly. As per the LibGDX documents we should not explicitly set the widgets dimensions, but the table (container) cell dimensions. So for testing, I have a simple clickListener on what of the buttons like this;
button.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
super.clicked(event, x, y);
float max = container.getCell(button).getMaxWidth();
container.getCell(button).width(max*0.9f);
container.invalidate();
}
});
This works fine, I click it and the cell (and the widget) shrink 90% each time.
For the next step, I thought it would be as simple as this, in my custom ImageTextButton's draw() method;
glyphWidth = getLabel().getGlyphLayout().width;
labelCellWidth = getLabelCell().getMinWidth(); ///<--problem here
float glyphOpacityMultiplier = MathUtils.clamp(labelCellWidth/glyphWidth, 0f, 1f);
origLabelColor = getLabel().getColor().cpy();
newLabelColor = origLabelColor.cpy();
newLabelColor = new Color(newLabelColor.r, newLabelColor.g, newLabelColor.b, newLabelColor.a*glyphOpacityMultiplier);
getLabel().setColor(newLabelColor);
super.draw(batch, parentAlpha);
getLabel().setColor(origLabelColor);
This all works, except for the fact I can't find any method to give me with actual width of the Cell that contains the label. Since the ImageTextButton itself is also a Table, I tried to do button.invalidate() in the ClickListener too but it didn't help. These are the methods I have tried so far;
getLabelCell().getMinWidth();
getLabelCell().getMaxWidth();
getLabelCell().getPrefWidth();
getLabelCell().getActorWidth();
getLabelCell().getSpaceLeft();
getLabelCell().getSpaceRight();
None of them seem to update and give me the correct size, however I know something is working somewhere because I turned on "setClip(true)" on the ImageTextButton, and the label text is successfully being clipped within the boundaries of the NinePatch background when it is resized. So how do I get the correct size?
Any help is greatly appreciated!
Oops.. solved it. I thought the cell containing the label would be offset and sized by the NinePatch background but its not, it is full size but has padding. Therefore the answer is;
labelCellWidth = getWidth()-getPadLeft()-getPadRight();

Added TableView to Sprite is not visible and all other Sprites are visible

I inherited Sprite and I want to put inside TableView but when I add inherited Sprite to scene table is not visible but all others sprites added to inherited sprite are visible ( I checked it creates cells, position and z index are set right, when I add TableView directly to Scene it is visible).
I'm able to add a TableView to a Sprite in Cocos2d-x v3.6, but it's a little hard to say exactly why yours isn't showing up. Here are some things to check:
Have you added the TableView as a child to the Sprite via addChild?
When you add the TableView to the Sprite, is your DataSource set properly? (This seems to be the case given your question).
Are there positioning issues when you add it to the Sprite due to the anchor position(s) of your Sprite and it's parent(s)? It could be the TableView with incorrect positioning, or it could be the TableViewCells themselves. Remember that when you add a child to some Node, its anchor point is Vec2(0.5, 0.5).
You're not forced to override cocos2d::Size cellSizeForTable(cocos2d::extension::TableView *table), and if you don't have cell heights, the cells might not show up.
Try "dumbing down" any logistics you have and follow the code in TableViewTestScene.cpp, which is part of the cpp-tests. (cocos-directory/tests/cpp-tests/Classes/ExtensionsTest/TableViewTest)
Last resort: Try doing something silly like giving your table and cells a large height and width of 500-1000 pixels each. Give them an absolute position somewhere in your Sprite. Give each of them a Label that says "Hello, World!" and see if they show up.
It might be helpful to see your applicable code, too.
A very late edit: I realized today that it seems as though Layer objects (and thus TableViews) always have an Anchor Point of Vec2::ANCHOR_BOTTOM_LEFT. Could this be your issue?

How to align table in scrollPane top?

I' am making achievements screen in my libgdx game. I want to align my table in scrollPane to top, now it is centred vertically and horizontally and I don't know why. Using .top() method when I've tried to create new row didn't worked.
stage = new Stage();
Gdx.input.setInputProcessor(stage);
outerTable = new Table();
innerTable = new Table();
innerTable.setFillParent(true);
for(int i=0;i<score_bound; i++){
if(i<score_state){
innerTable.row().width(achie_width).height(achie_height).top();
innerTable.add(new Image(ltm.assets.score_textures[i]));
}else{
innerTable.row().width(achie_width).height(achie_height).top();
innerTable.stack(new Image(ltm.assets.score_textures[i]),new Image(ltm.assets.kurtyna));
}
}
for(int i=0;i<letin_bound; i++){
if(i<letin_state){
innerTable.row().width(achie_width).height(achie_height).top();
innerTable.add(new Image(ltm.assets.letin_textures[i]));
}else{
innerTable.row().width(achie_width).height(achie_height).top();
innerTable.stack(new Image(ltm.assets.letin_textures[i]),new Image(ltm.assets.kurtyna));
}
}
scrollPane = new ScrollPane(innerTable);
outerTable.setPosition(0, 0);
outerTable.setSize(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
outerTable.debug();
outerTable.add(scrollPane).fill().expand();
stage.addActor(outerTable);
I run into the same issue today and came across here, so I might as well post an answer here in case somebody is still looking for an answer.
#peterSweter said top() does not work, what #Rara suggested is the same as calling top.
The only way to achieve something that looks like an align to the top - which only is relevant if the innerTable is smaller - is to increase the size by adding empty elements around it, so the table you pass to the ScrollPane has at least the same size as the scrollPane.
I just wrapped yet another Table around my innerTable reference.
(658 is the fixed height I use for my ScrollPane)
Table spacingTable = new Table();
spacingTable.setHeight(Math.max(innerTable.getHeight(), 658));
spacingTable.add(innerTable);
if (innerTable.getHeight() < 658) {
spacingTable.row();
spacingTable.add().expandY();
}
ScrollPane scroll = new ScrollPane(spacingTable, skin);
In order to achieve what you want, you can wrap your table inside another table and use that table for ScrollPane. Note that when adding your table to container table, you'll need to add some growable, empty cell at the bottom and right side in order to "push" it to top-left (although I believe you can also simply use containerTable.add(myTable).top().left() - but haven't tested it really).
This of course is a much better solution than second's solution, which uses hardcoded height. The thing is, you will usually want to add scroll pane as growable (.grow()), so fixed height/width is useless.

Is JPanel supposed to be added to a JFrame?

I have this code which I don't understand:
JFrame jframe = new JFrame("Risultati protocolli cercati");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel body = new JPanel();
Container c = jframe.getContentPane();
body.setSize(100, 100);
body.setLayout(new GridLayout(1000, 1));
for (int i = 0; i < 1000; i++)
body.add(new JLabel("JLabel " + i));
JScrollPane jsp = new JScrollPane(body);
c.add(jsp);
jframe.setSize(100, 100);
//jframe.add(body);
jframe.setVisible(true);
If I leave the penultimate line commented then everything appears, both labels and scroll. Instead if I uncomment that line, I see nothing. Only the JFrame. Why does it happens? For the main window of my program I had to perform jframe.add(body)...
Instead if I uncomment that line, I see nothing. Why does it happens?
The below line
jframe.add(body);
internally calls
jframe.getContentPane().add(body);
JFrame by default uses BorderLayout and add(component) method directly add it in the center section, if you add again then last one is replaced with latest one.
You can use overloaded add() method of JFrame to add it in another section east, west, north and south as shown in below snapshot:
for e.g.:
frame.add(comp,BorderLayout.NORTH); // add in north section
frame.add(comp,BorderLayout.WEST); // add in west section
You can use other Layout Managers as well as per the design or your application:
It's worth reading How to Use BorderLayout
One more suggestion:
Use frame.pack() instead of frame.setSize() that fits the components as per component's preferred size.
Interesting problem caused by the layout managers.
A component can only have a single parent. First you add the "body" to the scrollpane but then the "body" gets removed from the scrollpane when you add it to the content pane of the frame (for the reasons mentioned by #braj). Not a big deal as it just means you won't see any scrollbars.
Since the component is directly added to the content pane you should still see the labels however they do not display and this is the confusing part. Change your code to use "100" for the GridLayout and the number of components you create in the loop. When the frame first displays the panel will be empty. Now, increase the height of the frame and you will see the components appear. What is happening is that you are trying to paint too many components in a small area and because of rounding issues the height of every component becomes 0, so there is nothing to paint. When you increase the height to at least 100 pixels every component can now be 1 pixel high so you get garbage.
The only solution is to keep the "body" panel in the scrollpane so that all components will be displayed at their preferred size. Then you can scroll through all the components as required.
A tip for when using a GridLayou. You can use:
body.setLayout(new GridLayout(0, 1));
Then means the grid will have unlimited rows and a single column.

Width and Height of JPanel inside Container of JFrame is 0, why?

I am having a simple problem I guess, that u should know how to solve..
I am trying to do this:
I have a JFrame.
Then I create a JPanel and set his layout to GridLayout(5,5)
Finnaly I add this JPanel to the Container of my JFrame.
When I try to get the width of my panel it shouldnt give me 0 right?
I do this: System.out.println(mypanel.getSize().getWidth()); and it says that is zero :c
why ??
I wanna know the size so I can divide per 5 and know how much to paint for each label, this will be a grid of labels..
Thanks alot in advance...
public janela(){
window = new JFrame("teste");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(300,300);
contentor = window.getContentPane();
interior = new JPanel();
interior.setLayout(new GridLayout(5,5));
contentor.add(interior);
System.out.println(interior.getSize().getWidth()); //it says 0 ?!?! why??
}
thanks alot in advance guys!!!!
Panels are sized based on their layout. specifically when they are shown and doLayout() is called for you. doLayout() figures out what the appropriate size for your panel is based on the contents of the panel, and the layout manager in force. Since your panel has nothing in it, the appropriate size is 0, 0.
If you will never have anything in the panel, and want to circumvent this (0, 0) size, you can override getPreferredSize() of the panel to return a size that you want the panel to respect for layout.