- V kódu se stále vytváří jedna konkrétní ukázka obrázku s několika tvary. Kromě vykreslení jsou zobrazeny také v podobě tabulky nebo seznamu.
- Při označení položky v této tabulce nebo seznamu se zobrazí další tabulka, která umožňuje upravovat jednotlivé atributy tvaru (např. X1, X2, Y1, Y2, Stroke a StrokeWidth pro úsečku).
- Při úpravě je obrázek hned překreslen.
Kvíz
- Lokální proměnné (zejména typů odvozených od JPanel, JTabbedPane, JTable atd.) je často vhodné předělat na _______________________ aby bylo snadnější rozdělovat kód na metody a vytvářet listenery.
-
Doplňte způsob, jak založit panel
"multiPanel", jehož levá část bude dále rozdělená na
horní a dolní půlku:
multiPanel = new JPanel();
leftPanel = new JPanel();
multiPanel.setLayout(new _____________());
multiPanel.add(leftPanel, BorderLayout.WEST);
leftPanel.setLayout(new
GridLayout(_____________,_____________));
Obecné tipy k tabulkám s modelem
- Model tabulky je vždy třída odvozená od AbstractTableModel. Musí implementovat zděděné metody jako getValueAt, getColumnCount, getRowCount. Tím definuje obsah tabulky bez ohledu na její vzhled.
-
Pokud
jsou implementovány také metody isCellEditable a setValueAt, lze tabulku použít i pro úpravy.
Konkrétní tipy
-
Doporučení:
Zvolte si vlastní třídu (odvozenou od JFrame nebo JPanel) která bude obě tabulky a vykreslovací panel vizuálně obsahovat.
Zároveň bude obsahovat všechen kód pro jejich vzájemnou spolupráci.
-
Mezikrok: Zkuste vytvořit třídu EmptyTableModel, který bude mít například 2 sloupce a 4 řádky,
všechny buňky prázdné. Pak dokončete kód pro vizuální umístění
obou tabulek a na otestování jim přiřaďte tento prázdný model.
-
Model
první tabulky bude udávat tolik řádků, kolik je tvarů v obrázku.
Třída modelu může být navržená tak, že objekt reprezentující celý
obrázek je přijat v konstruktoru.
-
Model
druhé tabulky se liší podle toho, jaký tvar je vybrán. Doporučení:
vytvořit speciální třídy (odvozené od AbstractTableModel) pro každý tvar zvlášť.
Například model tabulky pro úpravu kružnic (tak jak je na obrázku)
definuje dva sloupce, šest řádků a přesný obsah každé
buňky. Objekt reprezentující samotnou kružnici může být přijat v konstruktoru.
-
Doporučení:
Do třídy „vizuálního rodiče“ přidejte následující metody:
o
Metoda
s názvem např. „uživatelVybralTvar“. V této metodě se
zjistí jaký řádek první tabulky je vybrán a podle toho se naplní druhá
tabulka. Druhá tabulka (JTable) se nemusí vytvářet znovu, stačí jí
přiřadit nový table model, který je vytvořen podle toho, jaký
tvar byl vybrán.
Tato metoda je volána při vybrání řádku v první tabulce.
o
Metoda
s názvem např. „dataBylaZměněna“. V této metodě
se zařídí, aby se překreslil obrázek.
Tato metoda je volána při úpravě dat v druhé tabulce.
Ukázky doplněné během cvičení
public class
ModelHorniTabulky extends AbstractTableModel
{
...
@Override
public Object getValueAt(int rowIndex, int
columnIndex)
{
if(columnIndex ==0)
return rowIndex+1;
if(columnIndex == 1)
return
obrazek.getShapes().get(rowIndex)
.getClass().getSimpleName();
return "";
}
}
_________________________________________
public MujFrame()
{
// -Vytvořit JTable
// -Umístit ho někam pomocí add
// -Vytvořit model
// např. new EmptyTableModel()
// -Přidat model do tabulky
// pomocí setModel(...)
}
_________________________________________
table.getSelectionModel().addListSelectionListener(e -> {
…
});
_________________________________________
Ukázky doplněné po/během cvičení 10
Náznak, jak ošetřit vybrání tvaru a jeho zobrazení v dolní tabulce (šlo by nahradit abstraktní metodou, kterou by každý tvar vytvářel vlastní model):
m.getSelectionModel().addSelectionListener(e->{
int row=
horniTabulka.getSelectedRow();
Tvar tvar =
obrazek.getTvary().get(row);
if(tvar instanceof Obdelnik
obdelnik)
{
ModelObdelniku modelObdelniku =
new ModelObdelniku(obdelnik);
dolniTabulka.setModel(modelObdelniku);
}
else if(tvar instanceof Elipsa)
{
ModelObdelniku modelObdelniku =
new ModelObdelniku((Elipsa)tvar);
dolniTabulka.setModel(modelObdelniku);
}
else if(tvar instanceof Usecka)
{
ModelObdelniku modelObdelniku =
new ModelObdelniku((Usecka)tvar);
dolniTabulka.setModel(modelObdelniku);
}
});
_________________________________________
public class ModelObdelniku
extends AbstractTableModel
{
Obdelnik obdelnik;
public ModelObdelniku(Obdelnik obdelnik)
{
this.obdelnik = obdelnik;
}
@Override
public int getRowCount()
{
return 6;
}
@Override
public int getColumnCount()
{
return 2;
}
@Override
public Object getValueAt(int rowIndex, int
columnIndex)
{
if(columnIndex == 0)
{
switch (rowIndex)
{
case 0: return "X";
case 1: return "Y";
case 2: return "Width";
case 3: return "Height";
}
}
if(columnIndex == 1)
{
switch (rowIndex)
{
case 0: return obdelnik.getX();
case 1: return obdelnik.getY();
case 2: return obdelnik.getWidth();
case 3: return obdelnik.getHeight();
}
}
}
}
_________________________________________
public void setValueAt(Object
aValue, int rowIndex, int columnIndex)
{
if(columnIndex == 1)
{
switch (rowIndex)
{
case 0: shape.setCx(Float.parseFloat(aValue.toString()));
break;
case 1: shape.setCy(Float.parseFloat(aValue.toString()));break;
case 2: shape.setRx(Float.parseFloat(aValue.toString()));break;
case 3: shape.setRy(Float.parseFloat(aValue.toString()));break;
}
fireTableDataChanged();
}
}