I have a Composite called display that has children elements placed in an absolute layout. Throughout my program, these children can move around on the composite and overlap. I want to create a "priority" so I can choose which children are drawn on top of other elements. The children are a custom class named Llama I made that extends Canvas. I have an integer field that stores their priority, but I don't know how to make them display in the order I want them to display (based on the integer field). Here's an image of the program displaying what I mean by overlap.
Basically, they automatically choose an order of display based on the order they were added to the composite (as far as I can tell). How can I change that order to fit my priority field?
Thanks in advance!
You need Control.moveAbove() and moveBelow().
Related
I am building a JTreeTable. I found some starter code and have come pretty far. In the end my goal is to be able to have different data at different levels like a hierarchical list.
Currently, I have it working with data at different levels. However, I am running up against a wall when it comes to changing the columns as a next goal. From where I currently stand I have 3 more milestones:
Show different set of columns for different levels
Ability to adjust column widths for different levels
Ensure the JTree part of the table always stays to left
I am getting close to closing out this task but again stuck at the first of these 3.
Since creating a JTreeTable is complex, the minimum example leverages several class listed below in the image:
I am happy to post the code to any of those classes but I also did not want clog the question with useless code. First let me show the functionality I want.
The first image is when the top level is selected and the second image is when the second level is selected. Notice how the columns are different. That is what I want to happen in my application.
Top level selected:
Second level selected:
So one way I tried to solve this problem, is when the list selection is changed inside this section of code:
ListSelectionListener listener = (ListSelectionEvent e) -> {
TreeTableModelAdapter adapter = (TreeTableModelAdapter) JTreeTable.this.getModel();
//Need to see why this breaks.
JTreeTable.this.getTableHeader().setColumnModel(adapter.getColumnModel());
};
this.getSelectionModel().addListSelectionListener(listener);
This code is in the initialization of the JTreeTable. I have tried setting the column model on both the TableHeader and the table as well. Below is what happens then when I select a row:
The columns just disappear on me. The creation of the column model is happening in the TreeTableModelAdapter class with the following method:
public TableColumnModel getColumnModel(){
DefaultTableColumnModel model = new DefaultTableColumnModel();
for(int i=0;i<getColumnCount();i++){
TableColumn column = new TableColumn();
column.setIdentifier(getColumnName(i));
model.addColumn(column);
}
return model;
}
Any direction would be very helpful. Again happy to post any code you think could be helpful to answer the question. Just put a comment in and I will add it right away.
I will add the milestones as I find them in case this helps others, but for now this question is answered.
Milestone 1
I was actually able to solve the first milestone. The key is to trigger the creation of the columns of the column model, not to create a new column model. Below is the code for when the row selection is changed:
//Change columns depending on row
ListSelectionListener listener = (ListSelectionEvent e) -> {
createDefaultColumnsFromModel();
};
this.getSelectionModel().addListSelectionListener(listener);
This code creates the columns based on the row selected in the JTree part of the JTreeTable. The TreeTableModelAdapter implements the getColumnCount() and getColumnName() methods by also passing the selected row in the JTree to the JTreeTableModel so that the columns and their names are dynamically retrieved based on a particular node in the JTree. The key for this for me was trigger those to be called again to update the JTreeTable.
Milestone 2
Adjusting column widths based on the data level proved to be much more difficult than I had originally anticipated. In order to retain the cells state when the column model changed I had to disconnect the painting of the cells from it. This is a hairy process because this is done inside BasicTableUI and the method that gets the rectangle of the cell is private. So I had to subclass it, overload the paint() method and create my own methods that get called inside the paint method. There was a lot of copy pasting so that I could call normally private methods. I just renamed them and referenced these methods instead. The way the ui class was designed did not make it very flexible. Below is 2 images where I am selecting different levels and the columns are obviously different widths at different levels.
Milestone 3
I was able to make this work by keeping track of the view in the model. This seems very dirty to me as the model should separated from the view. Since the tree column's class is unique, I just returned the right class if that column was the first in the view.
The one problem I have with this technique is that I get unexpected behavior where the value returned is not consistent. I attempted to resolve this by overriding JTree.covertValueToText(). Since a JTree only expects 1 value and depending on the sequence of columns in the view this value could change. So in overriding this method I check the stored index for the JTree column's value. Again this causes the unexpected behavior. I will update the post if I find the fix.
Imagine we have some parent container. We add children to it, one by one. Children widgets are placed according to some CSS: may be as block elements, may be as inline elements.
A question is:
Can we calculate the supposed parent height and width BEFORE adding next child and manage to insert "SHOW MORE" widget instead of adding next child?
I tried to add ResizeEvent handler to my container. It catches the event, but only at the very moment when child widget is added, but CSS rules are not applied yet! That means that ResizeEvent is caught when all the children widgets are placed one on top of another as block elements, but in fact they should be placed as inline elements. After ResizeEvent Handler runs CSS rules are applied and child-widgets are reordered as inline elements, but this is not causing new ResizeEvents to parent container, which height is small again..
So in fact I want to catch the moment of resizing of my parent container before it happens.. a kind of a "if you add this child - parent needs resize" or "if you add this child - parent size is bigger than ... px" trigger.
So is it possible to solve this task?
You need to wait for the browser to render the new widget before you measure its height:
// add widget to the container
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
// measure it here
});
You can do it using following technique:
Make a copy of your parent container. Attach it to the DOM somewhere. Make it invisible for users using some CSS tricks (z-index, margin-left: 10000px, ....) but do not use display:none.
Attach your child to this "invisible" parent first. Override Window.onAttach() for child. Calculate height and width.
Take a decision about what to insert into real parent (this child or "show more" link).
Move your child widget from invisible parent to real parent if necessary.
Hope there is another more simple way to do it.
Calculated height and width will be wrong if your child contain some images, because Window.onAttach() is called before the moment when all images are loaded.
Finally I have found a solution which is good for me:
I create a container with fixed size and an internal container which can spread inside it. The overflow of the top container is hidden. Thus, when I add next widget that cannot be displayed because it is out of the bounds of my top container - well, it is not displayed.. just because overflow is hidden.
The only thing that remains is to insert a "SHOW MORE" widget. To do it I calculate whether the last inserted widget bounds are out of the bounds of top container. I.e. whether the last inserted widget overflows top container, or not. If yes, I insert "SHOW MORE" widget in place if previous (the one before last) widget.
Thats it!
I generated a decision tree based on a set of data, then I converted this data to a xml file, after that I put it into a JTree. This part works fine but now I have to take a new instance(which contains the data received from the user), find it's place in the decision tree and change that node's color. And I can't find a way to do that. I am using weka and the J48 classifier to generate the decision tree. The xml is created in the Luc Sorel style: http://www.lucsorel.com/media/downloads/sample_decision_tree.xml
The first thing I tried was to classify the instance using the algorithm but that gets me only the class where it belongs, and I don't know how to locate it in the JTree.
What should I do? Any ideeas?
Like JTable, JTree uses a flyweight renderer to draw nodes. As the default renderer is a JLabel, you can set the foreground color or make the label opaque and set the background color. This related example changes the icon for emphasis. More examples may be found here.
Addendum: I cannot find … the node that I should color.
When getTreeCellRendererComponent() is called, value is a reference to the node to be rendered, and the tree parameter allows access to the TreeModel as a whole via getModel(). This example shows how to search a tree.
In my application, I have URN-identified data coming in from the server. I'm in the process of abstracting as far as possible so there is very little to no logical code in my views, and I'm using a generic presenter that wraps those views. All widgets have URNs, making it super easy to map incoming data to a specific widget (until now, a 1 to 1 relationship). This has worked well for pretty much every widget, and now I've reached a point where I'm tripped up.
Assume I have (just for simplicity's sake) two RadioButton elements on a view. These buttons belong to a "group" (just by setting their name values to the same thing), but obviously they're 2 distinct elements. I can't map my URN-identified data to a single widget as in every other case because, in this case, it is two widgets.
Here's an example of what I mean:
Utility Company is a ListBox, so just one widget there. I map each item in the list to a specific Enum value.
Utility Rate is a TextBox, so again just one widget to map.
For Energy Usage, they can select to use either an average for the year or input 12 monthly values. I'm stuck here. I can't map to just one of the RadioButton elements, because then I'd need some extra logic in the view to handle the behavior appropriately.
Am I stuck mapping to just one widget and sticking (unwanted) logic in my view to determine what the state of all of the elements should be based on the value that came in for the one widget that is mapped?
How should I handle this case?
Edit (Solution):
Following the concepts of jusio's answer, I came up with a workable solution. Because I didn't want to go sticking special case handling through my logic to take care of a non-widget, I created a RadioButtonSet faux widget (public class RadioButtonSet <T extends Enum<?> & HasDisplayText> extends Widget implements HasValueChangeHandlers<T>, HasValue<T>), into which I manually pass the radios I intend to group. Having done that, I can get or set its value and have it fire appropriate events when the user changes the selection. Then mapping the collection of radios is no different than doing so for a listbox. Thanks jusio.
I believe in your case you shouldn't treat radio buttons as two separate widgets, basically in your case you can treat the radio button group as combo box, because behavior is almost the same (the only problem is that you have additional master detail). So basically what you will have to do is to wrap real BO objects into some kind of RadioButtonGroupModel, and give it to view, view can take this model and generate radio buttons (with some editors or whatever else). I remember running into this problem when i was extending databinding FW for JFace, and this was the best way I could find to solve this problem.
If I understood correctly the problem, there are 2 possible solutions:
Give each RadioButton a unique URN (ex: oldURN_1 , oldURN_2)
When you send data for a URN, disable the other one
Keep the same Name for each RadioButton but add a number variable in the data the server sends indicating which radioButton it is supposed to use (ex: 0 for Average and 1 for Monthly)
There are 2 JTree: JTree1 and JTree2. Note that the nodes (country, city, colors, blue ...) all will be implemented as JCheckboxes so that user can select particular colors for each city or for the whole country by selecting their corresponding checkboxes.
Problem:
Q1. I want that each country or city can have its own colors selected. Means if a user wants city1.1 to have colors blue and violet and city2.1 to have colors red, then he first have to select the city1.1 checkbox and then select blue and violet, and after that when he selects city2.1, then the checkboxes blue and violet are deselected automatically so that user can select the colors for city2.1. But when the user selects the city1.1 again, then the JTree2should show the selected colors (bule and violet) for city1.1.
So for this purpose, Is the JTree (with its nodes as checkboxes) correct option to implement or I should use some other JComponent?
If JTree is a correct option, then how can I remember the colors of each city?
So for this purpose, Is the JTree
(with its nodes as checkboxes) correct
option to implement or I should use
some other JComponent?
Not exactly sure what you meant, but I, personally, would not use a JTree to present the options on the right hand side. I think it is much simpler to present a JPanel that contains the options in this particular case. Left side seems fine for your example, although I don't really know what sort of data is going into the tree.
If JTree is a correct option, then how
can I remember the colors of each
city?
Note, I'm going to make a couple of assumptions:
The left side that contains your countries and cities remains a JTree and the right hand side can still be a JTree or a JPanel.
You want the options to appear exactly as the user last set it before they select a different node on the left hand side.
The simplest way of achieving this is to add a TreeSelectionListener to the tree's (the one containing the countries and cities) selection model. The TreeSelectionListener is provided with a TreeSelectionEvent which provides the node that was selected and the node that will become selected. This will provide you with the opportunity to extract the colour settings that were set for the node that the selection is changing from to the one that the selection is changing to. The TreeSelectionListener should be added to the TreeSelectionModel that is obtained from the JTree, by calling its getSelectionModel method.
If you use this technique, when you to perform the operation with the last selected options, you'll need to get the options one more time before you perform the operation. For example, if you had a "Save" button, you should check extract the colour settings for which node is selected on the left. This is to capture any changes that the user may have made that the listener has not captured (since the listener is triggered only when the left hand selection changes).
If you need an example, I've written one at http://www.box.net/shared/hgbet4uf6k.