|
| AbstractTableModel !!? Fra : Morten Rasmussen |
Dato : 23-10-01 08:48 |
|
Hej!
Jeg ønsker at lave en generel tabelmodel til brug i mange skærmbilleder.
Ønskelige er en model hvor jeg kan administrere både tabeldata og tabel
layout. Jeg har forsøgt med følgende:
public class BaseTableModel extends AbstractTableModel {
::
::
}
... her har jeg min tabelmodel, men er det også muligt her at lave
procedurere til det layoutmæssige så jeg fx. kan kalde:
baseTableModel.lookCell(x, y)
baseTableModel.colWidth(col, width)
baseTableModel.setCellColor(x, y, cell)
osv.
Er dette muligt eller hvordan kan det ellers lade sig gøre? Fx. ved brug af
en anden klasse end AbstractTableModel?
Mange tak hvis nogle kan hjælpe.
Morten
| |
Jacob Nordfalk (23-10-2001)
| Kommentar Fra : Jacob Nordfalk |
Dato : 23-10-01 11:02 |
|
Morten Rasmussen wrote:
> Hej!
>
> Jeg ønsker at lave en generel tabelmodel til brug i mange skærmbilleder.
> Ønskelige er en model hvor jeg kan administrere både tabeldata og tabel
> layout. Jeg har forsøgt med følgende:
>
> public class BaseTableModel extends AbstractTableModel {
> ::
> ::
> }
>
> .. her har jeg min tabelmodel, men er det også muligt her at lave
> procedurere til det layoutmæssige så jeg fx. kan kalde:
>
> baseTableModel.lookCell(x, y)
> baseTableModel.colWidth(col, width)
> baseTableModel.setCellColor(x, y, cell)
> osv.
>
Nej. TableModel beskriver datamodellen, d.v.s. de underliggende data _uafhængigt_ af præsentationen
(det er ideen i MVC-arkitekturen)
Det du har brug for er TableCellRenderer.
--
Jacob Nordfalk
| |
Jacob Nordfalk (23-10-2001)
| Kommentar Fra : Jacob Nordfalk |
Dato : 23-10-01 11:06 |
|
Jeg vedlægger nogle noter om MVC og tabeller.
4.2 Model-View-Controller-arkitekturen
De fleste brugergrænsefladers kan inddeles i tre dele, nemlig:
datamodellen som repræsenterer data og de bagvedliggende beregninger,
præsentationen af data over for brugeren, og tilsidst
brugerens mulighed for at ændre i disse data gennem forskellige handlinger.
Ofte præsenteres brugeren ikke for alle data, og måske kan han ikke ændre frit, og måske er der
konsekvenser for andre data, i det samme eller i andre skærmbilleder.
Model-View-Controller-arkitekturen (forkortet MVC) er en slags programmeringsmodel beregnet til
brugergrænseflader. Den anbefaler at man opdeler en grænseflade i tre dele: En model, en
præsentation, og en kontrol-del.
4.2.1 Modellen
Datamodellen indeholder data og registrerer hvilken tilstand den pågældende del af programmet er i.
Oftest er data indkapslet sådan at konsistens sikres. I så fald er der kun adgang til at spørge og
ændre på data gemmem metodekald.
Oftest modellen bør være uafhængig af hvordan data præsenteres over for brugeren, og er der flere
programmer der arbejder med de samme slags data kan de have den samme samme datamodel, selvom de i
øvrigt er helt forskellige.
Eksempel: En bankkonto har navn på ejer, kontonummer, kort-ID, saldo, bevægelser, renteoplysninger
e.t.c. Saldoen kan ikke ændres direkte, men med handlingerne overførsel, udbetaling og indbetaling
kan saldoen påvirkes.
4.2.2 Præsentationen (Viewet)
Præsentationen henter relevante data fra modellen og viser dem for brugeren i en passende form.
Præsentationen kan være meget forskellig fra program til program, selvom de deler model.
Eksempel: Bankkontoen præsenteres meget forskelligt. I en Dankort-automat vises ingen personlige
oplysninger overhovedet. I et hjemmebank-system kan saldo og bevægelser ses (det kunne være
implementeret i HTML, d.v.s. et server-side-program der generer HTML). Ved skranken kan
medarbejderen se endnu mere, f.eks. filial og kontaktperson i banken (det kunne være implementeret
som en grafisk applikation der kører hos brugeren).
4.2.3 Kontrol-delen (Controlleren)
Kontroldelen definerer hvad programmet kan. Den omsætter brugerens indtastninger til handlinger der
skal udføres på modellen.
Eksempel: I Dankort-automaten kan man kun hæve penge. I et hjemmebank-system kan brugeren måske
lave visse former for overførsel fra sin egen konto. Ved skranken kan medarbejderen derudover
foretage ind- og udbetalinger.
Tabeller
For JTable kan man sætte fremvisningen på hver kolonne (hentet med getColumn() og navnet på
kolonnen) med metoden: setRenderer(TableCellRenderer renderer).
public interface TableCellRenderer {
/**
* Returns the component used for drawing the cell. This method is
* used to configure the renderer appropriately before drawing.
*
* @param table the <code>JTable</code> that is asking the
* renderer to draw; can be <code>null</code>
* @param value the value of the cell to be rendered. It is
* up to the specific renderer to interpret
* and draw the value. For example, if
* <code>value</code>
* is the string "true", it could be rendered as a
* string or it could be rendered as a check
* box that is checked. <code>null</code> is a
* valid value
* @param isSelected true if the cell is to be rendered with the
* selection highlighted; otherwise false
* @param hasFocus if true, render cell appropriately. For
* example, put a special border on the cell, if
* the cell can be edited, render in the color used
* to indicate editing
* @param row the row index of the cell being drawn. When
* drawing the header, the value of
* <code>row</code> is -1
* @param column the column index of the cell being drawn
*/
Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column);
}
I stedet tilrådes det dog at man arver fra klassen DefaultTableCellRenderer (der er en optimeret
JLabel) og definerer metoden
public void setValue(Object værdi)
{
// her skal man konfigurere JLabel, f.eks:
setText("værdi:"+værdi);
}
eksempel
Herunder ses en simpel demo af tabller.
import javax.swing.*;
import javax.swing.table.*;
public class Frame1 extends JFrame {
JScrollPane jScrollPane1 = new JScrollPane();
JTable jTable1 = new JTable();
private void jbInit() throws Exception {
this.getContentPane().add(jScrollPane1, BorderLayout.CENTER);
jScrollPane1.getViewport().add(jTable1, null);
}
public Frame1() {
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
//
// Hjælpevariabler
//
ImageIcon æble = new ImageIcon("apple.jpg", "æble");
ImageIcon asparges = new ImageIcon("asparagus.jpg", "asparges");
ImageIcon banan = new ImageIcon("banana.jpg", "banan");
ImageIcon broccoli = new ImageIcon("broccoli.jpg", "broccoli");
ImageIcon gulerod = new ImageIcon("carrot.jpg", "gulerod");
ImageIcon kiwi = new ImageIcon("kiwi.jpg", "kiwi");
ImageIcon løg = new ImageIcon("onion.jpg", "løg");
Boolean ja = Boolean.TRUE;
Boolean nej = Boolean.FALSE;
/////////////////////////////////////////////////
// Data
/////////////////////////////////////////////////
final String[] kolonner =
{ "Navn", "Yndlingsfarve", "Yndlingstal", "Yndlingsret", "Enlig?", "Sexet?"};
final Object[][] data = {
{"Hans Petersen" , Color.blue, new Double(44), æble, ja, nej},
{"Jacob Sørensenn" , Color.yellow, new Double(42), kiwi, ja, ja},
{"Grethe Ibsen" , Color.blue, new Double(-37), løg, nej, nej},
{"Kurt Ibsen" , Color.darkGray, new Double(1), banan, nej, nej},
{"Karin Ibsen" , Color.green, new Double(10.5),gulerod, nej, ja}
};
jTable1.setRowHeight(2*æble.getIconHeight()/3); // sæt højden af cellerne
Oprettelse af datamodellen
// Man kan oprette en datamodel direkte ud fra interfacet...
class DatamodelFraInterface implements TableModel
{
public int getColumnCount() {return kolonner.length;}
public int getRowCount() {return data.length;}
public Object getValueAt(int r, int k) {return data[r][k];}
public String getColumnName(int k) {return kolonner[k];}
public Class getColumnClass(int k) {return
data[0][k].getClass();}
public boolean isCellEditable(int r, int k) {return k != 1;}
public void setValueAt(Object v, int r, int k){data[r][k]=v; }
public void addTableModelListener(TableModelListener p0) {} // hmm...
public void removeTableModelListener(TableModelListener p0) {} // hmm...
};
//jTable1.setModel(new DatamodelFraInterface());
// eller oprette fra en hjælpeklasse der sørger for de fleste ting, bl.a. hændelser
class DatamodelFraHjælpeklasse extends AbstractTableModel
{
public int getColumnCount() {return kolonner.length;}
public int getRowCount() {return data.length;}
public Object getValueAt(int r, int k) {return data[r][k];}
public String getColumnName(int k) {return kolonner[k];}
public Class getColumnClass(int k) {return
data[0][k].getClass();}
public boolean isCellEditable(int r, int k) {return k != 1;}
public void setValueAt(Object v, int r, int k){data[r][k]=v; }
};
jTable1.setModel(new DatamodelFraHjælpeklasse());
// ... eller bruge standardklassen DefaultTableModel der sørger for
// det hele (men ikke altid helt som man vil ha' det)...
//jTable1.setModel(new DefaultTableModel(data,kolonner));
Styring af fremvisningen
/////////////////////////////////////////////////
// Opret præsentationsobjekter
/////////////////////////////////////////////////
// Man kan oprette et præsentationsobjekt direkte ud fra interfacet...
class Farvepræsentation implements TableCellRenderer
{
JLabel jLabel = new JLabel();
public Component getTableCellRendererComponent(
JTable tabel, Object værdi,
boolean erValgt, boolean harFokus,
int række, int kolonne)
{
if (værdi instanceof Color)
{
Color f = (Color) værdi;
jLabel.setBackground(f);
jLabel.setForeground(f.darker());
jLabel.setOpaque(true);
jLabel.setText("farve");
} else {
jLabel.setBackground(Color.white);
jLabel.setForeground(Color.black);
jLabel.setText(værdi.toString());
}
return jLabel;
}
}
jTable1.getColumn("Yndlingsfarve").setCellRenderer(new Farvepræsentation());
// ...men det er mere effektivt og simpelt at arve fra DefaultTableCellRenderer,
// (der er en JLabel med noget ekstra maskineri)
class Talpræsentation extends DefaultTableCellRenderer
{
public void setValue(Object værdi)
{
if (værdi instanceof Double) {
if (((Double) værdi).doubleValue()<0)
setForeground(Color.red);
else setForeground(Color.blue);
}
else setForeground(Color.black);
setText(værdi.toString());
}
}
jTable1.getColumn("Yndlingstal").setCellRenderer(new Talpræsentation());
Styre redigeringen
// Lav en valgliste til at vælge mellem retterne.
JComboBox comboBox = new JComboBox();
comboBox.addItem(æble);
comboBox.addItem(asparges);
comboBox.addItem(banan);
comboBox.addItem(broccoli);
comboBox.addItem(gulerod);
comboBox.addItem(kiwi);
comboBox.addItem(løg);
jTable1.getColumn("Yndlingsret").setCellEditor(new DefaultCellEditor(comboBox));
// Og en til vælge mellem enlig og ikke-enlig.
comboBox = new JComboBox();
comboBox.addItem( new Boolean(true));
comboBox.addItem( new Boolean(false));
jTable1.getColumn("Enlig?").setCellEditor(new DefaultCellEditor(comboBox));
}
} // slut på klassen
--
Jacob Nordfalk
| |
Morten Rasmussen (23-10-2001)
| Kommentar Fra : Morten Rasmussen |
Dato : 23-10-01 17:00 |
|
Mange tak - det ser skide godt ud!
Prøver først i morgen el. torsdag, men du hører nok hvis det kniber!
Mvh. Morten
"Jacob Nordfalk" <nordfalk@mobilixnet.dk> wrote in message
news:3BD54110.CDB20940@mobilixnet.dk...
> Jeg vedlægger nogle noter om MVC og tabeller.
>
>
>
>
> 4.2 Model-View-Controller-arkitekturen
>
> De fleste brugergrænsefladers kan inddeles i tre dele, nemlig:
>
> datamodellen som repræsenterer data og de bagvedliggende beregninger,
>
> præsentationen af data over for brugeren, og tilsidst
>
> brugerens mulighed for at ændre i disse data gennem forskellige
handlinger.
>
> Ofte præsenteres brugeren ikke for alle data, og måske kan han ikke ændre
frit, og måske er der
> konsekvenser for andre data, i det samme eller i andre skærmbilleder.
>
>
>
> Model-View-Controller-arkitekturen (forkortet MVC) er en slags
programmeringsmodel beregnet til
> brugergrænseflader. Den anbefaler at man opdeler en grænseflade i tre
dele: En model, en
> præsentation, og en kontrol-del.
>
>
>
>
> 4.2.1 Modellen
>
> Datamodellen indeholder data og registrerer hvilken tilstand den
pågældende del af programmet er i.
>
> Oftest er data indkapslet sådan at konsistens sikres. I så fald er der kun
adgang til at spørge og
> ændre på data gemmem metodekald.
>
> Oftest modellen bør være uafhængig af hvordan data præsenteres over for
brugeren, og er der flere
> programmer der arbejder med de samme slags data kan de have den samme
samme datamodel, selvom de i
> øvrigt er helt forskellige.
>
>
>
> Eksempel: En bankkonto har navn på ejer, kontonummer, kort-ID, saldo,
bevægelser, renteoplysninger
> e.t.c. Saldoen kan ikke ændres direkte, men med handlingerne overførsel,
udbetaling og indbetaling
> kan saldoen påvirkes.
>
>
>
> 4.2.2 Præsentationen (Viewet)
>
> Præsentationen henter relevante data fra modellen og viser dem for
brugeren i en passende form.
> Præsentationen kan være meget forskellig fra program til program, selvom
de deler model.
>
>
>
> Eksempel: Bankkontoen præsenteres meget forskelligt. I en Dankort-automat
vises ingen personlige
> oplysninger overhovedet. I et hjemmebank-system kan saldo og bevægelser
ses (det kunne være
> implementeret i HTML, d.v.s. et server-side-program der generer HTML). Ved
skranken kan
> medarbejderen se endnu mere, f.eks. filial og kontaktperson i banken (det
kunne være implementeret
> som en grafisk applikation der kører hos brugeren).
>
>
>
> 4.2.3 Kontrol-delen (Controlleren)
>
> Kontroldelen definerer hvad programmet kan. Den omsætter brugerens
indtastninger til handlinger der
> skal udføres på modellen.
>
>
>
> Eksempel: I Dankort-automaten kan man kun hæve penge. I et
hjemmebank-system kan brugeren måske
> lave visse former for overførsel fra sin egen konto. Ved skranken kan
medarbejderen derudover
> foretage ind- og udbetalinger.
>
>
>
>
>
>
>
>
>
> Tabeller
>
> For JTable kan man sætte fremvisningen på hver kolonne (hentet med
getColumn() og navnet på
> kolonnen) med metoden: setRenderer(TableCellRenderer renderer).
>
>
>
> public interface TableCellRenderer {
>
> /**
> * Returns the component used for drawing the cell. This method is
> * used to configure the renderer appropriately before drawing.
> *
> * @param table the <code>JTable</code> that is asking the
> * renderer to draw; can be <code>null</code>
> * @param value the value of the cell to be rendered. It
is
> * up to the specific renderer to interpret
> * and draw the value. For example, if
> * <code>value</code>
> * is the string "true", it could be rendered
as a
> * string or it could be rendered as a check
> * box that is checked. <code>null</code> is
a
> * valid value
> * @param isSelected true if the cell is to be rendered with
the
> * selection highlighted; otherwise false
> * @param hasFocus if true, render cell appropriately. For
> * example, put a special border on the cell,
if
> * the cell can be edited, render in the
color used
> * to indicate editing
> * @param row the row index of the cell being drawn.
When
> * drawing the header, the value of
> * <code>row</code> is -1
> * @param column the column index of the cell being drawn
> */
>
> Component getTableCellRendererComponent(
> JTable table, Object value,
> boolean isSelected, boolean
hasFocus,
> int row, int column);
> }
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> I stedet tilrådes det dog at man arver fra klassen
DefaultTableCellRenderer (der er en optimeret
> JLabel) og definerer metoden
>
> public void setValue(Object værdi)
> {
> // her skal man konfigurere JLabel, f.eks:
> setText("værdi:"+værdi);
> }
>
>
>
>
> eksempel
>
> Herunder ses en simpel demo af tabller.
>
>
>
>
> import javax.swing.*;
> import javax.swing.table.*;
>
> public class Frame1 extends JFrame {
> JScrollPane jScrollPane1 = new JScrollPane();
> JTable jTable1 = new JTable();
>
> private void jbInit() throws Exception {
> this.getContentPane().add(jScrollPane1,
BorderLayout.CENTER);
> jScrollPane1.getViewport().add(jTable1, null);
> }
>
> public Frame1() {
> try {
> jbInit();
> }
> catch(Exception e) {
> e.printStackTrace();
> }
>
> //
> // Hjælpevariabler
> //
> ImageIcon æble = new ImageIcon("apple.jpg",
"æble");
> ImageIcon asparges = new ImageIcon("asparagus.jpg",
"asparges");
> ImageIcon banan = new ImageIcon("banana.jpg",
"banan");
> ImageIcon broccoli = new ImageIcon("broccoli.jpg",
"broccoli");
> ImageIcon gulerod = new ImageIcon("carrot.jpg",
"gulerod");
> ImageIcon kiwi = new ImageIcon("kiwi.jpg",
"kiwi");
> ImageIcon løg = new ImageIcon("onion.jpg",
"løg");
> Boolean ja = Boolean.TRUE;
> Boolean nej = Boolean.FALSE;
>
> /////////////////////////////////////////////////
> // Data
> /////////////////////////////////////////////////
> final String[] kolonner =
> { "Navn", "Yndlingsfarve", "Yndlingstal", "Yndlingsret",
"Enlig?", "Sexet?"};
>
> final Object[][] data = {
> {"Hans Petersen" , Color.blue, new Double(44),
æble, ja, nej},
> {"Jacob Sørensenn" , Color.yellow, new Double(42),
kiwi, ja, ja},
> {"Grethe Ibsen" , Color.blue, new Double(-37), løg,
nej, nej},
> {"Kurt Ibsen" , Color.darkGray, new Double(1),
banan, nej, nej},
> {"Karin Ibsen" , Color.green, new
Double(10.5),gulerod, nej, ja}
> };
>
> jTable1.setRowHeight(2*æble.getIconHeight()/3); // sæt
højden af cellerne
>
> Oprettelse af datamodellen
>
> // Man kan oprette en datamodel direkte ud fra
interfacet...
> class DatamodelFraInterface implements TableModel
> {
> public int getColumnCount()
{return kolonner.length;}
> public int getRowCount()
{return data.length;}
> public Object getValueAt(int r, int k)
{return data[r][k];}
> public String getColumnName(int k)
{return kolonner[k];}
> public Class getColumnClass(int k)
{return
> data[0][k].getClass();}
> public boolean isCellEditable(int r, int k)
{return k != 1;}
> public void setValueAt(Object v, int r, int
k){data[r][k]=v; }
> public void
addTableModelListener(TableModelListener p0) {} // hmm...
> public void
removeTableModelListener(TableModelListener p0) {} // hmm...
> };
> file://jTable1.setModel(new DatamodelFraInterface());
>
> // eller oprette fra en hjælpeklasse der sørger for de
fleste ting, bl.a. hændelser
> class DatamodelFraHjælpeklasse extends AbstractTableModel
> {
> public int getColumnCount()
{return kolonner.length;}
> public int getRowCount()
{return data.length;}
> public Object getValueAt(int r, int k)
{return data[r][k];}
> public String getColumnName(int k)
{return kolonner[k];}
> public Class getColumnClass(int k)
{return
> data[0][k].getClass();}
> public boolean isCellEditable(int r, int k)
{return k != 1;}
> public void setValueAt(Object v, int r, int
k){data[r][k]=v; }
> };
> jTable1.setModel(new DatamodelFraHjælpeklasse());
>
> // ... eller bruge standardklassen DefaultTableModel der
sørger for
> // det hele (men ikke altid helt som man vil ha' det)...
> file://jTable1.setModel(new
DefaultTableModel(data,kolonner));
>
> Styring af fremvisningen
>
> /////////////////////////////////////////////////
> // Opret præsentationsobjekter
> /////////////////////////////////////////////////
>
> // Man kan oprette et præsentationsobjekt direkte ud fra
interfacet...
> class Farvepræsentation implements TableCellRenderer
> {
> JLabel jLabel = new JLabel();
>
> public Component getTableCellRendererComponent(
> JTable tabel,
Object værdi,
> boolean erValgt,
boolean harFokus,
> int række, int
kolonne)
> {
> if (værdi instanceof Color)
> {
> Color f = (Color) værdi;
> jLabel.setBackground(f);
> jLabel.setForeground(f.darker());
> jLabel.setOpaque(true);
> jLabel.setText("farve");
> } else {
> jLabel.setBackground(Color.white);
> jLabel.setForeground(Color.black);
> jLabel.setText(værdi.toString());
> }
> return jLabel;
> }
> }
>
> jTable1.getColumn("Yndlingsfarve").setCellRenderer(new
Farvepræsentation());
>
> // ...men det er mere effektivt og simpelt at arve fra
DefaultTableCellRenderer,
> // (der er en JLabel med noget ekstra maskineri)
> class Talpræsentation extends DefaultTableCellRenderer
> {
> public void setValue(Object værdi)
> {
> if (værdi instanceof Double) {
> if (((Double)
værdi).doubleValue()<0)
> setForeground(Color.red);
> else setForeground(Color.blue);
> }
> else setForeground(Color.black);
>
> setText(værdi.toString());
> }
> }
>
> jTable1.getColumn("Yndlingstal").setCellRenderer(new
Talpræsentation());
>
> Styre redigeringen
>
> // Lav en valgliste til at vælge mellem retterne.
> JComboBox comboBox = new JComboBox();
> comboBox.addItem(æble);
> comboBox.addItem(asparges);
> comboBox.addItem(banan);
> comboBox.addItem(broccoli);
> comboBox.addItem(gulerod);
> comboBox.addItem(kiwi);
> comboBox.addItem(løg);
> jTable1.getColumn("Yndlingsret").setCellEditor(new
DefaultCellEditor(comboBox));
>
> // Og en til vælge mellem enlig og ikke-enlig.
> comboBox = new JComboBox();
> comboBox.addItem( new Boolean(true));
> comboBox.addItem( new Boolean(false));
> jTable1.getColumn("Enlig?").setCellEditor(new
DefaultCellEditor(comboBox));
>
> }
> } // slut på klassen
>
>
>
> --
> Jacob Nordfalk
| |
|
|