[Επιλύθηκε] κατασκευή JTable δυναμικά μέσα από listener handler

Συζητήσεις για γλώσσες προγραμματισμού και θέματα σχετικά με προγραμματισμό.
Post Reply
User avatar
Luke
Gbyte level
Gbyte level
Posts: 1388
Joined: Wed Aug 09, 2006 11:19 am
Academic status: Alumnus/a
Gender:

[Επιλύθηκε] κατασκευή JTable δυναμικά μέσα από listener handler

Post by Luke » Wed Jul 04, 2012 12:16 pm

Προσπαθώ να κάνω χρήση JTable για να βελτιώσω σε μία παλιά εφαρμογή τον τρόπο με τον οποίο παρουσιάζονται τα δεδομένα που λαμβάνονται από μία βάση δεδομένων. Για το σκοπό αυτό έχω ένα combo box και ανάλογα με την επιλογή που κάνω επιστρέφονται άλλα δεδομένα με βάση κάποια προκαθορισμένα queries. Με λίγα λόγια θέλω το μοντέλο του JTable (πλήθος και ονόματα στηλών αλλά και πλειάδες δεδομένων) να αλλάζει δυναμικά ανάλογα με την επιλογή στο combo box.

Όταν φτιάχνω και γεμίζω "καρφωτά" το JTable μέσα από τον κατασκευαστή της Demo κλάσης που έχω, το JTable εμφανίζεται κανονικά.
Όταν όμως πάω να το παράγω μέσα από τον listener handler (actionPerformed()) τότε δεν εμφανίζεται τίποτα...
Είμαι πεπεισμένος ότι κάνω πολύ τραγικό λάθος αλλά δε μπορώ να δω τι ακριβώς. Παραθέτω ενδεικτικό κώδικα (είναι απλοποιημένος ώστε να μην περιλαμβάνει το κομμάτι της βάσης δεδομένων και να τρέχει standalone) αν μπορεί να βοηθήσει κάποιος.
Έχω βάλει να εμφανίζεται το table (μία μόνο πλειάδα) όταν επιλέγουμε την "Customers" option στον listener.

Code: Select all

package comboboxjtabledemo;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.Vector;

public class ComboBoxJTableDemo extends JPanel implements ActionListener {
    JLabel picture;
    JTable table;
    JScrollPane scroll;
    String[] columnNames;
    DefaultTableModel model;

    public ComboBoxJTableDemo() {
        super(new BorderLayout());

        String[] options = { "Customers", "Agencies", "Rooms", "Employees", "Services" };

        //Create the combo box, select the item at index 1.
        JComboBox optionList = new JComboBox(options);
        optionList.setSelectedIndex(1);
        optionList.addActionListener(this);

        //Set up the picture.
        picture = new JLabel();
        picture.setFont(picture.getFont().deriveFont(Font.ITALIC));
        picture.setHorizontalAlignment(JLabel.CENTER);
        //updateLabel(options[optionList.getSelectedIndex()]);
        picture.setBorder(BorderFactory.createEmptyBorder(10,0,0,0));

        //The preferred size is hard-coded to be the width of the
        //widest image and the height of the tallest image + the border.
        //A real program would compute this.
        picture.setPreferredSize(new Dimension(177, 122+10));

        //Lay out the demo.
        add(optionList, BorderLayout.PAGE_START);
        add(picture, BorderLayout.PAGE_END);
        setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
        
        
        /*TESTING code from within constructor*/
        
        /*
        columnNames[0] = "ID";
        columnNames[1] = "Name";
        columnNames[2] = "Surname";
        columnNames[3] = "Father name";
        columnNames[4] = "Address";
        olumnNames[5] = "Telephone";
        columnNames[6] = "County";
        columnNames[7] = "City";
        model = new DefaultTableModel(columnNames, 0);
            
        Vector<String> row = new Vector<String>();
        row.add("1");
        row.add("John");
        row.add("Johnakis");
        row.add("Sr. John");
        row.add("Adamantos 4");
        row.add("0123456789");
        row.add("Papua New Guinea");
        row.add("Noland");
        model.addRow(row);
            
        table = new JTable(model);
        scroll = new JScrollPane(table);
        add(scroll);*/
    }

    /** Listens to the combo box. */
    public void actionPerformed(ActionEvent e) {
        JComboBox cb = (JComboBox)e.getSource();
        String option = (String)cb.getSelectedItem();
        
        if (option.equals("Customers"))
        {
            columnNames[0] = "ID";
            columnNames[1] = "Name";
            columnNames[2] = "Surname";
            columnNames[3] = "Father name";
            columnNames[4] = "Address";
            columnNames[5] = "Telephone";
            columnNames[6] = "County";
            columnNames[7] = "City";
            model = new DefaultTableModel(columnNames, 0); //0 data rows for the moment
            
            //add 1 record/row manually just for testing
            Vector<String> row = new Vector<String>();
            row.add("1");
            row.add("John");
            row.add("Johnakis");
            row.add("Sr. John");
            row.add("Adamantos 4");
            row.add("0123456789");
            row.add("Papua New Guinea");
            row.add("Noland");
            model.addRow(row);
            
            table = new JTable(model);
        }
        else //just to prevent Null Pointer Exception
        {
            table = new JTable();
        }
        scroll = new JScrollPane(table);
        add(scroll);
        table.updateUI();
    }

    /** Returns an ImageIcon, or null if the path was invalid. */
    protected static ImageIcon createImageIcon(String path) {
        java.net.URL imgURL = ComboBoxJTableDemo.class.getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("ComboBoxDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        JComponent newContentPane = new ComboBoxJTableDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}
Last edited by Luke on Thu Jul 05, 2012 12:06 pm, edited 1 time in total.
Είμαι ένας μοναχικός cowboy...
User avatar
Van51
Kilobyte level
Kilobyte level
Posts: 429
Joined: Tue Dec 02, 2008 8:41 pm
Academic status: N>4
Gender:

Re: κατασκευή JTable δυναμικά μέσα από listener handler

Post by Van51 » Wed Jul 04, 2012 1:40 pm

Luke wrote:Προσπαθώ να κάνω χρήση JTable για να βελτιώσω σε μία παλιά εφαρμογή τον τρόπο με τον οποίο παρουσιάζονται τα δεδομένα που λαμβάνονται από μία βάση δεδομένων. Για το σκοπό αυτό έχω ένα combo box και ανάλογα με την επιλογή που κάνω επιστρέφονται άλλα δεδομένα με βάση κάποια προκαθορισμένα queries. Με λίγα λόγια θέλω το μοντέλο του JTable (πλήθος και ονόματα στηλών αλλά και πλειάδες δεδομένων) να αλλάζει δυναμικά ανάλογα με την επιλογή στο combo box.

Όταν φτιάχνω και γεμίζω "καρφωτά" το JTable μέσα από τον κατασκευαστή της Demo κλάσης που έχω, το JTable εμφανίζεται κανονικά.
Όταν όμως πάω να το παράγω μέσα από τον listener handler (actionPerformed()) τότε δεν εμφανίζεται τίποτα...
Είμαι πεπεισμένος ότι κάνω πολύ τραγικό λάθος αλλά δε μπορώ να δω τι ακριβώς. Παραθέτω ενδεικτικό κώδικα (είναι απλοποιημένος ώστε να μην περιλαμβάνει το κομμάτι της βάσης δεδομένων και να τρέχει standalone) αν μπορεί να βοηθήσει κάποιος.
Έχω βάλει να εμφανίζεται το table (μία μόνο πλειάδα) όταν επιλέγουμε την "Customers" option στον listener.

Code: Select all

package comboboxjtabledemo;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.Vector;

public class ComboBoxJTableDemo extends JPanel implements ActionListener {
    JLabel picture;
    JTable table;
    JScrollPane scroll;
    String[] columnNames;
    DefaultTableModel model;

    public ComboBoxJTableDemo() {
        super(new BorderLayout());

        String[] options = { "Customers", "Agencies", "Rooms", "Employees", "Services" };

        //Create the combo box, select the item at index 1.
        JComboBox optionList = new JComboBox(options);
        optionList.setSelectedIndex(1);
        optionList.addActionListener(this);

        //Set up the picture.
        picture = new JLabel();
        picture.setFont(picture.getFont().deriveFont(Font.ITALIC));
        picture.setHorizontalAlignment(JLabel.CENTER);
        //updateLabel(options[optionList.getSelectedIndex()]);
        picture.setBorder(BorderFactory.createEmptyBorder(10,0,0,0));

        //The preferred size is hard-coded to be the width of the
        //widest image and the height of the tallest image + the border.
        //A real program would compute this.
        picture.setPreferredSize(new Dimension(177, 122+10));

        //Lay out the demo.
        add(optionList, BorderLayout.PAGE_START);
        add(picture, BorderLayout.PAGE_END);
        setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
        
        
        /*TESTING code from within constructor*/
        
        /*
        columnNames[0] = "ID";
        columnNames[1] = "Name";
        columnNames[2] = "Surname";
        columnNames[3] = "Father name";
        columnNames[4] = "Address";
        olumnNames[5] = "Telephone";
        columnNames[6] = "County";
        columnNames[7] = "City";
        model = new DefaultTableModel(columnNames, 0);
            
        Vector<String> row = new Vector<String>();
        row.add("1");
        row.add("John");
        row.add("Johnakis");
        row.add("Sr. John");
        row.add("Adamantos 4");
        row.add("0123456789");
        row.add("Papua New Guinea");
        row.add("Noland");
        model.addRow(row);
            
        table = new JTable(model);
        scroll = new JScrollPane(table);
        add(scroll);*/
    }

    /** Listens to the combo box. */
    public void actionPerformed(ActionEvent e) {
        JComboBox cb = (JComboBox)e.getSource();
        String option = (String)cb.getSelectedItem();
        
        if (option.equals("Customers"))
        {
            columnNames[0] = "ID";
            columnNames[1] = "Name";
            columnNames[2] = "Surname";
            columnNames[3] = "Father name";
            columnNames[4] = "Address";
            columnNames[5] = "Telephone";
            columnNames[6] = "County";
            columnNames[7] = "City";
            model = new DefaultTableModel(columnNames, 0); //0 data rows for the moment
            
            //add 1 record/row manually just for testing
            Vector<String> row = new Vector<String>();
            row.add("1");
            row.add("John");
            row.add("Johnakis");
            row.add("Sr. John");
            row.add("Adamantos 4");
            row.add("0123456789");
            row.add("Papua New Guinea");
            row.add("Noland");
            model.addRow(row);
            
            table = new JTable(model);
        }
        else //just to prevent Null Pointer Exception
        {
            table = new JTable();
        }
        scroll = new JScrollPane(table);
        add(scroll);
        table.updateUI();
    }

    /** Returns an ImageIcon, or null if the path was invalid. */
    protected static ImageIcon createImageIcon(String path) {
        java.net.URL imgURL = ComboBoxJTableDemo.class.getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("ComboBoxDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        JComponent newContentPane = new ComboBoxJTableDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}
Κάτι πρέπει να παίζει με τον LayoutManager όταν προσθέτεις το νέο JScrollPane στο JPanel σου απ' τον Listener. Δοκίμασα μήπως ήθελε remove το προηγούμενο, αλλά δεν δούλεψε. Πάντως αν αντί να δημιουργήσω νέο ScrollPane, απλά αλλάξω το viewport του τωρινού, δουλεύει κανονικά :

Code: Select all

....
/* αντί για αυτό */
//scroll = new JScrollPane(table);
//add(scroll);

/* αυτό */
scroll.setViewportView(table);

table.updateUI();
 
User avatar
Luke
Gbyte level
Gbyte level
Posts: 1388
Joined: Wed Aug 09, 2006 11:19 am
Academic status: Alumnus/a
Gender:

Re: κατασκευή JTable δυναμικά μέσα από listener handler

Post by Luke » Wed Jul 04, 2012 1:54 pm

Ευχαριστώ Van51 για τη γρήγορη απάντηση. ;)

Βασικά στον κώδικα που λες δεν έχει γίνει αρχικοποίηση του scroll object οπότε θα πετάξει NullPointerException. Εκτός κι αν προσθέσω και το

Code: Select all

scroll = new JScrollPane();
αλλά και πάλι δε μου εμφανίζει το JTable.
Μήπως έχεις κάνει και κάποια άλλη αλλαγή στον κώδικα; Μπορείς να παραθέσεις full τον κώδικα που σου δούλεψε;
Είμαι ένας μοναχικός cowboy...
User avatar
Van51
Kilobyte level
Kilobyte level
Posts: 429
Joined: Tue Dec 02, 2008 8:41 pm
Academic status: N>4
Gender:

Re: κατασκευή JTable δυναμικά μέσα από listener handler

Post by Van51 » Wed Jul 04, 2012 1:58 pm

Luke wrote:Ευχαριστώ Van51 για τη γρήγορη απάντηση. ;)

Βασικά στον κώδικα που λες δεν έχει γίνει αρχικοποίηση του scroll object οπότε θα πετάξει NullPointerException. Εκτός κι αν προσθέσω και το

Code: Select all

scroll = new JScrollPane();
αλλά και πάλι δε μου εμφανίζει το JTable.
Μήπως έχεις κάνει και κάποια άλλη αλλαγή στον κώδικα; Μπορείς να παραθέσεις full τον κώδικα που σου δούλεψε;
Το scroll το είχα αφήσει να δημιουργείται στον constructor.
Ορίστε ο κώδικας πάντως :

Code: Select all


    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.table.*;
    import java.util.Vector;

    public class ComboBoxJTableDemo extends JPanel implements ActionListener {
        JLabel picture;
        JTable table;
        JScrollPane scroll;
        String[] columnNames;
        DefaultTableModel model;

        public ComboBoxJTableDemo() {
            super(new BorderLayout());

            String[] options = { "Customers", "Agencies", "Rooms", "Employees", "Services" };

            //Create the combo box, select the item at index 1.
            JComboBox optionList = new JComboBox(options);
            optionList.setSelectedIndex(1);
            optionList.addActionListener(this);

            //Set up the picture.
            picture = new JLabel();
            picture.setFont(picture.getFont().deriveFont(Font.ITALIC));
            picture.setHorizontalAlignment(JLabel.CENTER);
            //updateLabel(options[optionList.getSelectedIndex()]);
            picture.setBorder(BorderFactory.createEmptyBorder(10,0,0,0));

            //The preferred size is hard-coded to be the width of the
            //widest image and the height of the tallest image + the border.
            //A real program would compute this.
            picture.setPreferredSize(new Dimension(177, 122+10));

            //Lay out the demo.
            add(optionList, BorderLayout.PAGE_START);
            add(picture, BorderLayout.PAGE_END);
            setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
           
           
            /*TESTING code from within constructor*/
           
            columnNames = new String[8];
            columnNames[0] = "ID";
            columnNames[1] = "Name";
            columnNames[2] = "Surname";
            columnNames[3] = "Father name";
            columnNames[4] = "Address";
            columnNames[5] = "Telephone";
            columnNames[6] = "County";
            columnNames[7] = "City";
            model = new DefaultTableModel(columnNames, 0);
               
            Vector<String> row = new Vector<String>();
            row.add("1");
            row.add("John");
            row.add("Johnakis");
            row.add("Sr. John");
            row.add("Adamantos 4");
            row.add("0123456789");
            row.add("Papua New Guinea");
            row.add("Noland");
            model.addRow(row);
               
            table = new JTable(model);
            scroll = new JScrollPane(table);
            add(scroll);
        }

        /** Listens to the combo box. */
        public void actionPerformed(ActionEvent e) {
            JComboBox cb = (JComboBox)e.getSource();
            String option = (String)cb.getSelectedItem();
           
            if (option.equals("Customers"))
            {
                columnNames[0] = "ID";
                columnNames[1] = "Name";
                columnNames[2] = "Surname";
                columnNames[3] = "Father name";
                columnNames[4] = "Address";
                columnNames[5] = "Telephone";
                columnNames[6] = "County";
                columnNames[7] = "City";
                model = new DefaultTableModel(columnNames, 0); //0 data rows for the moment
               
                //add 1 record/row manually just for testing
                Vector<String> row = new Vector<String>();
                row.add("1");
                row.add("JohnIS");
                row.add("Johnakis");
                row.add("Sr. John");
                row.add("Adamantos 4");
                row.add("0123456789");
                row.add("Papua New Guinea");
                row.add("Noland");
                model.addRow(row);
               
                table = new JTable(model);
		
            }
            else //just to prevent Null Pointer Exception
            {
                table = new JTable();
            }
	//	remove(scroll);
       //     scroll = new JScrollPane(table);
		scroll.setViewportView(table);
         //  add(scroll,BorderLayout.CENTER);
	//	invalidate();
            table.updateUI();
        }

        /** Returns an ImageIcon, or null if the path was invalid. */
        protected static ImageIcon createImageIcon(String path) {
            java.net.URL imgURL = ComboBoxJTableDemo.class.getResource(path);
            if (imgURL != null) {
                return new ImageIcon(imgURL);
            } else {
                System.err.println("Couldn't find file: " + path);
                return null;
            }
        }

        /**
         * Create the GUI and show it.  For thread safety,
         * this method should be invoked from the
         * event-dispatching thread.
         */
        private static void createAndShowGUI() {
            //Create and set up the window.
            JFrame frame = new JFrame("ComboBoxDemo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            //Create and set up the content pane.
            JComponent newContentPane = new ComboBoxJTableDemo();
            newContentPane.setOpaque(true); //content panes must be opaque
            frame.setContentPane(newContentPane);

            //Display the window.
            frame.pack();
            frame.setVisible(true);
        }

        public static void main(String[] args) {
            //Schedule a job for the event-dispatching thread:
            //creating and showing this application's GUI.
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGUI();
                }
            });
        }
    }
User avatar
Luke
Gbyte level
Gbyte level
Posts: 1388
Joined: Wed Aug 09, 2006 11:19 am
Academic status: Alumnus/a
Gender:

Re: κατασκευή JTable δυναμικά μέσα από listener handler

Post by Luke » Wed Jul 04, 2012 8:20 pm

Να 'σαι καλά Van51. Πολύτιμη η βοήθειά σου! Δε μπορείς να φανταστείς τι κόλλημα είχα φάει από χθες...
Η setViewportView() έκανε ουσιαστικά τη δουλειά σε συνδυασμό βέβαια με τις αρχικοποιήσεις που πήγαν όλες στον κατασκευαστή.

Τώρα βέβαια το γιατί βοήθησε η συγκεκριμένη μέθοδος να σου πω την αλήθεια δεν το κατάλαβα. :lol:
Αν έχει κανείς γνώση ας μας πει, για το εκπαιδευτικό του πράγματος. ;)
Είμαι ένας μοναχικός cowboy...
User avatar
Van51
Kilobyte level
Kilobyte level
Posts: 429
Joined: Tue Dec 02, 2008 8:41 pm
Academic status: N>4
Gender:

Re: κατασκευή JTable δυναμικά μέσα από listener handler

Post by Van51 » Wed Jul 04, 2012 8:39 pm

Από το documentation της add : "If the container has already been displayed, the hierarchy must be validated thereafter in order to display the added component.".
Οπότε το δοκίμασα με τον αρχικό σου κώδικα και μετά από την add, κάλεσα την validate() και δούλεψε (έχοντας κάνει όμως και remove το προηγούμενο scroll απ' το
panel). Άμα διαβάσεις και το documentation της validate, εξηγεί ποια είναι η δουλειά της! Οπότε λογικά με το την setViewportView δούλεψε επειδή έχει ήδη εμφανιστεί το component και άρα δεν χρειάζεται η validate και θα αναλαμβάνει το ίδιο την ανανέωση του περιεχομένου του.
User avatar
Luke
Gbyte level
Gbyte level
Posts: 1388
Joined: Wed Aug 09, 2006 11:19 am
Academic status: Alumnus/a
Gender:

Re: κατασκευή JTable δυναμικά μέσα από listener handler

Post by Luke » Thu Jul 05, 2012 12:06 pm

Σωστός!
Είμαι ένας μοναχικός cowboy...
Post Reply

Return to “Προγραμματισμός”