# Checkbox in Liste deaktivieren und paintComponent explizit aufrufen



## carolin (30. Sep 2010)

Hallo,

ich habe zwei Probleme, für ich bis jetzt zwar Ansätze habe, aber keine wirkliche Lösung gefunden habe.

Problem 1:
Ich habe eine Liste aus Checkboxen. Dafür habe ich im WWW ein Beispiel gefunden und übernommen. Der Code ist der folgende:

[JAVA=42]package client;

import java.awt.Component;

import javax.swing.JCheckBox;
import javax.swing.JList;
import javax.swing.ListCellRenderer;

/**
 * @author 
 *         How do add a checkbox to items in a JList? | web development helpdesk
 *         a-jlist
 * 
 */
public class CheckListItem {

	private static final long serialVersionUID = 1L;
	private String label;
	private boolean isSelected = false;

	public CheckListItem(String label) {
		this.label = label;
	}

	public CheckListItem(String label, boolean isSelected) {
		this.label = label;
		this.isSelected = isSelected;
	}

	public boolean isSelected() {
		return isSelected;
	}

	public void setSelected(boolean isSelected) {
		this.isSelected = isSelected;
	}

	public String toString() {
		return label;
	}
}

// Handles rendering cells in the list using a check box

class CheckListRenderer extends JCheckBox implements ListCellRenderer {

	private static final long serialVersionUID = 1L;

	@Override
	public Component getListCellRendererComponent(JList list, Object value,
			int index, boolean isSelected, boolean hasFocus) {
		setEnabled(list.isEnabled());		
		setSelected(((CheckListItem) value).isSelected());
		setFont(list.getFont());
		setBackground(list.getBackground());
		setForeground(list.getForeground());
		setText(value.toString());
		return this;
	}


}
[/code]

Ein einzelner Eintrag mit einer Checkbox wird durch ein CheckListItem repräsentiert. Ich möchte jetzt zusätzlich ein einzelne CheckListItem deaktivieren können. Ich hab schon hinten und vorne mit dem CheckListRenderer rumgespielt, leider erfolglos. Hat jemand eine Idee, wie ich das Problem lösen kann?

Problem 2:

Ich lade auf ein JPanel ein JPG als Hintergrund und zwar in dem ich paintComponent dieses JPanel überschreibe. Das gewünschte Bild wird über einen JFileChooser ausgewählt. Das funktioniert auch alles, das einzige Problem ist, dass ich es nicht hinbekomme, dass das Bild direkt nach dem Schließen des JFileChoosers mit "ok" angezeigt wird. Das passiert erst, wenn ich das Fenster verändere oder ähnliches. Nach Suche im WWW habe ich versucht mit paint() die paintComponent() auszulösen, die Verzögerung bleibt aber leider. Gibt es irgendeine Möglichkeit meine paintComponent() direkt nach dem Abschließen der Bildauswahl aufzurufen?

Danke schonmal.

Gruß,

Carolin


----------



## Michael... (30. Sep 2010)

Zu Problem 1. 
Genauso wie mit dem isSelected kannst Du Deinem Item ein zusätzliches Attribut wie z.B. isEnabled verpassen, das Du im Renderer auswertest:


carolin hat gesagt.:


> [JAVA=93]setEnabled(((CheckListItem) value).isEnabled());
> setSelected(((CheckListItem) value).isSelected());
> [/code]


Es macht dann naturlich Sinn das value Objekt nur einmal zu casten.

Zu Problem 2:
mittels der Methode repaint() kann man eine Neuzeichnen der Komponente anfordern.


----------



## carolin (30. Sep 2010)

Danke für deine Antwort.



Michael... hat gesagt.:


> Zu Problem 1.
> Genauso wie mit dem isSelected kannst Du Deinem Item ein zusätzliches Attribut wie z.B. isEnabled verpassen, das Du im Renderer auswertest:



Schon versucht, ich kann trotzdem die Checkbox auswählen bzw. wieder abwählen.


QUOTE=Michael...;681137]
Zu Problem 2:
mittels der Methode repaint() kann man eine Neuzeichnen der Komponente anfordern.[/QUOTE]

Auch schon versucht (ich habe mich oben verschrieben, ich meinte natürlich repaint(), verzeihung) und ich habe trotzdem noch eine Verzögerung. Erst wenn ich bspw. die Größe des Fenster ändere, wird das Bild angezeigt.


----------



## KrokoDiehl (30. Sep 2010)

Hallo. Das ist nun zwar hässlicher Code (ich rede von mir  ), aber das "disablen" von CheckBoxen im Renderer geht prinzipiell (siehe mein Beispiel).
Es ist daher nur eine Sache vom Modell die entsprechende Information zum Renderer zu liefern.

```
public class Dummy
{
    public static void main( String[] args )
    {
        DefaultListModel model = new DefaultListModel();
        model.addElement("Hallo");
        model.addElement("Huhu");
        model.addElement("Gruezi");
        model.addElement("Tach");
        
        JList l = new JList(model);
        l.setCellRenderer(new ListCellRenderer()
        {
            private final JCheckBox box;
            
            {
                box = new JCheckBox();
            }
            
            @Override
            public Component getListCellRendererComponent( JList list, Object value,
                    int index, boolean isSelected, boolean cellHasFocus )
            {
                box.setEnabled( (index % 2 == 0) );
                box.setSelected( (index % 2 == 1) );
                box.setFont(list.getFont());
                
                if (isSelected)
                {
                    box.setBackground(list.getSelectionBackground());
                    box.setForeground(list.getSelectionForeground());
                }
                else
                {
                    box.setBackground(list.getBackground());
                    box.setForeground(list.getForeground());
                }
                box.setText( value.toString() );
                
                return box;
            }
        });
        
        
        final JFrame f = new JFrame("test");
        f.add(new JScrollPane(l));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }
}
```

Aber ich muss nochmal nachfragen, nicht dass hier ein Missverständnis vorliegt ...


			
				carolin hat gesagt.:
			
		

> Schon versucht, ich kann trotzdem die Checkbox auswählen bzw. wieder abwählen.


... oder meinst du damit die Selektion einer disabledten CheckBox ( ...Herrgott, wie sagt man das denn in deutsch ???:L )?


----------



## Michael... (30. Sep 2010)

Entweder Du überprüfst in der setSelected() des Item, ob es deaktiviert ist und änderst die Selekion eben nicht oder Du machst es an der Stelle im Code bevor Du diese Methode an einem Item Objekt aufrufst.


----------



## carolin (30. Sep 2010)

KrokoDiehl hat gesagt.:


> Aber ich muss nochmal nachfragen, nicht dass hier ein Missverständnis vorliegt ...
> 
> ... oder meinst du damit die Selektion einer disabledten CheckBox ( ...Herrgott, wie sagt man das denn in deutsch ???:L )?



Ich möchte, dass ich keinen Haken mehr in die Box machen kann bzw. den Haken nicht entfernen kann, wenn die Box disabled ist. So wie es auch bei einzelnen Checkboxen möglich ist.

Ich habe ein lauffähiges Testprogramm geschrieben, das vielleicht ein wenig verdeutlicht was ich mache. Vielleicht liegt mein Fehler ja auch an einer anderen Stelle.

Die schon oben erwähnte CheckListItem-KLasse habe ich um isEnabled() und setEnabled() erweitert und den Vorschlag von Michael eingearbeitet:
 [JAVA=42]package checklist;

import java.awt.Component;

import javax.swing.JCheckBox;
import javax.swing.JList;
import javax.swing.ListCellRenderer;

/**
 * @author 
 *         How do add a checkbox to items in a JList? | web development helpdesk
 *         a-jlist
 * 
 */
public class CheckListItem {

	private static final long serialVersionUID = 1L;
	private String label;
	private boolean isSelected = false;
	boolean isEnabled = true;

	public CheckListItem(String label) {
		this.label = label;
	}

	public CheckListItem(String label, boolean isSelected) {
		this.label = label;
		this.isSelected = isSelected;
	}

	public boolean isSelected() {
		return isSelected;
	}

	public void setSelected(boolean isSelected) {
		this.isSelected = isSelected;
	}

	public String toString() {
		return label;
	}

	public boolean isEnabled() {
		return isEnabled;
	}

	public void setEnabled(boolean en) {
		this.isEnabled = en;
	}
}

// Handles rendering cells in the list using a check box

class CheckListRenderer extends JCheckBox implements ListCellRenderer {

	private static final long serialVersionUID = 1L;

	@Override
	public Component getListCellRendererComponent(JList list, Object value,
			int index, boolean isSelected, boolean hasFocus) {
		setEnabled(list.isEnabled());
		setEnabled(((CheckListItem) value).isEnabled());
		setSelected(((CheckListItem) value).isSelected());
		setFont(list.getFont());
		setBackground(list.getBackground());
		setForeground(list.getForeground());
		setText(value.toString());
		return this;
	}


}
[/code]

Meine Testklasse:
[JAVA=42]package checklist;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;


public class Main extends JFrame {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		new Main().initGui();
	}

	private JList list;

	public void initGui() {

		JPanel pane = new JPanel();

		CheckListItem one = new CheckListItem("One");
		CheckListItem two = new CheckListItem("Two");
		CheckListItem three = new CheckListItem("three");
		CheckListItem[] checkArray = new CheckListItem[3];
		checkArray[0] = one;
		checkArray[1] = two;
		checkArray[2] = three;

		list = new JList(checkArray);
		list.setCellRenderer(new CheckListRenderer());
		list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		list.addMouseListener(new CheckListListener());

		pane.add(list);

		JButton disable = new JButton("Disable");
		disable.addActionListener(new DisableButtonListener());
		pane.add(disable);

		this.add(pane);
		this.setSize(200, 200);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	public void disableList() {
		list.setEnabled(false);
		ListModel model = list.getModel();
		for(int i = 0; i < model.getSize(); i++) {
			CheckListItem itemS = (CheckListItem) model.getElementAt(i);
			itemS.setEnabled(false);
		}
	}

	class CheckListListener extends MouseAdapter {
		public void mouseClicked(MouseEvent event) {
			JList list = (JList) event.getSource();
			int index = list.locationToIndex(event.getPoint());
			CheckListItem item = (CheckListItem) list.getModel().getElementAt(
					index);
			item.setSelected(!item.isSelected());
			list.repaint(list.getCellBounds(index, index));
		}
	}

	class DisableButtonListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			disableList();
		}

	}

}
[/code]

Mit dem Disable-Button soll die Liste deaktiviert werden. Leider kann ich immernoch die Haken in die Checkboxen setzen und wieder entfernen. Das soll nicht möglich sein.
Natürlich ist es möglich wie du das vorgeschlagen hast, Michael. Ich werde das so umsetzen, wenn sich keine saubere Lösung findet, aber ich hoffe noch drauf, dass ich das noch anders hinbekomme.

Danke und Gruß


----------



## jgh (1. Okt 2010)

Da du -unabhängig davon- ob die List enabled, oder disabled ist, in deiner Klasse [c]CheckListListener [/c] die Selektion setzt...hilft dir evtl. folgendes Konstrukt:
Ob das sehr sinnig ist, lasse ich mal dahingestellt.. 


```
class CheckListListener extends MouseAdapter {
		public void mouseClicked(MouseEvent event) {
			JList list = (JList) event.getSource();
			if (list.isEnabled()) {
				int index = list.locationToIndex(event.getPoint());
				CheckListItem item = (CheckListItem) list.getModel()
						.getElementAt(index);
				item.setSelected(!item.isSelected());
				list.repaint(list.getCellBounds(index, index));
			}
		}
	}
```


----------



## KrokoDiehl (1. Okt 2010)

Ich stimme _jgh_ zu. Es liegt nicht am Renderer, sondern am MouseListener. Ich würde aber zusätzlich noch die _enabled_-Eigenschaft des geklickten _CheckListItems _prüfen:


```
class CheckListListener extends MouseAdapter {
        public void mouseClicked(MouseEvent event) {
            JList list = (JList) event.getSource();
            if (list.isEnabled()) {
                int index = list.locationToIndex(event.getPoint());
                CheckListItem item = (CheckListItem) list.getModel()
                        .getElementAt(index);
                if (item.isEnabled())
                {
                    item.setSelected(!item.isSelected());
                    list.repaint(list.getCellBounds(index, index));
                }
            }
        }
```

Außerdem wäre es "sauberer" das 
	
	
	
	





```
repaint()
```
 der Liste anders zu handhaben. Eigentlich müsste ein 
	
	
	
	





```
item.setSelected(dingens)
```
 genügen und dann müsste es intern über die _ListDataListener _weitergehen. Aber das nur am Rande.


----------



## carolin (1. Okt 2010)

Ja, das löst mein Problem.  Danke!



KrokoDiehl hat gesagt.:


> Außerdem wäre es "sauberer" das
> 
> 
> 
> ...


Ich war mir nicht sicher ob ich das brauche oder nicht. Danke, dass du diese Frage auch noch beantwortet hast. 

Hat auch noch jemand eine Idee zu meinem paintComponent()-Problem?


----------



## KrokoDiehl (1. Okt 2010)

Hm, ich bin mir nicht ganz sicher.
Du hast ein Panel, dass über 
	
	
	
	





```
paintComponent()
```
 ein Bild malt. Am Anfang hat es aber keines ja? Dann wird über einen FileChooser eines ausgesucht und nun müsste das Panel sich neu zeichnen? 
Warum kannst du kein JLabel verwenden und mit 
	
	
	
	





```
setIcon()
```
 arbeiten? Wenn man das Bild zur Laufzeit ändert, muss man ja ggfs. auch die Größe des Panels anpassen.
Probier mal ein 
	
	
	
	





```
myPanel.invalidate()
```
 oder 
	
	
	
	





```
myPanel.revalidate()
```
 ...


----------



## carolin (1. Okt 2010)

Ich habe deine Vorschläge ausprobiert, aber leider immer noch keinen Erfolg. Zur Verdeutlichung meines Problems habe ich ein kleines Testprogramm geschrieben. Meine eigentliche Implementierung läuft ein wenig anders ab (dort habe ich z.B. mein Panel in einem ScrollPane und das Bild kann nachträglich geändert oder gelöscht werden), aber ich denke, dass das für das Problem nicht ausschlaggebend ist.

Im Folgenden Code habe ich ein JPanel, das die paintComponent()-Methode überschreibt um ein Bild einzufügen. Dieses wird als String übergeben.

[JAVA=42]package jpanelpic;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class PicPanel extends JPanel {

	private String imagename = "";

	public void setImagename(String imagename) {
		this.imagename = imagename;
	}

	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		Image img = null;
		ImageIcon image = new ImageIcon(imagename);
		if (image != null) {
			img = image.getImage();

		}
		if (img != null) {
			g.drawImage(img, 0,0, this);
			this.setPreferredSize(new Dimension(img.getWidth(null), img.getHeight(null)));
		} else {

		}
	}
}
[/code]

In der Main-Klasse habe ich einen Button, wenn der betätigt wird, dann öffnet sich ein JFileChooser und es kann ein JPG ausgewählt werden. Wenn dieser mit "OK" abgeschlossen wird, dann wird das Panel erneut hinzugefügt mit diesem Bild. (Das ist etwas unsauber gelöst, aber wie gesagt ist es nur ein Testprogramm). 

[JAVA=42]package jpanelpic;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.filechooser.FileNameExtensionFilter;

public class Main extends JFrame {

	PicPanel pane;

	public static void main(String[] args) {
		new Main().initGui();
	}

	public void initGui() {
		pane = new PicPanel();

		JButton but = new JButton("Image");
		but.addActionListener(new ImageButtonListener());

		pane.add(but);

		this.add(pane);
		this.setSize(200, 200);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	public void setThePanel(String imagename) {
		pane.setImagename(imagename);
		this.add(pane);
	}

	class ImageButtonListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			final JFileChooser fc = new JFileChooser();
			FileNameExtensionFilter filter = new FileNameExtensionFilter(
					"JPG Images", "jpg");
			fc.setFileFilter(filter);
			int returnVal = fc.showOpenDialog(null);
			if (returnVal == JFileChooser.APPROVE_OPTION) {
				File file = fc.getSelectedFile();
				String imagename = file.getAbsolutePath();
				setThePanel(imagename);
			} else {

			}

		}

	}
}
[/code]

Jetzt taucht wie gesagt das Problem auf, dass ich das Main-Fenster aktualisieren will nachdem mein JFileChooser abgeschlossen ist und ich bis jetzt dafür keine Lösung gefunden habe. Ich hoffe, dass ein wenig deutlicher wird, was ich meine.

Danke und Gruß


----------



## jgh (2. Okt 2010)

carolin hat gesagt.:


> Ich habe deine Vorschläge ausprobiert, aber leider immer noch keinen Erfolg. Zur Verdeutlichung meines Problems habe ich ein kleines Testprogramm geschrieben. Meine eigentliche Implementierung läuft ein wenig anders ab (dort habe ich z.B. mein Panel in einem ScrollPane und das Bild kann nachträglich geändert oder gelöscht werden), aber ich denke, dass das für das Problem nicht ausschlaggebend ist.
> 
> Im Folgenden Code habe ich ein JPanel, das die paintComponent()-Methode überschreibt um ein Bild einzufügen. Dieses wird als String übergeben.
> 
> ...



und wie immer, wenn man aktualisieren will...ruft man repaint() und/oder validate() auf 
Bei dir langt hier repaint() in der setThePane-Methode


----------



## carolin (2. Okt 2010)

Okay, es hat geklappt. Ich habe repaint() immer an der falschen Stelle aufgerufen.
Danke!!


----------

