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:
Related
I have a java JPanel with 16 JCheckBoxes and I am wanting to ensure that the user selects at least one before submitting the form. The only way I know to do this is a huge if statement that looks at the Boolean value of the "isSelected()" method, but this seems inefficient.
So I was wondering if there was a faster to way to check if all of the boxes are unchecked.
You don't need an if statement. You can do it with a big logical expression using ||:
boolean somethingChecked = box1.isSelected()
|| box2.isSelected()
|| ...;
or, if the boxes are in an array (much preferred), a loop:
boolean somethingSelected = false;
for (JCheckBox box : boxes) {
if (box.isSelected()) {
somethingSelected = true;
break;
}
}
Alternatively, you can use an ItemListener attached to each JCheckBox to track the count of checked boxes:
int selectionCount;
ItemListener boxListener = new ItemListener() {
#Override public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
selectionCount++;
} else {
selectionCount--;
}
}
};
(Note that if this is all that the ItemListener is doing, a single instance can be attached to all the boxes.) The selectionCount should be initialized to the number of boxes initially checked. Then at the appropriate point(s) in your code, you can simply test whether selectionCount is greater than zero.
This will do the trick I believe:
public boolean validatePanel(JPanel panel) {
for (Component component : panel.getComponents()) {
if(component instanceof JCheckBox){
JCheckBox c = (JCheckBox) component;
if(c.isSelected()){
return true;
}
}
}
return false;
}
That method receives a JPanel and get all the components on it. Then check all of then, if it's a checkbox will cast the Component to CheckBox to have access to isSelected method. If any checkbox is selected it will return true, if it finish the foreach without returning any true it means that no checkbox were selected.
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.
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
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.
I use a JTable which has its own cell renderer and cell editor.
Say, this table contains 2 columns and x rows:
The first column contains a boolean value, its own cell rendering and cell editor (a radiobutton)
The second column contains a string value, its own cell renderer: it makes it bold when the first column of the current row is set to true (radiobutton checked)
All the values are correctly updated by the editor but the 2nd row does not become bold when the radio button is set to true...
I have to check a radio button from a different row to see the changes
Where can I fire thoses changes ?
Cheers and thanks for your help
RadiobuttonTableCellEditor.java
public class RadiobuttonTableCellEditor extends DefaultCellEditor
implements ItemListener {
JRadioButton rb = new JRadioButton();
public RadiobuttonTableCellEditor(JCheckBox pCheckBox) {
super(pCheckBox);
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if (value == null)
return null;
rb.addItemListener(this);
rb.setSelected((Boolean)value);
return rb;
}
public void itemStateChanged(ItemEvent e) {
super.fireEditingStopped();
}
public Object getCellEditorValue() {
rb.removeItemListener(this);
return rb.isSelected();
}
}
In your table model whenever your value changes you have to fire appropriate event. If your model is inherited from AbstractTableModel you can use several fireXXX methods. My guess is you should call them from setValueAt method.
If you know exact column and row - you can call fireTableCellUpdated, otherwise you can you probably have to use fireTableChanged since you have to update different column.
And of course you renderer should properly render new value.
It doesn't seem to make any sense to extend DeafultCellEditor there. Implementing a listener interface like that is also not a great idea.
Renderers work best as a thin layer. If another cell should change, then that needs to be reflected in the table model which should fire a relevant update event.
I guess it could help people with a similar problem, make a true radiobutton unique in a row, you'll have to extend the DefaultTableModel to modify its behaviour especially the setValueAt method
Cheers
/**
* When <code>column</code> is the column that contains the Boolean (in fact the radio button):
* If aValue == false and that it had a previous value set to true we don't do anything
* If aValue == true and that it had a previous value set to false, we set all the other booleans to false and this one to true
*/
#Override
public void setValueAt(Object aValue, int row, int column) {
if (column == colonneBoutonradio)
{
if (((Boolean)aValue && !(Boolean)super.getValueAt(row, column)))
for (int i = 0; i < this.getRowCount(); i++)
// i==row permet de vérifier si la ligne courante est celle à modifier (et donc celle à mettre à true)
super.setValueAt(i==row, i, colonneBoutonradio);
}
else
super.setValueAt(aValue, row, column);
}