I've create a new subclass of a wicket behavior which can be attached to form components. If a validation error occurs for such a component, the behaviors shows/hides a specific error label. My code looks similar to this:
public MyErrorBehavior(Component errorComponent) {
// show/hide errorComponent within onUpdate() or
// onError() based on getComponent().isValid()
}
My questions is: Is it ok to pass a component to a behaviors constructor?
Cheers,
Andreas
Yes, a behavior is allowed to keep references to components, please see EqualInputValidator as an example.
Take care if you remove these components from your component tree: you should remove the behavior too, otherwise you'll have dangling references of components which are no longer detached.
There is no need to keep a reference to the component because Wicket will pass the component in the callback method, e.g.
#Override
public void onComponentTag(Component component, ComponentTag tag)
{
// cast component to FormComponent and make the check here
}
This way there is no need to clean up and you can add the same Behavior instance to more than one (Form)Component.
Related
In my viewmodel I have the following code:
#Command
public void onFinish(#BindingParam(value = "myButton") Button myButton) {
Component root = myButton.getParent().getParent().getParent();
...
}
Is there a more elegant way to find the root component of any given component? The expression above has to be altered every time I change the zul.
P.S. I am new to zkoss..:)
It all depends on what the root of your component is.
Your root is normally an IdSpace, and if you didn't have set other IdSpace element's you could use :
#Command
public void onFinish(#ContextParam(ContextType.SPACE_OWNER) IdSpace spaceOwner) {
...
}
This way, you never have to pass anything in the zul.
It will automaticly fetch that component.
Remember that IdSpace is an interface what is implemented in some specific components.
Please take a look of the other, maybe more suitable in your case, options you can do.
But there are also other tricks, this one uses CSS selectors :
#Command
public void onFinish(#SelectorParam(":root") Component root) {
...
}
Like this you will always have the root.
I'm not a great fan of sending components from the view to the viewmodel with bindingparams.
Reason is that today, you call this command from a button, but maybe you add the same command on other component and then this will fail.
Yes, you can use the Component class, but MVVM has so many ways to do it in a better way without polluting your view.
Remember that the whole point of MVVM is a separation between UI and code.
It may not matter what triggers a command, even as it doesn't matter what your collection will fill on the screen.
Assuming your root component has an id, you could do the following:
Component root = myButton.getPage().getFellow("id-of-root-component");
I have a panel, let's call it detailsPanel, which holds a Person reference and displays its field values in the following manner:
Name: person.getName ();
Surname: person.getSurname ();
Emain: person.getEmail ();
.... .......
.... .......
And so on. I will use JLabels (correctly aligned using a GridBagLayout) to show each (fieldName, fieldValue). I have a lot of fields to display.
The problem is that the panel which shows the details must be always visible, i.e it will not be shown in a modal JDialog, so that i could create the panel by simply reading my Person object fields at the panel creation.
The panel must always be visible, and its Person reference will change when the user selects a different row in a Person list. This means i will call a method to update its state, something like:
detailsPanel.setPerson (aPerson);
Now, i'm wondering how i should update all the fields. Should i keep a reference to all the JLabels which show the values, and use setText(value) on each of them when i update the panel, or would it be better to override getText() method for every label, returning the correct field value, so that in the update method i would only repaint the panel, and the text would automatically change when the getter method is used on a different Person object?
Any suggestion is appreciated!
Since this is UI stuff which is usually called almost never (relative to how often things are called in other computation) you don't need to worry about efficiency at all. Just do what you think is the most elegant solution. There are three options That quickly come to my mind. They are ordered from quick and static to elegant and reusable:
Quick and dirty: create your constructor and make everything look nice. Then move everything from the constructor to a separate init() method and every time the entities change, you just call removeAll(); and then init() again.
As you suggested, keep a reference to all labels and use the setPerson() method to update all panels. Then call this method in the constructor (this is arguably the most common solution).
As you suggested, build your own extension of JLabel. This new class should either have an update() method which is to be called when things change, or have it set its own listeners to ensure that it gets notified of any relevant change.
If you are planning to create a single panel which is supposed to display all kinds of objects, you could have those object implement an interface called Displayable which gives you generic access to all its values and maybe even listeners to each value. An alternative to the Displayable interface is to use reflection and use annotations to allow the panel to get its values for display.
Please note that the most elegant solution is - contrary to what some people may tell you - not always the best for any situation. How much maintenance do you expect there to be in the future? How big is the application? Will you ever hand off the code to someone else? All these and more need to be considered to decide how "nice" you want your solution to be.
I have partStack with a lot of parts in tabs. I'd like to know how can I make tabs inactive when I don't need them and active when I need.
By inactive I mean tab which is visible but I can't click on it and it is like disable function (for example text on it is gray instead of black).
I use an e4 RCP (with Application.e4xmi).
Thanks for help.
Handling of the selection of parts in a part stack is handled by the part stack renderer org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer which basically uses a CTabFolder.
You can use a renderer factory to override the stack renderer see here
You can extend the existing StackRenderer class and override methods to change its behavior. In this case probably the hookControllerLogic method. But you are going to have to study the source carefully to see what needs to be done.
You can try using using EPartService to manipulate a part but I think active/inactive part just means visible or not.
Or you can just loop and disable all swt controls yourself manually 😄
Use Renderer factory to override the stack renderer.
Extend the existing StackRenderer class and override hookControllerLogic() or activate() methods with empty implementation.
Example-
public class MyE4Part extends ContributedPartRenderer {
/*
* Don't activate the Part on part selection. part should not be gain the focus on any
* selection on part .
*/
#Override
public void hookControllerLogic( MUIElement me )
{
//Don't do anything.
//super.hookControllerLogic( me );
}
}
I have table of player in html: [table]
How I can hide or not render this table when it is empty? I try to add if conditional in java code and add this table to the page only if there is some value but then wicket throws an exception that he cant find component with this id. So how I can do this?
It throws the exception because the html markup expects the component to exist. Ie you must add it.
If it's an entire panel you want to hide then using EmptyPanel is the will hide the entire panel.
You can also use component.setVisible(false) to hide it if its only one component in the panel.
You can override the isVisible() function and return false if no date is available. But, this function will be called a few times, so if determining if data is available(like, hitting a database) you can call the setVisible(boolean) function.
Another option is to exchange the Repeater with an EmptyPanel if no data is available.
You can use the same condition you already use in java, but instead of not adding the table to the page, use table.setVisible(false).
Another way to do it would be to override the setVisible() and isVisible() methods, but i don't think it is recommended (see here)
Hope this helps
As the other users have pointed out, overriding isVisible() is not recommended because this function is called many times before component is rendered.
You should instead override onConfigure() and put inside it the code that decides if your table must be visible or not. onConfigure() is called just once per request.
Is there a way (e.g., via an event?) to determine when a Swing component becomes 'displayable' -- as per the Javadocs for Component.getGraphics?
The reason I'm trying to do this is so that I can then call getGraphics(), and pass that to my 'rendering strategy' for the component.
I've tried adding a ComponentListener, but componentShown doesn't seem to get called. Is there anything else I can try?
Thanks.
And additionally, is it OK to keep hold of the Graphics object I receive? Or is there potential for a new one to be created later in the lifetime of the Component? (e.g., after it is resized/hidden?)
Add a HierarchyListener
public class MyShowingListener {
private JComponent component;
public MyShowingListener(JComponent jc) { component=jc; }
public void hierarchyChanged(HierarchyEvent e) {
if((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED)>0 && component.isShowing()) {
System.out.println("Showing");
}
}
}
JTable t = new JTable(...);
t.addHierarchyListener(new MyShowingListener(t));
You can listen for a resize event. When a component is first displayed, it is resized from 0,0 to whatever the layout manager determines (if it has one).
You need to check up the component hierarchy. Check after AncestorListener.ancestorAdded is called.
I've always used Coomponent.addNotify to know when the component is ready to be rendered.Not sure if is the the best way, but it works for me. Of course you must subclass the component.
Component.isDisplayable should be the right answer but I know it didn't worked for me as I thought it will(I don't remember why, but there was something and I switched to addNotify).
Looking in the SUN's source code, I can see addNotify fires a HierarchyEvent.SHOWING_CHANGED so this is the best way to be notified.