In the program I'm writing, I have a JTree storing some objects of my own design. I made my own extension of DefaultTreeCellRenderer and overrode getTreeCellRendererComponent to return a JPanel with some buttons and things. What I found was that the buttons I added didn't act like buttons, which makes think that interaction with the components is being "stolen" by the tree cell. (If you click on the button, the container surrounding the button is also being clicked on, and the tree has its own response to being clicked.)
So my question is this:
If what I want is the basic functionality of a tree, plus some buttons, what approach should I use?
Continue on the same route; add a mouse listener of some kind to manually add the functionality to the button.
Continue on the same route; remove the existing mouse listener and add your own to achieve the right behavior.
Extend or implement a slightly different class or interface than you did - maybe not DefaultMutableTreeNodes, maybe not DefaultTreeCellRenderer, etc. - use the existing XXXX to do what you're trying to do.
Avoid using JTree; make your own, it's not that hard.
I'm leaning toward the last option - there's a decent chance I don't actually want the folding behavior of a tree anyway, so I may just make my own structure. However, even if I choose that option, I'd like to know what I should have done.
You'll also need a TreeCellEditor, illustrated here.
Avoid using JTree; make your own, it's not that hard
I wish you good luck wit that ;-)
What is happening is that the components returned by the renderer are only used as a 'stamp'. So the JTree does not really contain the returned components, they are only painted. Hence no interaction with your button. It only looks like a button. It seems the JTree tutorial does not contain a real section on this, but it is basically the same concept as for tables, which is explained in the 'Renderers and editors' part of the tutorial.
That also explains why a typical renderer class extends JLabel and can simply use return this after it made customizations to itself, without affecting the other nodes in the tree. For example the source code of the DefaultTreeCellRenderer, which extends JLabel, contains
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel,
boolean expanded,
boolean leaf, int row,
boolean hasFocus) {
//...
setText(stringValue);
//...
return this;
}
How to fix this: create an editor as well, as suggested by #trashgod
Related
I'm working on my custom ColorChooserPanel class, but I don't know how to create a ColorSwatch.
I found a class named ColorSwatch or something like that but its package private and I can't access it.
How can I ensure that I have a proper color chooser?
First, you need to think about the way this should work, to formulate your goals into action points that you can always check and see whether and how they are fulfilled:
it should be displayed
it should handle click events
it should be able to return a color (the last chosen color, or a default in lack of that)
Now, a very common way of supporting color choosers is to have something like in this image:
However, this is way too complex for a first implementation. You should first have something which "works", that is, you are able to choose colors to taste success and then work out the subsequent details. Unless you say otherwise, I'm assuming that the Basic colors section is good for now. In that case, you can create a class, which contains a JPanel, containing clickable elements. Your class needs to have a Color member, which one can get calling a getter and which is set when a clickable item inside your JPanel is clicked. The clickable items can be JPanels on their own, for example.
If you prefer something ready-made, then kindly read these:
https://docs.oracle.com/javase/tutorial/uiswing/components/colorchooser.html
https://coderanch.com/t/332515/java/Color-Palette
I'm using a JFace TreeViewer object in my Eclipse RCP ViewPart, and I'd like to add some additional information to the label on some of my nodes by way of an image.
Essentially the image should sit to the right of the label text and will represent a rating (I'm thinking 1 - 5 stars)
If there's a way to do this I can't find it, does anybody know of one?
If not then does anyone know how the eclipse package explorer shows the different coloured extra info when using other plugins like Subclipse? I guess if I'm forced to I could use that and the "*" character? ( I have tried to look at the source but it's very abstracted and a little beyond me at the moment, so I'm just asking if anyone knows off hand, I'm not asking anyone to dig through the source for me)
Regards,
Glen
x
You can custom-draw tree items by adding SWT.MeasureItem and SWT.PaintItemlisteners to the tree. Check out example 5 in this tutorial.
In order to get the selection highlight painted over the extended area, add also SWT.EraseItem listener and update event.width.
Are you using the PackageExplorer or your own TreeViewer ?
1.PackageExplorer: You need to extend the ui decorator.
<extension point="org.eclipse.ui.decorators">
<decorator
adaptable="true"
class="org.example.com.PackageExplorerDecorator"
id="org.example.filedecorator"
label="File Decorator"
lightweight="true"
state="true">
<enablement>
<or>
<objectClass
name="org.eclipse.jdt.core.IMethod">
</objectClass>
<objectClass
name="org.eclipse.core.resources.IResource">
</objectClass>
</or>
</enablement>
The class should look like this:
public class PackageExplorerDecorator extends LabelProvider implements ILightweightLabelDecorator {
#Override
public void decorate(final Object resource, final IDecoration decoration) {
decoration.addSuffix(..)
decoration.addPrefix(..)
}
}
2. TreeViewer: You can try to create custom Widget, or just create TreeViewer with multiple columns ( First one for the tree and the second one for the stars).
This and this might be for you useful.
I have been looking into JTree and TreeCellRenderer. It seems in general, the application (with one JTree) has only one instance of TreeCellRenderer. The application makes multiple calls to TreeCellRenderer's getTreeCellRendererComponent method to decide how each TreeCell is drawn, and such call are made in many occasions (when a cell is selected, deselected, move over, when scrolling, etc.). Why did they decide to do that instead of having multiple instances of TreeCellRenderer, each responsible for one cell??
I am trying to make a JTree where each cell contains a checkbox. The checkbox can be checked/unchecked by the user. Then, the TreeNode userObject's values are set base on the state of these checkboxes. But, from the current JTree design this is impossible - since there is only one instance of JCheckBox, and is only used to show how the Cell looks like (you can't really check it). In some sense I want to separate selection of the TreeCell and the checking of the boxes.
I have some workarounds (implementing MouseAdapter and checking if the mouse click is close by where the checkbox is rendered, then emulate a check on the box by changing its appearence in TreeCellRenderer), but still I want to know if this can be done more directly. Thanks!
Why did they decide to do that instead of having multiple instances of TreeCellRenderer, each responsible for one cell?
This is a nice example of the flyweight pattern.
For a check box tree, I like org.netbeans.swing.outline.Outline, mentioned here, but other examples are available.
Addendum: Reading your question more closely, you ask:
In some sense I want to separate selection of the TreeCell and the checking of the boxes.
This is the correct instinct: The data (checked or unchecked) should be stored in the model (TreeModel), not the view (JCheckBox). The example uses instances of CheckBoxNode in it's (implicit) model, accordingly.
Sorry for the odd choice of words for the title, however, "border" seems to be the inappropriate term. While it is true that the visible line surrounding an icon in a JToggleButton can be made invisible by using setBorderPainted(false), the same is not true for JCheckBox and JRadioButton.
I can not use the JToggleButton and therefore need to use either the JCheckBox or JRadioButton (or some derivative of JToggleButton I am not aware of), but need the square or circle, respectively, to be non-visible when there is no icon on the button. Also, using setVisible(false) eliminates the button from the layout, however, I need the space to be reserved and not have the component layout change (using GroupLayout).
Any suggestions? Am I going to have to create a custom renderer? I will be looking at that in the mean time.
The route into this would be through customising the look at feel by changing some of the UI properties in the UImanager (the sort of thing that allows you to make simple tweaks with fonts and colours and presumably the images used for the checkboxes or radiobuttons) -- but it's many years since I last did that sort of thing and can't remember the details.
A little Googling turned up this project to inspect current property values, so might at least help with indicating the right part of the APIs to be looking at.
You have to choices here:
1) Customize Look and Feel as described in previous entry.
2) Create your own custom controls by inheriting from existing ones and overriding component painting.
I found a cheap and easy (read hack) for this. I created an empty transparent icon and used it when I didn't want any item to be displayed.
I'm developing a grid based sim game in java, and I was wondering if there is a standard way of doing the following.
I have a panel which is the game panel, and there are many different things which could happen when the panel is clicked. For example, when building a room, there are several stages, where dragging the mouse and left clicking will have different actions.
Right now, the way I have done it, is to use booleans to check what's being built, and then what stage it is at.
Is there any better or standard way of handling something like this? I had a quick google, but as I have said before, people on Stack Overflow always give a better, more relevant, up to date answer.
I consider myself still rather new to java.
Thanks in advance.
You might try looking into something similar to the strategy pattern.
Basically, you start by clicking the room button on your toolbar. The toolbar goes through and tells the grid to use the 'room place' actionlistener. Presumably removing any previous action listener that was listening
The room place actionlistener would in turn implement all the interesting bit of logic for left/right clicking, dragging, etc.
If you have multiple stages to building a room (say, placing doors, then windows, then trap doors); the action listeners would be responsible for handing control off to the next stage: a bit of a finite state machine.
So, start by clicking 'room' button, 'place room' listener is added. Drag out the area you want the room to be, 'place room' modifies the game state, then changes the actionlistener to the 'place windows' listener. Ad infinitum... until you finish.
One very simple (non compilable) example:
class GridPanel extends JPanel
{
void SetMouseListener(MouseListener newListener)
{
for(MouseListener ml : getMouseListeners())
removeMouseListener(ml);
addMouseListener(newListener);
}
}
class ControlPanel extends JPanel
{
GridPanel gameGrid;
void OnRectangleButtonClicked(some stuff)
{
gameGrid.SetMouseListener(new PlaceRoomListener(gameGrid));
}
}
class PlaceRoomListener extends MouseAdapter
{
GridPanel gameGrid;
//constructor, etc
void OnClick(mouse event)
{
gameGrid.doCoolStuff();
gameGrid.SetMouseListener(new PlaceTrapDoorListener());
}
}
//etc
Now, that non-compilable example aside, Pyrolistical does have a point: you generally don't want to combine your game model and graphic interface into one single glob of classes. You want the model separated from the GUI, and to manipulate it through a well defined interface.
(Also, there are probably better methods for going about removing the mouse listener then just randomly removing all listeners... I was in a bit of a rush, sorry)
It sounds like you need to define your game model/state and keep it separate from your mouse actions.
Are you using MVC?