If I have elements inside my gridLayout, can I get the reference to that object, if yes, which function do I need to use? Is it good idea to perform some actions on the objects inside gridLayout? Or there is another better language idiom?
No you cannot get references to items from a layout. However, you can from the container that holds the button. A better solution might be to hold a reference to the button at a higher level of scope in order to be able to access it later.
You can't get stuff out of a LayoutManager unless it specifically supports it, and GridLayout doesn't.
If you are putting Components into a Container then you probably have a reference to them anyway. Can't you pass this reference around?
Related
Can a Java Swing JPanel hold a String value than can be modified/accessed where I can save some information?
I see no other option but to implement my own class holding a JPanel and a String... was just trying to save some space/coding..
I like the setName/getName of the Component super class... is there any inconvenience in using that ??
Yes it can. Any Swing component can hold client properties for the specific component.
See the putClientProperty(...) and getClientProperty(...) methods of JComponent. Using this approach you can define any number of client properties:
panel.putClientProperty("Title", "Panel1");
panel.putClientProperty("Description", "some text for the description");
You can also use the setName(..) and getName() methods if you just want to uniquely identify the panel with a string name. Many IDE's will use this property.
Of course if you are creating a panel with multiple Swing components and related instance variables then you would probably extend JPanel and customize its behaviour.
I like the setName/getName of the Component super class... is there any inconvenience in using that ??
If you feel the "name" property adequately describies the data you want to store then this is the most efficient way to store the data. However, if the data is not really the name of the component then don't force the data just because it is easy to use. Also it is possible some IDE's may use this property for generic debugging or messaging. That it may check display this value in an error message to help identify a specific component.
Several solutions, and it's hard to know what you're looking for here. You could create a MyJPanel class that extends JPanel and is identical except including a String field with getter/setter. You could also store information in silly ways like by setting/getting the name of the JPanel. (That is use setName and getName of the Component superclass.) Another solution is to add a JLabel or some other component with that information to the JPanel, and if necessary, making it invisible or hidden.
No, I think it cannot hold a String value.
You can see all getters/setters here:
http://docs.oracle.com/javase/7/docs/api/javax/swing/JPanel.html
Also, you can check the source code (if you want to go that far).
There's no getter/setter useful for holding a String value
(I mean ... e.g. no setText or setTitle).
Of course, you can add e.g. an invisible JTextField to your JPanel and
set the String into the JTextField. But that doesn't seem very nice to me.
JPanels hold JComponents, i.e. JButtons, JLabels, etc. A String is not a component. It would be best if you'd just use a JLabel with a String as its parameter, then add that to a JPanel.
You can add a Component like JLabel/JTextField and use setVisible(false). That object can hold strings.
note: Only for Buttons.
You could use setAtionCommand() but it is indented for something very specific. It would be horrible practice for anything else.
To illustrate my problem, let's say I have an instance of Thing which has two text properties - 'foo' and 'bar'.
I want to create a Panel to edit instances of Thing. The panel has two TextField components, one for the 'foo' property and one for the 'bar' property.
I want to be able to call setDefaultModel() on my Panel with an instance of IModel<Thing> and for the TextField components to reference this model. How best to achieve this?
Should I override the Panel.setDefaultModel() method to also call setModel() on the two TextField components? Or perhaps create anonymous ReadOnlyModels for the TextField components, overriding the getObject() method to retrieve the object from the containing Panel's model?
Neither of these seem very elegant to me, so I was wondering if there's a better way?
You can use a PropertyModel for the textFields. Pass the IModel<Thing> into the constructor of the PropertyModel with foo as the property name:
add(new TextField("fooFieldId", new PropertyModel(thingModel, "foo")));
The PropertyModel will figure out that the thingModel is a Model and call getObject().getFoo() etc.
This assumes the IModel<Thing> instance doesn't change, only its underlying object which can be changed calling setDefaultModelObject.
Maybe I'm just missing the point, but I can't find a Panel.setModel() in the JavaDocs of neither 1.4 nor 1.5. If it's something you implemented maybe you could change it not to replace the model object but to call model.setObject() instead?
Disclaimer: Can't really check right now, cause there is no wicket at work and my home machine suffered a video card breakdown earlier...
Maybe this would help?
public abstract class AbstractWrapModel<T> extends Object implements IWrapModel<T>
Simple base class for IWrapModel objects.
See IComponentAssignedModel or IComponentInheritedModel so that you don't have to have empty methods like detach or setObject() when not used in the wrapper. The detach method calls the wrapped models detach.
I want to create panel object (working as a kind of navigation bar) shared between pages. I want to add buttons dynamically, so it's important to me that all pages share the same object.
However when I add the panel to second page it disappears from the first one! Why is it so?
And maybe any tips how to deal with it? :)
The Vaadin component hierarchy allows for one component to be at one place at a time. In other words, you can't have the same Component instance added to two places at the same time.
The best solution would be to move your panel so that the panel is never replaced, only the surroundings. If that's impossible, you need to just recreate the controls for each page.
If your controls are stateful, remember that Properties can be shared between Fields, and all classes extending AbstractFields are Properties, so you can do stuff like
TextField tf1 = new TextField();
layout1.addComponent(tf1);
TextField tf2 = new TextField();
tf2.setPropertyDataSource(tf1);
layout2.addComponent(tf2);
This way your two textfields are backed up by the same Property. So, after the value has changed, your two textfields have the same value.
I would suggest you take a look at FlexTabSheetNavigationFeeder a component that, to my understanding, is used for creating a universal navigation menu connecting view/content to each of the buttons/tabs of the component.
I use a common library of the Vaadin framework and we have component called SFlexTabSheet doing exactly what it sounds that you want to do.
I just started yesterday using GWT, so maybe I'm not using the proper mechanism to solve that problem. So, I will try to explain exactly what I'm trying to do (with a simple problem) and 2 solutions I came up with to address that problem.
Problem:
Remember an index that can be updated via other widgets. Let's use focus to represent it.
[button 1]
[button 2] [button A]
[button 3]
The buttons [1..3] and [A] are not in the same class and need to find the element using the id using the DOM. The reason is that those 2 views needs to be orthogonal.
We can use up/down key to move the focus from button 1 to 3.
If we are on the buttons [1..3] and press right, we go to button A.
If we are on the button A and press left, we go to button previously focused.
What we want to do is save or set the focus index when pressing right.
Solution 1: Global variables
I'm not usually fond of global variables, but in some case it's handy. By using, for instance, a dictionary (Dictionary.getDictionary) defined globally in the javascript, I could save the current index in it using the "Focus Event" in that case.
So, in the key press event, when left would be fired, I would just read the value in the dictionary.
I haven't tested yet, but I think it should work.
Solution 2: Set the value with the Element
Element element = DOM.getElementById("button id A");
element.<setFocusLeftKey>("button id [1..3]");
Here what I would like to achieve is just in the "onFocus" Event, I would simply set the value of that button.
So is it possible to cast/find the object with the Element? I think that if there is no easy way, it's probably because it's not recommended.
Is there a simpler way/other method to achieve that?
So, any thought or solutions?
Thanks in advance.
P.S. I haven't found a better title for that, so if any suggestion, just put it in the comments and I'll update it.
Using ID is definitely not the suggested way to do this in GWT. You say you need this mechanism to keep your views orthogonal to one another. This is noble, but in GWT you would achieve by using another resource (an EventBus, implemented in SimpleEventBus) that hides the different components from one another. In fact, I would argue that looking up the element by ID strongly couples the two views and is smelly.
Armed your EventBus you simply create and fire custom events that let the views (or, better, their presenters) communcate with one another. For example here you could have: NavigateRightFromButtonsEvent and NavigagteLeftFromButtonA event.
However, depending on the size of your app (or as a first experiment) you could decide to couple your two views. In this case simply pass the view for the button list into the one for button A and vice-versa. This is not really worse than relying on a global ID.
No matter which mechanism you choose (event bus or wiring the views together), you should now have access directly to the instance of the widget you want to highlight. To focus, just call setFocus(true) on it.
The container uses a BorderLayout. I have a JPanel that I added to the CENTER. However the JPanel doesn't have a variable name for it.
I could do contents.remove(nameofPanel)
But since I added it like this contents.add(new CustomJPanel(), BorderLayout.CENTER);
Now I'm trying to remove the current CustomJPanel and add a new one.
How do I do this?
While Carl's answer is probably the best one, a less-pleasant alternative if for some reason you can't modify the original add() call:
contents.remove(((BorderLayout)getLayout()).getLayoutComponent(BorderLayout.CENTER));
contents.add(someNewPanel);
Though if you think you need to do this, you may want to step back and evaluate why you're trying to do it.
Your best way is to extract the constructor call into a named variable - probably a field, actually - and then reduce to the previous case.
contents.add(new CustomJPanel(), BorderLayout.CENTER);
becomes
nameOfPanel = new CustomJPanel();
contents.add(nameOfPanel, BorderLayout.CENTER);
Or you can list all the elements in the container with the getComponents() function, and search your Panel by an other attribute (if you can).
The getName() attribute is useful for this purpose, e.g. you set a name for your panel before insertion and you can use that name as a search key.
I strongly suggest you declare a global CustomJPanel variable, instantiate it with your first panel, then add the panel. When you want to remove it, you use the same object. Then you assign the new object to the variable, and add it the same way.
Anonymous object are okay when you don't need to refer to them. But you do. So you should avoid using the anonymous way.