Fáze 2
Požadavky

-        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.

A screenshot of a computer

Description automatically generated

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();
    }
}