I created a slider inside of a table like shown in the following code example as I know that the minimum width of the background is used for the slider width:
public OptionScreen(MainClass game) {
super(game);
preference = new PreferencesHelper();
font = this.getDefaultFont(25);
this.table = new Table();
if (Config.DEBUG)
this.table.debug();
// add volumenlabel
LabelStyle style = new LabelStyle(font, Color.WHITE);
volumenLabel = new Label(Config.VOLUMEN_LABLE, style);
table.add(volumenLabel).colspan(2);
table.row();
// add slider
Skin skin = new Skin();
skin.add("sliderbackground",
this.game.manager.get("data/sliderbackground.png"));
skin.add("sliderknob", this.game.manager.get("data/sliderknob.png"));
SliderStyle sliderStyle = new SliderStyle();
sliderStyle.background = skin.getDrawable("sliderbackground");
sliderStyle.background.setMinWidth(600f);
sliderStyle.knob = skin.getDrawable("sliderknob");
volumenSlider = new Slider(0f, 1f, 0.1f, false, sliderStyle);
volumenSlider.setValue(preference.getVolumen()); // load current volumen
volumenSlider.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
volumeValue.setText(String.format("%.01f",
volumenSlider.getValue()));
// sett the preference
preference.setVolumen(volumenSlider.getValue());
}
});
// add volslider to stage
table.add(volumenSlider);
volumenLabel.invalidate();
// table
style = new LabelStyle(font, Color.WHITE);
// set current volumen
volumeValue = new Label(
String.format("%.01f", volumenSlider.getValue()), style);
volumenLabel.setAlignment(2);
table.add(volumeValue).width(50f);
table.row();
initBackButton();
// init table
table.setPosition(Config.VIRTUAL_VIEW_WIDTH / 2,
Config.VIRTUAL_VIEW_HEIGHT / 2 - Config.BLOCK_SIZE * 10);
// add a nice fadeIn to the whole table :)
table.setColor(0, 0, 0, 0f);
table.addAction(Actions.fadeIn(2f)); // alpha fade
table.addAction(Actions.moveTo(Config.VIRTUAL_VIEW_WIDTH / 2,
Config.VIRTUAL_VIEW_HEIGHT / 2, 2f)); // move to center of the
// screen
// add to stage
this.stage.addActor(table);
}
The slide is inside a table with no width set. I already took a look if the width is set and if the calculation for the prefWidth of the slider does uses the set 600f.
Math.max(style.knob == null ? 0 : style.knob.getMinWidth(), style.background.getMinWidth())
Is the calculation for the width of the slider inside the Sliderclass. If I calculate that and log it, it loggs the desired 600f.
Everything seems right to me but the slider is rendered way to small for the 600 I set.
The background and knobtextures are 24x24.
So I hope you guys can tell me what I am doing wrong.
The folution is, that it's inside an table so the width is defined by the table width attibut for the spec. col and row.
So the fix is pretty short:
table.add(volumenSlider).width(600).height(60);
And its 600width and 60 height.
The wiki got edited to be more clear about this:
UI widgets do not set their own size and position. Instead, the parent widget sets the size and position of each child. Widgets provide a minimum, preferred, and maximum size that the parent can use as hints. Some parent widgets, such as Table, can be given constraints on how to size and position the children. To give a widget a specific size in a layout, the widget's minimum, preferred, and maximum size are left alone and size constraints are set in the parent.
Layout at Wiki
speedSlider.getStyle().knob.setMinHeight(100)
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.
I added a progress bar to my stage, and it gets a default width as expected. However, I do want to change the width a bit, but for some reason LibGDX don't. I've tried setSize, setWidth, setMinWidth at the background of the progress bar and changing the texture. Nothing works. The only thing I can get to change size of, is the knob.
Here's the code:
background = new Texture("progress_bar_texture");
knob = new Texture("knob_texture");
ProgressBar.ProgressBarStyle pbs = new ProgressBar.ProgressBarStyle();
pbs.background = new TextureRegionDrawable(new TextureRegion(background));
pbs.knob = new TextureRegionDrawable(new TextureRegion(knob));
pbs.knobAfter = pbs.knob;
progressBar = new ProgressBar(0f, 80f, 1f, false, pbs);
progressBar.setWidth(400); // This doesn't change anything at all...
table.add(progressBar).right().colspan(1).expandX().padRight(40);
Anton, you can increase the width of the ProgressBar within the table using 1. .colspan(2) or 2.Table.setWidth(). If you want precise (pixel-perfect) control of the position and size of the ProgressBar, add it to a Group instead of Table - then the things you tried ( setSize, setWidth, setMinWidth at the background of the progress bar) will work.
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'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 💚.
I have a libgdx game I am working, and in this game, when you hit the "Help" screen, my Help_Manager class uses my "Room's" stage object to draw a label. The room's camera is 27 wide, and 18 tall. The stage uses the same camera, and set's it's viewport to the same WIDTH, and HEIGHT.
If I were to add a text button to the stage with bounds(4,4,1,1), the button draws correctly, but when I add a Label with bounds(0,0,16,4) the labels "S" alone takes up half the screen (shown above)(it's supposed to say "Swipe finger from ship to \"Fling\" ship."). No matter what I set the bounds width and height to, the label is still the same size. Changing the scale doesn't have an effect either. Changing the font-scale(of the label, not the font) does have an effect, but for some reason the text is all messed up:
Heres bits and peices of code:
Room.java:
Stage stage = new Stage();
camera = new OrthographicCamera(WIDTH,HEIGHT);
camera.position.set(WIDTH/2,HEIGHT/2,0);
camera.update();
stage.setCamera(camera);
stage.setViewport(WIDTH, HEIGHT, false);
public void resize(int width, int height){
ppux = width/WIDTH;
ppuy = height/HEIGHT;
stage.setViewport(Room.WIDTH,Room.HEIGHT,false);
}
public void render(float delta){
stage.act(delta);
stage.draw();
}
Help_Manager.java
BitmapFont font = new BitmapFont();
LabelStyle style = new LabelStyle();
Label text;
style.font = font;
text = new Label(instructions[0],style);
text.setText(instructions[stage]);
text.setBounds(0,0,16,4);
//text.setFontScale(0.1f);
room.stage.addActor(text);
So how do I get my label to cooperate? Thanks in advance for any help!
Well, I discovered that fonts by default use integers for positions. When using a small camera size and stage viewport, means that the letters need to be placed more acurately, and so I had to change the font.setUseIntegerPosistions(false); I also discovered, that when you set the bonds for a Label, this simply defines the space that can be used, but it is still being filled with the same font, and size of text. Your putting the same stuff in a bigger/smaller box. (This explains why the text moves up as you increase the height of your Label, your raising the top bound, and the text starts at the top). To actually change the size of the font youse text.setFontScale();