DefaultTreeCellRenderer not working as expected - java

I'm being crazy because I don't understand what I'm doing wrong. I need that each node of my Tree have a different icon as if it is correct, incorrect or needs updating. I saw the Oracle Documentation and a lot of webpages (including Stackoverflow) but my Code just show all the nodes with the same icon. I'm sorry if I did something wrong, it's my first POST :>
Display:
I can't show because i no have reputation >.<
Imagine a tree and imagine that it show always the leafIcon with the gifNew icon. It seems as if only the state would listen to the last node.
Here's the code (all the vars are correctly created, icons like gifNew too):
ICONS:
static Icon closedIcon = new ImageIcon("folder.png");
static Icon openIcon = new ImageIcon("folder.png");
static Icon leafIcon = new ImageIcon("file.png");
static Icon gifWarn = new ImageIcon("warn.gif");
static Icon gifOk = new ImageIcon("ok.gif");
static Icon gifNew = new ImageIcon("plus.gif");
static Icon gifError = new ImageIcon("error.gif");
Call:
tree.setCellRenderer(new TreeRenderer());
Renderer:
private static class TreeRenderer extends DefaultTreeCellRenderer {
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel, boolean exp, boolean leaf, int row, boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, sel, exp, leaf, row, hasFocus);
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
String s = node.getUserObject().toString();
String error;
if (actualTree.equals("DOORS")){
error = checkTypeError(s, valuesClass.listOfValuesDOORS);
//System.out.println("DOORS - S: "+s);
}else{
error = checkTypeError(s, valuesClass.listOfValuesTC);
//System.out.println("TC - S: "+s);
}
switch (error) {
case "CORRECT":
setOpenIcon(openIcon);
setClosedIcon(closedIcon);
setLeafIcon(leafIcon);
break;
case "CREATE":
setOpenIcon(gifNew);
setClosedIcon(gifNew);
setLeafIcon(gifNew);
break;
case "DELETE":
setOpenIcon(gifError);
setClosedIcon(gifError);
setLeafIcon(gifError);
break;
case "UPDATE":
setOpenIcon(gifWarn);
setClosedIcon(gifWarn);
setLeafIcon(gifWarn);
break;
default:
setOpenIcon(openIcon);
setClosedIcon(closedIcon);
setLeafIcon(leafIcon);
//System.err.println("ERROR IN RENDERER. VALUE: "+error);
break;
}
return this;
}
/*****************************************
* Function that return which error have the actual node to push the icon when the tree is created.
*****************************************/
protected static String checkTypeError(String txt, List<valuesClass> list){
for (int i = 0; i < list.size(); i++) {
if (list.get(i).text.equals(txt))
if (list.get(i).create == true){
return "CREATE";
}else if (list.get(i).delete == true){
return "DELETE";
}else if (list.get(i).update == true){
return "UPDATE";
}else{
return "CORRECT";
}
}
return "DEFAULT";
}
}

The behaviour you are describing is caused by the fact that you are not setting correctly the node icon in the switch statement. The setOpenIcon(), setClosedIcon() etc set the icons that the renderer will use for the whole tree. So the action taken in the last node is going to decide what icons will be rendered at the end.
The DefaultTreeCellRenderer extends a JLabel. This component will be used for each node to render its contents. It is this components' icon that needs to be set i.e. your code should look like this:
switch (error) {
case "CORRECT":
setIcon(leafIcon); // sets the icon of the renderer which is a JLabel
break;
case "CREATE":
setIcon(gifNew);
break;
case "DELETE":
setIcon(gifError);
break;
...
}
Be sure to set the icon in all cases though and make sure that you understand how the renderer is used to render tree nodes (the same instance is reused for all nodes)

Strings are allowed in switch statements in Java 7, and while I haven't used them yet, your syntax looks correct. I suspect that the values of error String are not what you expect.
Since the case values are all upper case, change the line
switch (error) {
to
switch (error.toUpperCase()) {
and see if that solves it. If it doesn't, then print out the value of error, or use the debugger to check it's value.
EDIT: following our discussion below, I suspect that your tree nodes are DefaultMutableTreeNode objects (is that right?) and that you are storing data in the user object.
In that case, cast the value to DefaultMutableTreeNode, and extract your data:
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
MyData myData = (MyData) node.getUserObject();
You can then test myData to work out what icon to set.

Related

ListCellRenderer, selected value not visible

I have JComboBox where I apply ListCellRenderer as following:
colorList = new JComboBox<>(COLORS_NAMES);
ColorComboBoxRenderer renderer = new ColorComboBoxRenderer(colorList);
renderer.setColors(COLORS);
renderer.setColorNames(COLORS_NAMES);
colorList.setRenderer(renderer);
it has result in modyfing cells, but I can't find reason why selected value is remembered but not pictured. Like following:
Here is my code for renderer ( omitting setColors, getColors etc..)
class ColorComboBoxRenderer extends JPanel implements ListCellRenderer{
JPanel textPanel;
JLabel text;
public ColorComboBoxRenderer(JComboBox combo){
textPanel = new JPanel();
textPanel.add(this);
text = new JLabel();
text.setOpaque(true);
text.setFont(combo.getFont());
textPanel.add(text);
}
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
if (isSelected){
list.setSelectionBackground(colors[list.getSelectedIndex()]);
}
else{}
if(colors.length != colorNames.length){
System.out.println("colors.length doesn't match colorNames.length");
return this;
}
else if(colors == null){
System.out.println("Set colors by setColors first.");
return this;
}
else if(colorNames == null){
System.out.println("Set colorNames by setColorNames first.");
return this;
}
text.setText(" ");
if(index > -1){
text.setBackground(colors[index]);
text.setText(" ");
}
return text;
}
}
What also confuses me is that if(isSelected) block is done everytime I point cursor on specified cell, but my intuition would rather expect that happen when cellHasFocus param is true.
Thanks in advance, as I am struggling with it since 2 days ;/
EDIT 1
Added JComboBox field to ColorComboBoxRenderer class, and initializes it in constructor:
private JComboBox comboBox;
public ColorComboBoxRenderer(JComboBox combo) {
this.comboBox = combo;
//rest of code as it was
}
Changed that:
if(isSelected){
list.setSelectionBackground(colors[list.getSelectedIndex()]);
}
To:
if (isSelected){
list.setSelectionBackground(colors[list.getSelectedIndex()]);
comboBox.setBackground(colors[list.getSelectedIndex()]);
}
Results in:
Now the effect is better, so maybe u have an idea how to change JComboBox background but do not affect dropdown arrow?
In EDIT 1 it is important that we did edit ComboBox, it is necessary, because ListRenderer just generates dropDown list and its cells, but wouldn't affect ComboBox fields. So what was necessary and I finally found it, was quite brute force approach. I changed whole ComboBox background when selected as in EDIT 1 but then returned Arrow State, which is at Index (0) of JComboBox. Finally that section of code should be like this:
if (isSelected){
list.setSelectionBackground(colors[list.getSelectedIndex()]);
comboBox.setBackground(colors[list.getSelectedIndex()]);
comboBox.getComponent(0).setBackground(new JButton().getBackground());
}
Now everything works as designed:

How to update JList while adding or removing elements with using DefaultListModel()

i know this question asked many times before. However, i spent on hours to research about a way to update a JList, and i couldn't handle with this issue. I'm trying to implement a JList which shows who is online or offline.(It holds JLabels i guess this is the only way for holding a string with an icon). I have my own CellRenderer() which is like;
public class UserRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list, Object value,int index, boolean isSelected, boolean hasFocus) {
if(value instanceof ClientObject){
final ClientObject clientObject = (ClientObject) value;
JLabel label = (JLabel) super.getListCellRendererComponent(list, clientObject.getNickName(), index, isSelected, hasFocus);
if(clientObject.isIsOnline()){
label.setIcon(iconArray[1]);
}
else{
label.setIcon(iconArray[0]);
}
return label;
}
else {
return super.getListCellRendererComponent(list, value, index, isSelected, hasFocus);
}
}
}
Moreover, i construct client's list whenever he/she gets connected to server with this way;
private void buildBuddyList(ClientObject tempClientObject){
if( tempClientObject.getBuddyList().size() > 0 ){
mainClient.setBuddyList(tempClientObject.getBuddyList());
for (Iterator<ClientObject> iter = mainClient.getBuddyList().iterator(); iter.hasNext();) {
ClientObject tempon = iter.next();
if(tempon.isIsOnline()){
model.addElement(tempon);
labelIconList.put(tempon, iconArray[1]);
}
else{
model.addElement(tempon);
labelIconList.put(tempon, iconArray[0]);
}
}
}
}
The trick which i use when a client changed his/her status (becomes online/offline) is i get rid off all elements with model.clear() and start to construct the list again. Here is the code segment;
if(tempClientObject.isStatusChanged()){
if(tempClientObject.isIsConnected()){
System.out.println(tempClientObject.getUserName() + " is ONLINE");
model.clear();
for (Iterator<Map.Entry<ClientObject,ImageIcon>> iter = labelIconList.entrySet().iterator(); iter.hasNext();) {
Map.Entry<ClientObject,ImageIcon> pairs = iter.next();
ClientObject changedOnlineStatusClient = (ClientObject) pairs.getKey();
if(changedOnlineStatusClient.getUserName().equals(tempClientObject.getUserName())){
changedOnlineStatusClient.setIsOnline(tempClientObject.isIsOnline());
}
model.addElement(changedOnlineStatusClient);
}
}
else{
System.out.println(tempClientObject.getUserName() + " is OFFLINE");
model.clear();
for (Iterator<Map.Entry<ClientObject,ImageIcon>> iter = labelIconList.entrySet().iterator(); iter.hasNext();) {
Map.Entry<ClientObject,ImageIcon> pairs = iter.next();
ClientObject changedOnlineStatusClient = (ClientObject) pairs.getKey();
if(changedOnlineStatusClient.getUserName().equalsIgnoreCase(tempClientObject.getUserName())){
changedOnlineStatusClient.setIsOnline(tempClientObject.isIsOnline());
}
model.addElement(changedOnlineStatusClient);
}
}
}
I can assure that logical system works fine.(I can check the actions if they are working properly on background). Only the problem is sometimes when a client connected to server JList looks blank even though it adds elements into model. i will appreciate for every answer. And thanks anyway
only comment, not an answer
there no require for one dimensional JList
if(value instanceof ClientObject){
because Object from
getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean hasFocus) {
returns the same value, then to test this value if == or equeals ...
First of all thanks for all your replies. On the other hand, i corrected my issue with creating a new model whenever it has to be get updated. So the code segment is like this;
DefaultListModel tempModel = new DefaultListModel();
// add or remove elements from tempModel
buddyList.setModel( tempModel );
i'm not sure about if it is the only correct way but at least it works.
Call model.fireContentsChanged() method.
JavaDoc on AbstractListModel

SWT - ComboBoxCellEditor / Default Value

I would like for my ComboBoxCellEditor to be able to have 3 selections possible. Right now it only has Yes or No. I would like for it to have Yes, No, Both.
Also the combobox selection values does not show up in the table unless the cell is clicked. It is hard to tell if the table cell has a selection possible unless they click in the empty cell. I would like it to at least show the down arrow.
I have read some where that the only way you can get around this is to set a default value.
I am not sure how to add the 3rd value. I will add my code trying to add the 3rd value
How can a get the combobox show up in the table without the cell having to be clicked first?
.
public class OptionEditingSupport extends EditingSupport {
private ComboBoxCellEditor cellEditor;
public OptionEditingSupport(ColumnViewer viewer) {
super(viewer);
cellEditor = new ComboBoxCellEditor(((TableViewer)viewer).getTable(), new String[]{"Yes", "No", "Both"}, SWT.READ_ONLY);
}
protected CellEditor getCellEditor(Object element) {
return cellEditor;
}
protected boolean canEdit(Object element) {
return true;
}
protected Object getValue(Object element) {
return 0;
}
protected void setValue(Object element, Object value)
{
if((element instanceof AplotDatasetData) && (value instanceof Integer)) {
Integer choice = (Integer)value;
String option = (choice == 0? "Yes":"No":"Both"); **<- Error Here
((AplotDatasetData)element).setMarkupValue(option);
getViewer().update(element, null);
}
}
}
The conditional operator
x ? y : z
is a ternary operator, which internally does:
if(x)
y;
else
z;
Thus, you can only use it with three components. Use an if else if else instead:
Integer choice = (Integer)value;
String option = "";
if(choice == 0)
option = "Yes";
else if(choice == 1)
option = "No";
else
option = "Both";
TableEditor can be used to show any Widget on top of Table Cell. It should solve your problem with showing Combobox to let user know there is selection possible for that row and column.
I am not sure I understand your question about 3 selections.

JList pre/post rendering hook?

I am doing custom rendering in a JList. My custom ListCellRenderer uses a static String so that it can test the value of a particular variable against the previous occurance of that variable.
private static String lastUsername = "";
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
User user = (User)value;
if (lastUsername == user.getUsername()) {
// Do something
} else {
// Do something else
lastUsername = user.getUsername();
}
Now, that works fine when the program first loads but if I then scroll the list it causes problems as the lastUsername variable is still set to the last username it encountered when in fact it should be an empty string. Basically lastUsername needs to be reset to an empty string before or after all the cells have been rendered. Does anyone know if there is an JList post/pre AllCellsRendered event/hook that I can override to achieve this?
Common mistake to compare String objects with == instead of equals. Try if (lastUsername.equals( user.getUsername() )) instead.

HTML Well-formedness parser

Heyy guys, I need to determine if a given HTML Document is well formed or not.
I just need a simple implementation using only Java core API classes i.e. no third party stuff like JTIDY or something.
Actually, what is exactly needed is an algorithm that scans a list of TAGS. If it finds an open tag, and the next tag isn't its corresponding close tag, then it should be another open tag which in turn should have its close tag as the next tag, and if not it should be another open tag and then its corresponding close tag next, and the close tags of the previous open tags in reverse order coming one after the other on the list. If the list conforms to this order then it returns true or else false. I've already written methods to convert a tag to a close tag.
Here is the skeleton code of what I've started working on already. Its not too neat, but it should give you guys a basic idea of what I'm trying to do.
public boolean validateHtml(){
ArrayList<String> tags = fetchTags();
//fetchTags returns this [<html>, <head>, <title>, </title>, </head>, <body>, <h1>, </h1>, </body>, </html>]
//I create another ArrayList to store tags that I haven't found its corresponding close tag yet
ArrayList<String> unclosedTags = new ArrayList<String>();
String temp;
for (int i = 0; i < tags.size(); i++) {
temp = tags.get(i);
if(!tags.get(i+1).equals(TagOperations.convertToCloseTag(tags.get(i)))){
unclosedTags.add(tags.get(i));
if(){
}
}else{
return true;//well formed html
}
}
return true;
}
Two thoughts. First off maybe you could get away with using an XML parser on the html? Potentially easier and vastly less time consuming.
I havn't put a whole lot of thought into this but to me it sounds like recursion and stack would be the way to go. Something like
public myClass(String htmlInput)
{
openedTags = new Stack<String>();
this.htmlInput = htmlInput;
}
public boolean validate()
{
return validate(this.htmlInput);
}
private boolean validate(String html)
{
boolean result = true;
String curTag;
while(htmlLeft) //worker loop
{
if(isOneOffTag(curTag)) //matches <tags />
continue;
else if(isOpenTag(curTag)) //matches <tags>
{
openedTags.push(curTag);
if(!validate(innerHtml))
return false;
}
else if(isCloseTag(curTag)) //matches </tags>
{
String lastTag = (String)openedTags.peek();
if(!tagIsSimiliar(curTag, lastTag))
return false;
openedTags.pop();
}
}
return result;
}
private String nextTag(){return null;}
private boolean isOpenTag(String tag){ return true;}
private boolean isCloseTag(String tag){ return true;}
private boolean isOneOffTag(String tag){ return true;}
private boolean tagIsSimiliar(String curTag, String lastTag){return true;}
*edit 1: probably should have pushed onto the stack.
**edit 2: I suppose the issue here would be to determine where when returning solely a boolean you've left off. This would require some kind of pointer so that you know where you've left off. The idea though i believe would still work.

Categories