Swing FAQ
Bedoeling van dit topic is een aantal veelgestelde vragen ivm Java SWING op te lossen. Deze onderwerpen zullen telkens bestaan uit een korte vraag en antwoord, waarbij telkens in een klein demonstratie-programmaatje een voorbeeld wordt gegeven hoe men het probleem kan oplossen.
Deze faq zullen worden opgesteld adhv vragen gesteld in het forum, maar als je er nog andere bij wil zien: stuur je vragen gerust per PM of in dit topic, en ik zorg dat ze opgelost raken :D
Hoe kan ik een checkbox weergeven in een JTable?
antwoord:
Door de methode getColumnClass te veranderen is het mogelijk terug te sturen wat de klasse van de gegevens van een bepaalde kolom is. Op deze manier kan de default renderer enkele types van gegevens aangepast weergeven. In dit geval zal een java.lang.Boolean worden weergegeven als een checkbox. Zo zijn er ook nog voor aangepaste tijd weer te geven,...
Het resultaat ziet er dan als volgt uit:
De code:
PHP-code:
import javax.swing.*;
public class TableWithCheckbox extends JTable{
private int nrDeleteColumn = 0;
public TableWithCheckbox(Object[][] data, String[] kolomnamen){
super(data,kolomnamen);
}
//overriden zodat voor de delete-kolom de checkbox wordt getoond:
public Class getColumnClass(int column) {
Class dataType = super.getColumnClass(column);
if (column == nrDeleteColumn) {
dataType = java.lang.Boolean.class;
}
return dataType;
}
// Een voorbeeld main-methode voor het gebruik:
public static void main(String args[]){
String[] columnNames = { "Delete?", "Voornaam", "Achternaam" };
Object[][] values = {
{ new Boolean(true), "Marco","Pantani" },
{ new Boolean(false), "Roberto","Heras" },
{ new Boolean(true), "Jan","Ullrich" },
{ new Boolean(false), "Lance","Armstrong" },
};
TableWithCheckbox tabel = new TableWithCheckbox(values, columnNames);
JFrame frame = new JFrame();
frame.getContentPane().add(new JScrollPane(tabel),java.awt.BorderLayout.CENTER);
frame.setSize(300,300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Hoe kan ik meerdere lijnen in 1 JLabel weergeven?
antwoord:
Een van de handige features van Swing is dat z'n (meeste) componenten HTML-code kunnen parsen en weergeven. Het is van deze feature dat we gebruik zullen kunnen maken om meerdere lijnen weer te geven.
Je geeft gewoon de html-code op zoals je die zou gebruiken voor een normale webpagina, zo kun je <br> gebruiken om een nieuwe lijn aan te geven.
Volgende voorbeeld:
is bijvoorbeeld te verwezenlijken met volgende code:
PHP-code:
import javax.swing.*;
public class MultilijnLabelDemo {
public static void main(String args[]){
JFrame frame = new JFrame("Label demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200,200);
//label met multilijn tekst
JLabel label = new JLabel("<html>Eerste<br>Tweede<br>Laatste</html>");
//label toevoegen
frame.getContentPane().add(label);
//Venster tonen
frame.setVisible(true);
}
}
Hoe kan ik figuren in een JList weergeven?
antwoord:
We weten dat we in Swing gebruik kunnen maken van een JLabel om een tekst met een figuur ernaast weer te geven. De oplettende programmeur ziet in de API dat er een Object[] kan worden meegegeven als data :) Hij denkt dus: we geven een JLabel[] mee en dan worden die gebruikt als items.
Laten we dit even proberen:
PHP-code:
import javax.swing.*;
public class ImageList extends JList{
public ImageList(Object [] data){
super(data);
}
public static void main(String args[]){
JFrame frame = new JFrame("Lijst met figuren");
//We proberen via JLabels:
JLabel [] lijstdata = new JLabel[3];
lijstdata[0] = new JLabel("eerste", new ImageIcon("car1.gif"),
SwingConstants.LEFT );
lijstdata[1] = new JLabel("tweede", new ImageIcon("car2.gif"),
SwingConstants.LEFT );
lijstdata[2] = new JLabel("derde", new ImageIcon("car3.gif"),
SwingConstants.LEFT );
System.out.println(lijstdata[0].toString());
JList lijst = new ImageList(lijstdata);
//Frame instellen
frame.getContentPane().add(new JScrollPane(lijst));
frame.setSize(300,300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Dit geeft het volgende resultaat:
We zien dus duidelijk dat dit niet is wat we wensten. Toch is de oplossing nabij! :)
Een lijst gebruikt een renderer. Deze maakt krijgt een element door, tekent dit en geeft deze tekening door naar de lijst die de tekening zal gebruiken om de lijst te tekenen.
Als we zelf geen renderer opgeven of schrijven wordt van de opgegeven elementen toString() gebruikt, en deze wordt dan getekend in de lijst. Vandaar we dus de string-voorstelling te zien krijgen van onze labels.
We gaan dus zelf een renderer moeten maken en zeggen dat onze lijst deze moet gebruiken. Dit gebeurt in de volgende code:
PHP-code:
import javax.swing.*;
import java.awt.*;
public class ImageList extends JList{
public ImageList(Object [] data){
super(data);
//We geven zelf een renderer die zal bepalen
//hoe de items eruit zullen zien
setCellRenderer(new CustomCellRenderer());
}
//Deze renderer stuurt de labels terug. Deze zullen getekend worden
//en deze tekening zal gebruikt worden als zichtbaar item
class CustomCellRenderer implements ListCellRenderer {
public Component getListCellRendererComponent
(JList list, Object value, int index,boolean isSelected,boolean cellHasFocus) {
JLabel label = (JLabel)value;
label.setOpaque(true);
label.setBackground(isSelected ? Color.black : Color.white);
label.setForeground(isSelected ? Color.white : Color.black);
return label;
}
}
public static void main(String args[]){
JFrame frame = new JFrame("Lijst met figuren");
//We proberen via JLabels:
JLabel [] lijstdata = new JLabel[3];
lijstdata[0] = new JLabel("eerste", new ImageIcon("car1.gif"), SwingConstants.LEFT );
lijstdata[1] = new JLabel("tweede", new ImageIcon("car2.gif"), SwingConstants.LEFT );
lijstdata[2] = new JLabel("derde", new ImageIcon("car3.gif"), SwingConstants.LEFT );
System.out.println(lijstdata[0].toString());
JList lijst = new ImageList(lijstdata);
//Frame instellen
frame.getContentPane().add(new JScrollPane(lijst));
frame.setSize(300,300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
De lijst vraagt via getListCellRendererComponent de component op en tekent deze component op zichzelf als een weer te geven item (we spreken van een stempel (eng:stamp) in deze context).
Hierbij wordt als value een object doorgegeven dat het item is van de lijst, wij weten dat dit een JLabel is, met daarin de tekst en de figuur. We kunnen dus een cast doen naar JLabel. Dit label sturen we dan terug om te laten tekenen als item. We stellen de gepaste voor- en achtergrondkleur in van het label indien het al dan niet geselecteerd is.
Het resultaat ziet er als volgt uit:

Wat al veel beter is ;)
Hoe kan ik een kolom in een JTable centreren?
antwoord:
Net als bij voorgaande geldt het principe om een aangepaste renderer in te stellen. In dit geval wordt ook een JLabel als stempel gebruikt die kan ingesteld worden om gecentreerde tekst weer te geven.
Volgend voorbeeld maakt dit principe duidelijk:
Code:
import java.awt.Component;
import javax.swing.*;
import javax.swing.table.*;
public class CenteredColumnsDemo extends JFrame {
public CenteredColumnsDemo() {
Object[][] data = {
{"dit", "is", "een"},
{"demonstratie", "van", "een"},
{"speciale,", "aangepaste", "renderer"}
};
String[] kolommen = {"1", "2", "3"};
JTable table = new JTable(data, kolommen);
//stel de renderer in voor kolom met index=1
TableColumn col = table.getColumnModel().getColumn(1);
col.setCellRenderer(new CenteredColumnRenderer());
this.add(new JScrollPane(table));
this.setSize(200, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new CenteredColumnsDemo();
}
}
class CenteredColumnRenderer extends JLabel
implements TableCellRenderer {
public CenteredColumnRenderer() {
super();
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int rowIndex, int vColIndex) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
//dit stelt de tekst in en centreert:
setText(value.toString());
setHorizontalAlignment(SwingConstants.CENTER);
return this;
}
}
Zoals jullie kunnen zien aan dit resultaat:
wordt de kolom met index 1 gecentreerd weergegeven :)
Dit allemaal via het gebruik van volgende code:
Code:
//stel de renderer in voor kolom met index=1
TableColumn col = table.getColumnModel().getColumn(1);
col.setCellRenderer(new CenteredColumnRenderer());
die onze eigen cellrenderer zal gebruiken :)