Search code examples
javaswinguser-interfacepaintcomponent

How to draw the exact number of line in my gui?


I'm trying to draw the exact number of line in my gui. So I use a TableModelListener to listen the number of row in my Jtable and I manage to display the number of row each time when i add a new row in my table.

Problem : But now, I want to draw x lines in my gui when i have x rows in my jtable. I try to put a TableModelListerner like above but it's not working.

Thanks for helping. I sorry to put a lot of classes but I want also to learn to make a reusable code and to learn java swing.

enter image description here

class Test

import java.awt.GridLayout;

import javax.swing.JFrame;

public class Test {

    public static void main(String[] args) {
        JFrame f = new JFrame();

        f.setLayout(new GridLayout(1, 2, 5, 5));

        TablePanel tablePanel = new TablePanel();
        ButtonPanel buttonPanel = new ButtonPanel();
        DrawTwoSameDrawPanel drawPanels = new DrawTwoSameDrawPanel();

        f.add(tablePanel);
        f.add(buttonPanel);
        f.add(drawPanels);

        f.setSize(800, 300);
        f.setLocationRelativeTo(null);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);

    }

}

class MyTableModel

import javax.swing.table.AbstractTableModel;

public class MyTableModel extends AbstractTableModel {

    private String[] columnNames = { "RowListener", "B", "C" };
    private Object[][] data = { { "x", "xx", "xxx" }, { "y", "yy", "yyy" }, { "z", "zz", "zzz" } };

    @Override
    public int getColumnCount() {
        return columnNames.length;
    }

    @Override
    public int getRowCount() {
        return data.length;
    }

    @Override
    public Object getValueAt(int row, int col) {
        return data[row][col];
    }

    @Override
    public Class<?> getColumnClass(int col) {
        return data[0][col].getClass();
    }

    @Override
    public String getColumnName(int col) {
        return columnNames[col];
    }

    @Override
    public void setValueAt(Object aValue, int row, int col) {
        data[row][col] = aValue;
        fireTableStructureChanged();
    }

    public void addRow(Object[][] data) {
        int index = 0;
        int nbRow = this.getRowCount();
        int nbCol = this.getColumnCount();

        Object temp[][] = this.data;
        this.data = new Object[nbRow + 1][nbCol];

        for (Object[] value : temp)
            this.data[index++] = value;

        this.data[index] = data;
        temp = null;

        this.fireTableDataChanged();

    }

}

class ButtonPanel

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

public class ButtonPanel extends JPanel {

    private JButton button;
    private DrawPanel drawPanel;

    public ButtonPanel() {
        super();

        this.setBorder(new LineBorder(Color.red));
        button = new JButton("Update");
        this.add(button);
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                System.out.println("hello console");

                int n = JOptionPane.showConfirmDialog(null, "Would you like to update drawPanel ?", "Question",
                        JOptionPane.YES_NO_OPTION);

                if (n == JOptionPane.YES_OPTION) {
                    System.out.println("console : YES");
                    updatePanels();
                }
                else
                    System.out.println("console : NO");
            }

        });
    }

    public void updatePanels() {
        drawPanel = new DrawPanel();        
        drawPanel.revalidate();
        drawPanel.repaint();

    }
}

class DrawPanel

public class DrawPanel extends JPanel implements TableModelListener{

    private MyTableModel model = new MyTableModel();
    private JTable table = new JTable(model);

    private int numberOfLine = 0;

    public DrawPanel() {
        super();
        this.setBorder(new LineBorder(Color.blue));
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics graphics = g.create();
        int y = 10;

        /////////don't work 
        RowListener rowListener = new RowListener(model);
        numberOfLine = rowListener.getNumberOfRow();
        //////////

        for (int i = 0; i < numberOfLine; i++) {
            graphics.drawLine(10, y, getWidth() - 10, y);
            y += 10;
        }
        graphics.dispose();
    }

    public void setNumberOfArrows(int arrows) {
        numberOfLine = arrows;
        repaint();
    }

    public int getNumberOfArrows() {
        return numberOfLine;
    }

    @Override
    public Dimension getPreferredSize() {
        return isPreferredSizeSet() ? super.getPreferredSize() : new Dimension(200, 200);
    }

     @Override
     public void tableChanged(TableModelEvent arg0) {
     int numberOfRow = model.getRowCount();
     this.setNumberOfArrows(numberOfRow);
     System.out.println("numberOfRow: " + numberOfRow);

     }

    class RowListener implements TableModelListener {
        private MyTableModel model;
        private int numberOfRow;

        public RowListener(MyTableModel model) {
            this.model = model;
            model.addTableModelListener(this);
        }

        @Override
        public void tableChanged(TableModelEvent arg0) {
            numberOfRow = model.getRowCount();          
            System.out.println("numberOfRow: " + numberOfRow);
        }

        public int getNumberOfRow() {
            return numberOfRow;
        }

        public void setNumberOfRow(int numberOfRow) {
            this.numberOfRow = numberOfRow;
        }
    }

}

class TablePanel

public class TablePanel extends JPanel {

private MyTableModel model = new MyTableModel();
private JTable table = new JTable(model);
private int nbRow = 0;

private JButton addButton = new JButton("Add Row");

public TablePanel() {
    super();
    this.setBorder(new LineBorder(Color.orange));
    this.add(table);
    this.add(addButton);

    addButton.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            model.addRow(new Object[][] { { "u", "u", "u" }, { "v", "v", "vy" }, { "w", "w", "w" } });
            model.fireTableStructureChanged();
            nbRow = model.getRowCount();
            System.out.println("nbRow: " + nbRow);

        }
    });

    this.add(createDisplayNbRowPanel());

}

public JPanel createDisplayNbRowPanel() {
    JPanel p = new JPanel();
    p.add(new JLabel("number of row : "));
    NbRowView nbRowView = new NbRowView(model);
    p.add(nbRowView);
    p.setBorder(new LineBorder(Color.red));

    return p;
}

public int getNbRow() {
    return nbRow;
}

public void setNbRow(int nbRow) {
    this.nbRow = nbRow;
}

class NbRowView extends JLabel implements TableModelListener {

    private MyTableModel model;

    public NbRowView(MyTableModel model) {
        this.model = model;
        model.addTableModelListener(this);
    }

    @Override
    public void tableChanged(TableModelEvent arg0) {
        int nbOfRow = model.getRowCount();
        this.setText(nbOfRow + "");
        DrawPanel drawPanel = new DrawPanel();
        drawPanel.setNumberOfArrows(nbOfRow);

    }

}

}

class DrawTwoSameDrawPanel

public class DrawTwoSameDrawPanel extends JPanel {

private DrawPanel drawPanel_1 = new DrawPanel();
private DrawPanel drawPanel_2 = new DrawPanel();

public DrawTwoSameDrawPanel() {
    super();
    this.setBorder(new LineBorder(Color.green));
    this.add(drawPanel_1);
    this.add(drawPanel_2);
}

}

Solution

  • I want to draw x lines in my gui when i have x rows in my jtable.

    Looking at your previous question: How to synchronize two view in Java Swing you have implemented the paintComponent() method of your DrawPanel pretty well, but you still need to decouple this from table model. As other developers said your code is large and complicated and you need to better organize it:

    1. Create a reusable panel as shown in this answer
    2. When you create a new instance of your table model, attach a new TableModelListener to call setNumberOfArrows() method, that will repaint your panel as you wish.

    For instance:

    class GuiClass {
    
        private DrawPanel drawPanel;
    
        public void createAndShowGui() {
            drawPanel = new DrawPanel();
            MyTableModel model = new MyTableModel();
            model.addTableModelListener(new TableModelListener() { // Anonymous class
                @Override
                public void tableChanged(TableModelEvent e) {
                    if(e.getType() == TableModelEvent.INSERT || e.getType() == TableModelEvent.DELETE) {
                        int rows = ((TableModel)e.getSource()).getRowCount();
                        drawPanel.setNumberOfArrows(rows);
                    }
                }
            });
            // rest of your GUI code here
        }
    }
    

    Note: Java provides a good mechanism to avoid create an excesive number of classes to implement interfaces or extend from other classes: Anonymous Classes

    About your table model, please note it looks like DefaultTableModel pretty much, so you may want to use that class instead of create your own (if it fits your requirements of course).

    Additionaly, the implementation of getColumnClass() method should never look up for data to retrieve a value, you should be able to return the correct class since you know what kind of data your table model will contain.

    Finally your addRow(Object[][] row) method doesn't make sense since you probably want to add a single row to your table model, not row and columns. I think it should be addRow(Object[] row) (note single-dimension array as parameter). Having said this it should look like this:

    public void addRow(Object[] row) {
        // add row here
        int rowIndex = data.length;
        fireTableRowsInserted(rowIndex, rowIndex);
    }
    

    See AbstractTableModel API: