As title says, I have a VerticalGroup that I store bunch of Labels in. Now, it does align ALL of them to the left, kind of. The problem is that labels that are shorter than the largest label will be centered around the middle of the largest label, like so:
Here is the relevant code:
private ScrollPane chatScrollPane;
private VerticalGroup chatGroup;
...
chatGroup = new VerticalGroup();
chatScrollPane = new ScrollPane(chatGroup, game.getSkin());
stage.addActor(chatScrollPane);
... in another method that adds messages ...
String message = "a message";
Label messageLabel = new Label(message, game.getSkin());
messageLabel.setAlignment(Align.left);
chatGroup.left();
chatGroup.addActor(messageLabel);
Now, what I'm asking is how can I have EVERY message, regardless of length, be on the left (like the Welcome message in screenshot)?
Thanks in advance.
I actually found the solution after quite a bit of fiddling. Turns out I need to do chatGroup.columnAlign(Align.left); to fix the problem. Thanks anyway!
Related
I need to show three things in a row in a sort of table. The first column should have a fixed width of say 15% of the screen. The third one should be right aligned and take its preferred width. The second one should take all the remaining space (I'll need to add some spacing, but that's another story).
This happens in start:
final Container list = new Container(BoxLayout.y());
list.setScrollableY(true);
final String[][] lines = {
{"19", "Some text", "123,00"},
{"20", "Some very very very very looong text", "1,00"},
};
for(final String[] line : lines) list.add(createContainer(line));
form.add(list);
The container is rather trivial:
private Container createContainer(String[] line) {
final TableLayout tableLayout = new TableLayout(1, 3);
tableLayout.setGrowHorizontally(true);
final Container result = new Container(tableLayout);
{
final Label l = new Label(line[0]);
l.getAllStyles().setFgColor(0x0000FF);
result.add(tableLayout.createConstraint().widthPercentage(15), l);
}
{
final Label l = new Label(emptyToSpace(line[1]));
l.getAllStyles().setFont(Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM));
result.add(tableLayout.createConstraint().widthPercentage(-2), l);
}
{
final Label l = new Label(line[2]);
l.getAllStyles().setFont(Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_LARGE));
l.getAllStyles().setFgColor(0x00FF00);
result.add(tableLayout.createConstraint().widthPercentage(-1).horizontalAlign(Component.RIGHT), l);
}
return result;
}
According to the javadoc, -1 means preferred size and -2 means "remaining space". It sort of works, but there seem to be a miscalculation.
The problem happens in the simulator, no matter what device I choose. I may be doing it all wrong, as I'm new to codenameone layouts.
The -2 flag is mostly optimized for the last column so this looks like a bug but might be hard to workaround. I don't see a need to use table layout here since you don't use one table which would provide alignment between the rows.
A simpler approach would be border layout e.g.:
Container c = BorderLayout.centerEastWest(new Label(emptyToSpace(line[1])),
rightText, leftText);
If you want the left column to align just use Component.setSameWidth() on the entire column.
I've been trying to make a 9x9 grid of textFields, where each textField is allocated to an element in a 2d array. For example the top left textField is field[0][0], the one right of that is field[1][0], and the bottom right textField is field[8][8].
So far I have
TextField[][] fields = new TextField[9][9]; {
for (Y=0;Y<9;Y++) {
XPosition=0;
for (X=0;X<9;X++) {
fields[X][Y] = new TextField(1);
fields[X][Y].setColumns(1);
fields[X][Y].setBounds(XPosition, YPosition ,32, 32);
frame.getContentPane().add(fields[X][Y]);
XPosition=XPosition+32;
}
YPosition = YPosition+32;
}
}
For some reason when I run the program, only the first 5 textFields in the top row get created. I have a feeling all the other textFields are placed under the visible ones. The frame is definitely big enough, and I can't figure out any issues with the code.
Use a grid layout : https://docs.oracle.com/javase/tutorial/uiswing/layout/grid.html
Absolute positioning is not reliable.
Adding
frame.getContentPane().setLayout(null);
has fixed the error
Introduction to the problem
It seams impossible to change a Veriable in a event (like so for example button.setOnAction(e -> { x = x+2});) and I can see why, but what if that's exactly what I need? It's actually not the first time that I needed to do that, but last time I got around it by saving the changed property directly to a file.
This time I used a really tricky trick to create a 'fake variable' by using the text in an invisibe TextField as my veriable. It works, that's not the problem, but I'd like to have a more 'elegant' salution :D
Friuts of my research
The only two salutions I could find were to either declare a Variable as a class member (which I don't want to do seeing that I already have six of them and don't want to tripple that amount) or to use seperate classes. (I found that here: How to change a variable when a button has been clicked in JavaFx )
The programm
Here is the code of my popup window (I'll spare you of the rest of my stupid programm ^^ ), I'll explain what it does after the codebox. (Note that props is a properties object and one of the mentioned class members as well as propPath (meaning I declared it at the very top of the programm so that it can be accessed from every function)):
private void createNewBuff() throws Exception {
Stage popupStage = new Stage(StageStyle.UTILITY);
popupStage.initModality(Modality.APPLICATION_MODAL);
popupStage.setTitle("Creating a new Buff");
popupStage.setMinWidth(400);
popupStage.setMinHeight(300);
GridPane layoutGP = new GridPane();
layoutGP.getColumnConstraints().addAll(
new ColumnConstraints(200), //TextField column col 0
new ColumnConstraints(10), //Gab column col 1
new ColumnConstraints(60), //tf manips column col 2
new ColumnConstraints(30), //Gab column col 3
new ColumnConstraints(80)); //Main buttons col col 4
TextField tfName = new TextField("Unknown Buff");
tfName.setPromptText("Name of the Buff, e.g. \"Unknown Buff\"");
Label lblName = new Label("Name");
layoutGP.add(tfName, 0, 0);
layoutGP.add(lblName, 2, 0);
TextField varTF = new TextField();
TextField tfEffect = new TextField();
tfEffect.setPromptText("Effect of the Buff, e.g. \"+10 LP\"");
Button btnAdd = new Button("Add");
btnAdd.setOnAction(e -> {
String input = tfEffect.getText();
String[] comps = input.split(" "); //components
if (Array.getLength(comps) == 2) {
if (input.contains("+")) {
varTF.setText(varTF.getText() + input + ";");
layoutGP.add(new Label(input), 0, 1 + Array.getLength(varTF.getText().split(";")));
} else if (input.contains("-")) {
varTF.setText(varTF.getText() + input + ";");
layoutGP.add(new Label(input), 0, 1 + Array.getLength(varTF.getText().split(";")));
}
}
});
layoutGP.add(tfEffect, 0, 1);
layoutGP.add(btnAdd, 2, 1);
Button btnDone = new Button("Done");
btnDone.setOnAction(e -> {
int buffNumber = 1;
while (props.containsKey("Buff-" + buffNumber + "-name"))
buffNumber++;
props.setProperty("Buff-" + buffNumber + "-name", tfName.getText());
props.setProperty("Buff-" + buffNumber + "-effect", varTF.getText());
try {
FileOutputStream streamOut = new FileOutputStream(propPath);
props.store(streamOut, null);
streamOut.close();
popupStage.close();
}catch (IOException someE){/*something meaningful*/}
});
btnDone.setMaxWidth(Double.MAX_VALUE);
Button btnCancel = new Button("Cancel");
btnCancel.setOnAction(e -> popupStage.close());
btnCancel.setMaxWidth(Double.MAX_VALUE);
layoutGP.add(btnDone, 4, 0);
layoutGP.add(btnCancel, 4, 1);
layoutGP.setAlignment(Pos.TOP_CENTER);
Scene popupScene = new Scene(layoutGP);
popupStage.setScene(popupScene);
popupStage.showAndWait();
}
I wanted to post a picture there of how it looks once you start it and another of how it looks after you used it, but my reputation is still to low ^^
Therefor I'll provide the links to the pictures: Befor something was done http://i.imgur.com/Wx3nIEX.png After it's used http://i.imgur.com/5QNmWP6.png
What the programm does
It's pretty strait forward actually: my main programm is a character sheet and with that popup you can add a buff to it (later I'll make it so that the effects of the buff get calculated into the values of the sheed, but one step at a time ^^ ). You can set the name of the buff you want to create ("Unknown Buff" is the standart in case you forgett to set one) and then you can simply add defferent effects by writing tem into the TextField and then pressing the 'Add' button. They will list themself top to bottom in the free space. They will also, behind the scenes, save themself as one large string into a hidden TextField to make figuring out in which line each individual Effect has to be displayed and to save it to the properties file afterwards. (and that salution with the undisplayed textfield is exactly the trick I want to remove and turn into a more 'elegant' salution)
Detailed explanaition of the code
At first the Stage is created. Then the layout is made in form of a gridpane und the column sizes are set (every second column is for spacing reasons). After that I'm creating the line for the name (the label and the textfield) and also my tricky textfield that's used as a String variable. Now I'm creating the effect textfield and add button, as well as the event for the button: at first it turns the input from the textfield into a easier to read name and splits it into it's components (at first I used tfEffect.getText() and tfEffect.getText().split(" ") inside the code below, but that was really messy) now I have if statements to verify it and make sure that the Effect is in the right format (that format beeing the amount a certain stat is raised or lowerd, consisting of either a plus or a minus symbol at the beginning and a number after that; followed by a space and then the index of the stat (I haven't been able to implement verifying if the typed thing actually is a valid stat, maybe that'll be content of a future question ;D )). After verifying the programm it adds the effect below all the others. If you're done and happy with you're buff you can click the Done button, it will first look up how many Buffs already exist, then assign the new on a number and save it all to the properties file. The cancel button with of course just cancel it and at the bottom I'm setting the scene and calling the stage.
What I'm hoping for with this question
Now I think you have a pretty clear idea of what I need to do and why I couldn't find a better salution then using a hidden TextField as a variable and I hope it's because I'm a beginner and not because there actually is no better way of doing it ^^
Also if you actually read all of this you may found one or two things I can improve besides that, but that would be the special bonus ;D
i have done a small test on LibGdx, on Multi-line Label, it seems that i cant get the wrapped line's height. Following is the code. Theoretically, height for aLebel should be > bLabel. But the result appear the same.
code:
aLabel.setText("this is a super long long long text that need wrapping."); // line wrapped into 3 lines
aLabel.setWrap(true);
aLabel.setWidth(470);
doLog("aLabel.getHeight(): " + aLabel.getHeight());
bLabel.setText("this is short."); // unwrapped line
bLabel.setWrap(true);
bLabel.setWidth(470);
doLog("bLabel.getHeight(): " + bLabel.getHeight());
result:
aLabel.getHeight(): 45.0
bLabel.getHeight(): 45.0
Do anyone have any idea how to get the actual multi-line height in LibGdx? Thanks in advance.
I had this issue for years and accidentally solved it by setting the width and packing the label twice. Note that multiline labels were never intended to figure out their own width, so you have to set them externally, preferably from it's parent.
public Label createLabel() {
// Create label and set wrap
Label label = new Label("Some long string here...", skin);
label.setWrap(true);
// Pack label
label.pack(); // This might not be necessary, unless you're changing other attributes such as font scale.
// Manual sizing
label.setWidth(textWidth); // Set the width directly
label.pack(); // Label calculates it's height here, but resets width to 0 (bug?)
label.setWidth(textWidth); // Set width again
return label;
}
LibGDX version used: 1.6.4
Pack sizes the widget to its pref size, nothing more. Pref width of a label with wrapping is 0.
Label label = new Label(...);
label.setWrap(true);
label.setWidth(123);
label.setHeight(label.getPrefHeight());
I had the same issue and it seems there doesn't exist a method in Label class to solve this. Also, I agree with you, the getHeight() method should return the real height of the Actor, so I don't know if that's a bug or there is a reasoning behind that behaviour.
Anyways, how I solved the issue is by using BitmapFont's getWrappedBounds method. It's not short, but for your example it would be the following:
doLog("aLabel.getHeight(): " + aLabel.getStyle().font.getWrappedBounds(aLabel.getText(), aLabel.getWidth()).height);
This could be done by adding a restriction to the cell that contains the Label in the Table:
Label label = new Label("Example", new Label.LabelStyle(font, Color.WHITE));
label.setWrap(true);
Table table = new Table();
table.add(label).width(WITH);
For more information about how to use Table go to: https://github.com/libgdx/libgdx/wiki/Table
What would be an easy way to set the background color of all characters from some start to an end position in Java.
Eg:
red background from position D(4) to J(10)
String alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
Many thanks in advance.
Edit:
Oh no, 2 '-'? Ok here is what I'm doing.
JTextArea textArea = new JTextArea("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
textArea.setFont(new Font("Courier", Font.PLAIN, 16));
//then I want red background from position D(4) to J(10)
please read Using Text Components and tons examples for that
look here for excelent workaround
Split the String into 3 separate Strings.
String a = alpha.substring(0,4);
String b = alpha.substring(4,11);
String c = alpha.substring(11);
Then display a,b, and c next to each other while only formatting b as desired.