In libgdx I have a ScrollPane in my application and I can't figure out how to get it to scroll without extra space at the top. Currently, there is a massive space at the top of the pane, and when I scroll down, the text (high scores) slowly fill up the space.
BEFORE SCROLLING:
AFTER SCROLLING:
Is it possible to start without the space (so the pane is completely filled) and when I scroll, I can scroll through the high scores without them moving upwards?
I noticed I can accomplish this by removing the following line.
table.setTransform(true);
But if I do this, I cannot scale or set origin on the table so the text appears too large.
Below is my scrollpane creation method:
private void createScrollPane(ArrayList<String> scrollPaneScores) {
scrollPaneViewport = new FitViewport(800, 480);
stage = new Stage(scrollPaneViewport);
Skin skin = new Skin(Gdx.files.internal("skin/uiskin.json"));
Table scrollableTable = new Table();
scrollableTable.setFillParent(true);
stage.addActor(scrollableTable);
Table table = new Table();
for (String score : scrollPaneScores) {
table.add(new TextButton(score, skin)).row();
}
table.pack();
table.setTransform(true);
//table.setTransform(true); //clipping enabled ... this setting makes scrolling not occur in uniform fashion
table.setOrigin(400, 0);
table.setScale(0.75f);
final ScrollPane scroll = new ScrollPane(table, skin);
//scrollableTable.add(scroll).expand().fill();
scrollableTable.add(scroll).maxHeight(300);
//stage.setDebugAll(true);
//When stage is created, set input processor to be a multiplexer to look at both screen and stage controls
inputMultiplexer.addProcessor(inputProcessorScreen);
inputMultiplexer.addProcessor(stage);
Gdx.input.setInputProcessor(inputMultiplexer);
scrollPaneCreated = true;
}
Remove the setFillParent line. It is an old problem with tables inside scrollpanes.
Try removing the scrollableTable.setFillParent(true);
Related
My layout looks like that:
Panel is a VBox and Content is a HBox. Both are contained in an HBox.
I need to make panel fixed size, so right now I'm doing it like that:
VBox panel = new VBox();
double fixedWidth = Screen.getPrimary().getBounds().getWidth() / 10;
panel.setMinWidth(fixedWidth);
panel.setMaxHeight(fixedWidth);
... but what if user's screen resolution change? That code doesn't handle that and I'm afraid the Screen class doesn't provide any type of callback.
Your title and most of your question indicate you want panel to use 10% of the screen’s width, and content to use 90% of the screen’s width. However, you also use the term “fixed width” which is something different; namely, that panel would have the same width at all times, regardless of screen size.
I shall assume you meant the first concept: that you want panel to use 10% of the width and content to use 90% of the width.
Instead of an HBox, use a GridPane. Set its column constraints to 10% and 90%.
ColumnConstraints panelWidth = new ColumnConstraints();
panelWidth.setPercentWidth(10);
panelWidth.setFillWidth(true);
ColumnConstraints contentWidth = new ColumnConstraints();
contentWidth.setPercentWidth(90);
contentWidth.setFillWidth(true);
RowConstraints rowConstraints = new RowConstraints();
rowConstraints.setFillHeight(true);
rowConstraints.setVgrow(Priority.ALWAYS);
GridPane pane = new GridPane();
pane.addRow(0, panel, content);
pane.getColumnConstraints().setAll(panelWidth, contentWidth);
pane.getRowConstraints().setAll(rowConstraints);
Based on your current solution, you seem to be giving 10% size to your panel which means 90% is the content panel. You can directly bind screen size to your scene object and initialize your scene with screen size. It will make the whole application reactive to the screen resolution changes. Here is a sample from my code on how I do it:
final Scene scene = new Scene(root,width,height);
logger.debug("Scene Created");
stage.centerOnScreen();
stage.setScene(scene);
final ChangeListener<Number> listener = new ChangeListener<Number>()
{
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, final Number newValue)
{
logger.debug("Scene Resize Started");
Scale scale = new Scale();
scale.xProperty().bind(scene.widthProperty().divide(width));
scale.yProperty().bind(scene.heightProperty().divide(height));
scale.setPivotX(0); scale.setPivotY(0);
root.getTransforms().clear();
root.getTransforms().addAll(scale);
logger.debug("Scene Resize Ended");
}
};
scene.widthProperty().addListener(listener);
scene.heightProperty().addListener(listener);
This takes care of resize as well as resolution changes. The width and height variable in the start are width and height captured from Screen of the user.
What I'm trying to do is add a label to follow a slider knob and display the knob's value. I currently have a vertical slider and a label stacked inside a table cell. I'm able to position the label to where the knob is and update it's text correctly but am having a problem while moving the knob.
When I move the knob I can make the label follow it as long as I don't update the text. But if I update the text then the label re-centers itself in the cell till the knob has stopped moving at which point it places itself on the knob.
How do I make it so that the label doesn't reposition while it's updating text?
Here's some sample code of what I have going on:
public class OptionsWindow implements Screen {
private Stage stage;
private Table table;
private Slider slider;
private Label label;
private Skin textSkin = new Skin(Gdx.files.internal("skins/skin.json"),
new TextureAtlas(Gdx.files.internal("skins/text.pack")));
private Skin sliderSkin = new Skin(Gdx.files.internal("skins/skin.json"),
new TextureAtlas(Gdx.files.internal("skins/text.pack")));
private min = 1, max = 2;
#Override
public void show() {
stage = new Stage();
table = new Table();
slider = new Slider(min, max, 0.001f, true, sliderSkin);
label = new Label(""), textSkin);
table.stack(label, slider).height(1000);
table.setFillParent(true);
stage.addActor(table);
Gdx.input.setInputProcessor(stage);
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
label.setY(slider.getValue() - min);
label.setText(slider.getValue());
stage.act();
stage.draw();
}
}
I've done a lot of searching for an answer to this question but have yielded no results. I have also tried placing the label in a container and moving the container while changing the label text, but the same result happens. I'm sure somebody had done this before. It seems like something people would want. Please, any help is welcome.
Never done it before, I always show the amount in a label next to or above the slider to give feedback. But the result you are after gives a nice touch. Did you try adding a ChangeListener to your slider? Everytime the slider changes this would be called. So if you insert the new position and text in there it should be updating correctly.
//Slider has to be "final" for the listener.
final Slider slider = new Slider(0, 10, 1, true, skin);
slider.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
label.setY(slider.getValue() - min);
label.setText(slider.getValue());
}
});
This does not need to be in your render method. It's a listener so whenever something happens the listener listens for it will execute.
Ok, so I came up with a work around. It would seem that labels move back to their cell alignment position while updating text. to solve this I simply placed my label in a table with a row on either side like so:
Table subTable = new Table();
subTable.add().row();
subTable.add(label).row();
subTable.add();
Then in render I calculate new height values for the exterior cells and apply them:
float topH, botH;
// Calculate heights
topH = (1 - slider.getPercent()) * parentTable.getHeight();
botH = slider.getPercent() * parentTable.getHeight();
// Apply heights to exterior table cells
subTable.getCells().get(0).height(topH);
subTable.getCells().get(2).height(botH);
// Update label text
label.setText(slider.getValue());
This is just a simple form of what I have. You'll want to take into account the label height to get it to position correctly. Also if you want it to follow with the slider at the slider's set animateDuration, you'll want to use getVisualPercent() instead of getPercent(). However this causes issues when your finger flies out of the cell. For some reason the visual percent is linked to where the slider knob is when your finger leaves the cell, not where it ends up.
My work around for this was to just set the animateDuration to 0.0f and just use getPercent(). If I or someone comes up with a solution to the getVisualPercent() option, then that would be nice to have posted as well.
I've been working on some app's using libgdx & I can't figure out how to position a button via coords.
public void create() {
batch = game.getSpriteBatch();
background = new Texture("data/textures/menuScreen_small.png");
bubbleArray = new Array<Bubble>();
Gdx.input.setInputProcessor(stage);
for (int i = 0; i < 20; i++) {
bubbleArray.add(new Bubble(MathUtils.random(0,
Gdx.graphics.getWidth()), MathUtils.random(0,
Gdx.graphics.getHeight())));
}
table = new Table();
stage.addActor(table);
table.setSize(1280, 720);
table.setPosition(0, 0);
//table.left().top();
// table.debug();
//table.row().minHeight(55).maxHeight(55);
skin = new Skin(Gdx.files.internal("data/ui/uiskin.json"));
/*
* HomeScreen [Button 1]
*/
final TextButton camButton = new TextButton("Camera", skin);
//Add button
table.add(camButton);//.left().expandX().fillX();
camButton.setPosition(0, 0);
//Button Height
//table.row().minHeight(55).maxHeight(55);
//Button Width
//table.row().minWidth(55).maxWidth(55);
In the code above I am trying to position my textButton "camButton" at 0,0 on the screen.
when I start the program it's in the very center of the screen.
If anyone has some guides or tips let me know, I need to learn this stuff.
a small 'fix'
Not exactly a fix; but by removing the table in general solved this problem. By doing this I'm adding it to the stage instead of stage > table > button. Any comments to that?
If you just want to be able to fix buttons to absolute positions like 0,0 there is no need to add the items to a table, just add you button to the stage
TextButton button = new TextButton("Floating Button", skin);
button.setPosition(10, 10);
stage.addActor(button);
Edit
If you still want the controlled positioning that the table provides check out the guide for the table layout it has many good examples Table Layout
If you want to position the table
table.left().bottom();
To position items inside a table
table.add(button).expand().bottom().right();
I had your problem. My requirement for the whole screen or part of the screen was. I solved my problem using WidgetGroup layout.
actor.setPosition(100,200);
yourWidgetGroup.addActor(actor);
Hi I am trying to build a horizontal scrolling screen in my libgdx game but can only get it to scroll vertically rather than horizontally for some reason. Although the ScrollPane sounds simple I don't fully understand it for some reason but a scrolling credits example on here helped me a little.
I have a table and have added rows of text to it. The table matches the size of the screen and it also contains a ScrollPane called scroller which fills the size of the table. I am guessing since the rows of text don't fit on the screen and therefore the scroller, the scroller automatically allows vertically scrolling in the credits example? However when I change the text to one long line of text rather than new lines the scroller doesn't allow me to scroll horizontally to view all the text why is that? Surely the text is going outside the scroller width?
scrollTable = new Table(); //create table
scrollTable.add(text); //add a long line of text bigger than screen
scrollTable.row();
scrollTable.add(text2);
scrollTable.row();
scrollTable.add(text3);
scroller = new ScrollPane(scrollTable); //create the ScrollPane
Table table = new Table();
table.setFillParent(true);
table.add(scroller).fill().expand();
//scroller.setWidth(500);
//scroller.setScrollingDisabled(false, true);
stage.addActor(table);
private static final String reallyLongString =
"This is a really long string that has lots of lines and repeats itself over and over again This is a really long string that has" +
" lots of lines and repeats itself over and over again This is a really long string that has lots of lines and repeats itself over and over"+
" again This is a really long string that has lots of lines and repeats itself over and over again"+
" This is a really long string that has lots of lines and repeats itself over and over again This is a really long string that has lots"+
" of lines and repeats itself over and over again";
//This is my long string of text.
Try this:
Table table = new Table();
ScrollPane scroll = new ScrollPane(table);
I'm making a lobby in a multi-player game, which may have any number of players displayed in a table. I have the following code:
camera = new OrthographicCamera(WIDTH,HEIGHT);
camera.position.set(WIDTH/2,HEIGHT/2, 0);
camera.update();
stage = new Stage();
Gdx.input.setInputProcessor(stage);
stage.setCamera(camera);
stage.setViewport(WIDTH,HEIGHT,false);
ScrollPaneStyle paneStyle = new ScrollPaneStyle();
paneStyle.background = new TextureRegionDrawable(WizardsDuel.atlas.findRegion("cavebg"));
paneStyle.vScrollKnob = new TextureRegionDrawable(WizardsDuel.atlas.findRegion("GUI/slidernob"));
paneStyle.hScroll = paneStyle.hScrollKnob = paneStyle.vScroll = paneStyle.vScrollKnob;
Table container = new Table();
table = new Table();
ScrollPane pane = new ScrollPane(table,paneStyle);
container.add(pane).width(WIDTH).height(HEIGHT);
container.row();
container.setBounds(0,0,WIDTH,HEIGHT);
stage.addActor(container);
font = new BitmapFont();
color = new Color(0,0,0,1);
style = new TextButtonStyle();
style.font = font;
style.up = new TextureRegionDrawable(WizardsDuel.atlas.findRegion("GUI/guibg"));
style.fontColor = color;
handler = new ChangeHandler();
ArrayList<User> users = FirebaseManager.lobbyUsers;
for(int i = 0; i < users.size() || i < 100; i++){
TextButton tmp = new TextButton("",style);
tmp.scale(2);
//tmp.setText(users.get(i).name);
tmp.setText(i+ " asdf");
tmp.addListener(handler);
table.add(tmp).width(WIDTH/4f);
if(i%2 == 1 && i > 0)
table.row();
}
Despite the manner in which the table clearly extends below the bottom of the screen(which should be the bottom of the scroll pane), there is no scroll bar, and clicking and dragging does nothing.
Screenshot:
maybe you forget to make stage act in render(), add something like:
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
stage.draw();
}
You do actually need two things. An outer Container and an inner Container. You do regularly use two Tables for this. So here is a small example how I use the scrollPane. Actually with no style but it should make it clear.
this.table = new Table();
this.container = new Table();
scroll = new ScrollPane(table);
container.add(scroll).width(500f).height(500f);
container.row();
The table is the table one where you do add the stuff that should be scrollable. The container is the outer box. So you can add for example a headline above your scrollbox. The outer box (container) does need a size. Else you will not have any scrollbars or such. And you do need the inner table.
Simple example for adding:
style = new LabelStyle(font, Color.WHITE);
label = new Label(null, style);
table.add(label);
table.row();
label.setAlignment(1); // align center
give it more lines that it can show and you'll have a scroll pane. Else there is no scrollbar or such.
All in one. You just missed the outer container i think. Add it and it should work. Don't forget to sett the sizes.
My problem was that is wasn't receiving input. My I shouldn't have set the input processor in the constructor, because, the previous screen was setting the processor to null when it was "hidden", so when I moved the line to LobbyScreen's show method it happened after the previous screen was hidden, and the input is set correctly.
after you init the scrollpane you should call this first
mScrollPane.layout();
2023 | KOTLIN
The element to be scrolled must be added to the stage or group before passing it to the ScrollPane
Create the necessary actor and add it to the stage or group
val actor = Actor()
[Stage/Group].addActor(actor)
Create a ScrollPane and place an actor in it
val scrollPane = ScrollPane(actor)
Set the position and dimensions for the actor and the ScrollPane
actor.setBounds(x,y,w,h) | scrollPane.setBounds(x,y,w,h)
PS. Vel_daN: Love what You DO 💚.