I'm using libgdx Table to show some info. This information can change sometimes. I would like to change the cells so that they reflect the updated values. Is this possible or are Tables designed to be static? To clarify, I would like to do is something like this:
class MyTable extends Table{
Cell<Label> cell;
public MyTable(){
super();
cell = add("some value");
// Add many more cells and rows here
}
public void updateCell(String val){
cell.update(val); // How to do this??
}
}
Ideally, I would like to do this without knowing the position of the changed cell, but any solution that requires that info is OK too.
add("some value") is a convenience method, which actually adds a Label with the given text.
You can achieve the same by doing this:
Label myLabel = new Label("some value", skin);
add(myLabel);
After that you can change the text by changing the label itself.
public void updateCell(String val){
Label myLabel = (Label) cell.getActor();
myLabel.setText(val);
}
Related
public static void showHs(boolean remove){
if(remove){
table.getCell(hsLabel).getActor().setVisible(true);
table.getCell(hsLabel).getActor().setWidth(labelsWidth);
}else {
table.getCell(hsLabel).getActor().setVisible(false);
table.getCell(hsLabel).getActor().setWidth(0);
}
}
setVisible() doesn't remove actor - it still takes the cell, if I use remove() works, but permanently, can't bring actor at the same place.
Is there any methods like Visibility.GONE ? I searched and ended by being here.
public static void showHs(boolean remove){
if(remove){
table.getCell(hsLabel).getActor().setVisible(true);
table.getCell(hsLabel).getActor().setWidth(labelsWidth);
table.getCell(hsLabel).expandX();
}else {
table.getCell(hsLabel).getActor().setVisible(false);
table.getCell(hsLabel).getActor().setWidth(0);
table.getCell(hsLabel).width(0);
}
}
Worked out by setting 0 width to cell, but maybe there is a proper way
Here is a simple approach on how to make your actors inside your table set the visibility. You don't have to set the actor's width to zero to make it "disappear".
The second parameter in contains is Identity, If true, == comparison will be used. If false, .equals() comparison will be used.
true if an array contains a value, false if it doesn't.
public static void showHs(boolean visible,Actor yourActor){
if(table.getChildren().contains(actor,true){
actor.setVisible(visible);
}
}
What I'd like to do is be able to tab between elements in table.
I currently am creating my table like this.
this.tableViewer =
new TableViewer(parent , SWT.FULL_SELECTION);
tableViewer.setUseHashlookup(true);
table = tableViewer.getTable();
GridData gridData = new GridData(GridData.FILL_BOTH);
gridData.grabExcessVerticalSpace = true;
table.setLayoutData(gridData);
table.setLinesVisible(true);
table.setHeaderVisible(true);
...
/** Create the Cell Editor Array - will hold all columns **/
editors = new CellEditor[table.getColumnCount()];
/** Cell Editor Row 1 **/
/** Set the column properties **/
tableViewer.setColumnProperties(columnNames);
/** Assign the cell editors to the viewer **/
tableViewer.setCellEditors(editors);
/** Set the cell modifier for the viewer **/
tableViewer.setCellModifier(new MyCellModifier(this));
//Create the Table Viewer
/** Table Viewer Content and Label Provider **/
tableViewer.setContentProvider(new MyContentProvider(this));
tableViewer.setLabelProvider(new MyLabelProvider());
But I'm not sure how to set up the tabulation. Everything else works as far as editing columns, showing data, etc. Just stuck on this last part.
If I've missed obvious documentation or javadocs - my apologies and even pointing to those would be great.
Although the solution thehiatus posted is very low level and will probably work (I haven't tested it), JFace gives you a framework for this specific problem. See the org.eclipse.jface.viewers.TableViewerFocusCellManager along with org.eclipse.jface.viewers.CellNavigationStrategy classes to solve this problem.
I think by default tab does not jump from cell to cell in an swt table. Instead it traverses to the next control. So you'll also need to tell it not to traverse when tab is pressed
KeyListener keyListener = new KeyLisener()
{
public void keyPressed(KeyEvent evt)
{
if (evt.keyCode == SWT.TAB)
{
// There are numerous setSelection methods. I'll leave this to you.
tableViewer.getTable().setSelection(...)
}
}
public void keyReleased(KeyEvent evt){}
}
TraverseListener traverseListener = new TraverseListener()
{
public void keyTraversed(TraverseEvent evt)
{
if (evt.keyCode == SWT.TAB)
evt.doit = false;
}
}
tableViewer.getTable().addKeyListener(keyListener);
tableViewer.getTable().addTraverseListener(traverseListener);
Also, as derBiggi suggested, the listeners need to be added to the Table object, not the TableViewer.
I couldn't get the desired behavior with a TraverseListener (it would not traverse within the table), and I had trouble getting it to work with a FocusCellManager and CellNavigationStrategy. I finally found this solution that enables me to tab from column to column within a row and automatically activate the editor.
Viewer viewer = ...
TableViewerFocusCellManager focusCellManager =
new TableViewerFocusCellManager(
viewer,
new FocusCellHighlighter(viewer) {});
ColumnViewerEditorActivationStrategy editorActivationStrategy =
new ColumnViewerEditorActivationStrategy(viewer) {
#Override
protected boolean isEditorActivationEvent(
ColumnViewerEditorActivationEvent event) {
ViewerCell cell = (ViewerCell) event.getSource();
return cell.getColumnIndex() == 1 || cell.getColumnIndex() == 2;
}
};
TableViewerEditor.create(viewer, focusCellManager, editorActivationStrategy,
TableViewerEditor.TABBING_HORIZONTAL);
You need to add a KeyListener and set the selection or focus to the next cell:
tableViewer.getTable().addKeyListener(new KeyListener(){
public void keyPressed(KeyEvent e) {
System.out.println("Key Pressed");
if (e.keycode == SWT.TAB)
{
System.out.println("Detected TAB key");
// set table viewer selection
}
}
public void keyReleased(KeyEvent e) {
System.out.println("Key Released");
}}
);
I also had to implement tabbing between elements in a table. We use Grid from Nebula as the table.
Firstly, I had to suppress tabbing the focus preventing it from moving out of the table.
and then I added a Key Listener which moves the focus/selection to the next cell:
I also made my own algorithm to move the selection one cell to the right and when at the end of the row, move it to the beginning of the next row. When end of table is reached, the selection moves back to the first cell in the table.
This solved the problem for me.
I have the following setup: In Label.fla there is a MovieClip that contains a TextField, which has its class set to src.components.Label. All this class does is set the font in the constructor and then set the text property of the TextField to an empty string (the value of the string doesn't matter for this problem. It can be a non-empty string and have the same result). Like this:
package src.components
{
import flash.display.MovieClip;
import flash.text.TextFormat;
import flash.text.TextField;
public class Label extends MovieClip
{
public var mTextField:TextField;
public function Label()
{
super();
var tf:TextFormat = new TextFormat("Arial", 34, 0xFFFFFF);
mTextField.defaultTextFormat = tf;
mTextField.setTextFormat(tf);
trace("init before: " + mTextField.getTextFormat().font);
mTextField.text = "";
trace("init after: " + mTextField.getTextFormat().font);
}
}
}
The label object in Label.fla is set up to export for runtime sharing, which has been copied into MainMenu.fla. A single instance of this label is placed on the stage of MainMenu.fla, and when I run MainMenu.swf the output clearly shows that the font is being set and then immediately cleared just because I'm changing the text property of the TextField.
The output looks like this:
init before: Arial
init after: null
Why would setting the text cause the font to be cleared? This is causing me a lot of problems. The only way I've figured out how to work around this is to do something stupid where I make a copy of the TextFormat object before setting the text, set the text, and then reapply the copied TextFormat to make sure it doesn't change.
I've attached a zip file containing all of the source and compiled files to test this with.
FontTest.zip
The very short answer to the question is this:
because you did not read the documentation.
That's right that's the only problem in your code. You are using a method (setTextFormat(tf)) that is only meant to set the format for the current existing text. This is specified in the docs of course.
The one method that sets format for any future set texts is: "defaultTextFormat". Once again this is specified in the docs and this method will not modify a text that is already set in the textfield.
So 2 methods meant for 2 different things, one (the one you use) that is used to modify the existing text, and one "defaultTextFormat" that is used to modify any future texts.
But really reading the docs would have saved you a trip to SO, read the as3 docs and answer 99% of your future questions and problems.
Expanding off of what BotMaster posted, I reread the documentation and figured out where I was misunderstanding. You can only set the text using setSelection() followed by replaceSelectedText() if you want to maintain the text formatting when using defaultTextFormat. So the fixed constructor looks like this:
public function Label()
{
super();
var tf:TextFormat = new TextFormat("Arial", 34, 0xFFFFFF);
mTextField.defaultTextFormat = tf;
trace("init before: " + mTextField.getTextFormat().font);
mTextField.setSelection(0, mTextField.length);
mTextField.replaceSelectedText("");
trace("init after: " + mTextField.getTextFormat().font);
}
This generates the following output:
init before: Bender
init after: Arial
Bender is the font being set in the FLA so that is the expected starting value.
As an alternative solution, you could store the TextFormat object and just apply it after you set the text property, but I'm not sure which one is more efficient. That solution would look like this:
public class Label extends MovieClip
{
public var mTextField:TextField;
private var mTextFormat:TextFormat = null;
public function Label()
{
super();
// Storing this in a member so that anywhere in this class that you change the text
// you can just apply it without having to reconstructing it.
mTextFormat = new TextFormat("Arial", 34, 0xFFFFFF);
trace("init before: " + mTextField.getTextFormat().font);
mTextField.text = "";
mTextField.setTextFormat(mTextFormat);
trace("init after: " + mTextField.getTextFormat().font);
}
}
I am working on Swing code that has a bunch of radio buttons associated with a hashmap of their hex values. It will then display (in a display area) the color (in the background) along with some text of the hex value of that color.
I'd like it to do this by referencing the values stored in my hashMap and populating these fields accordingly but don't know quite how to do it. I could hard-code individual ActionListeners (20 in all) but what's the point of coding if you have to do everything the hard way?
Below is my ActionListener & a couple entries in my hashMap. Thanks in advance!
//---- Action Listener
jrbRed.addActionListener(new ActionListener() {//<---Reference whichever button is selected instead of just 'jrbRed'
#Override
public void actionPerformed(ActionEvent e) {
jlblMessage.setForeground(Color.decode("#000000"));
jlblMessage.setText("FF0000");//<---Reference hashmap value
getContentPane().setBackground(Color.red);//<---Reference hashmap value
}
});
// ...my color map of hex values for referencing...
hashMap.put("Blue", "#0000FF");
hashMap.put("Purplish", "#DF01D7");
hashMap.put("Red", "#FF0000");
// ...etc...
What if you're map looked like this?
JButton blueButton = new JButton("Blue");
hashMap.put(blueButton, "#0000FF");
MyActionListener listener = new MyActionListener();
for(JButton button : hashMap.keySet()) {
button.addActionListener(listener);
}
Then to get the value depending on the button in your listener:
jbliMessage.setText(hashMap.get((JButton)e.getSource());
You can subclass your radio buttons to have foreground, background, and text Color variables, and reference them in your ActionListener:
private class ColorSettingListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
ColorRadioButton crb = (ColorRadioButton) e.getSource();
jlblMessage.setForeground(crb.getForegroundColor());
jlblMessage.setText(crb.getColortext());
getContentPanel().setBackground(crb.getBackgroundColor());
}
}
If you think this is too obtrusive, you can use JComponent.getClientProperty(Object) and JComponent.setClientProperty(Object, Object) to do the same thing. Then you don't have to subclass.
i have created a group in run time and then added in it two buttons and one label
addElement (myGroup )
myGroup.addElement ( button 1 )
myGroup.addElement ( label )
myGroup.addElement ( button 2 )
now when i click on one button 2 i can get event.currentTarget.
How can i change the text of label using this event.currentTarget. How can i target the label
I believe this may solve your problem.
When you create the label Object provide it with an id. so that you can access the label through out the application using this 'id'. You can change the text by using this id.text
Or you can use the group objectId. like this one
groupObjectID.getElementAt(index).text
You can see if the event.currentTarget is Label by casting it using 'as' operator
var lbl:Label = event.currentTarget as Label;
if (lbl)
{
//do rest of processing
}
Give name to your Label label.name='lblSomething'. Then you can access by
var mylabel:Label = myGroup.getChildByName(lblSomething) as Label
Try var labelStr:String = event.currentTarget.label;
Actually I do recommend you try to create those labels and buttons as either public or private objects whenever possible so that you can always refer to them using the object ID.
This is a good practice as well... just my 2 cents.
public var t_label:Label = new Label (); // t_ just stands for temporary... nothing special
myGroup.addElement (this.t_label);
Then inside ANY event handler you can write something like this to change the label text.
private function onWhateverHandler (event:Event):void
{
this.t_label.text = "whatever new string value";
}