Link to home
Start Free TrialLog in
Avatar of carlpaddick
carlpaddick

asked on

Drag & Drop functionality for JTable removes JTable column headers

I've been scratching my head for days trying to sort out why the following problem occurs but have been unable to find a solution.  So I would appreciate someone's help, thanks.

I'm using Java 1.3.1

I have a JTable derived class that implements drag and drop - this works fine, no problems here.  However, I want to display column headers for my JTable, so USING a created JScrollPane instance variable, I add the JTable class to it, then add it to the JPanel container that they're both contained in.  Compile, run and........

NOTHING HAPPENS!  No table column headers appear in the table!  Code wise everything seems to be present, and in my derived JTable class I override getColumnName() and return the appropriate column name.

Now here's the strange bit.  If I remove the call to add my JTable class to the JPanel container, the table column headers appear but the drag and drop operation stops working.  Reintroducing the JPanel.add(JTable) line, enables drag a drop but removes the table column headers!  Bizarre - but very annoying!

Can anyone tell me if I'm doing anything wrong or if there's some bug in JTable that doesn't allow both of these features to exist happily together. I think I read somewhere that this could possibly be a bug?  Any working code examples would be much appreciated, and I can provide code snippets of the problem if it helps.

Thanks in advance.
Avatar of Mick Barry
Mick Barry
Flag of Australia image

How can the table headers appear (and dnd work) if you DON'T add the table to the container? You must be adding the table to something.
Can u post the relevant parts of your code pls.
Avatar of Ovi
Ovi

"I add the JTable class to it, then add it to the JPanel container that they're both contained in." - you add the table twice? Once to scrollPane and secont to the JPanel? If yes add only to the scrollpane and then add the scrollpane to the panel. Anyway, you should post some code so we can test'it. Create a dummy testing aplication which follows your design and post'it here.
Avatar of carlpaddick

ASKER

Thanks for your information both of you.  I've attached snippets of the code for your inspection.  What the code does is basically allow dropping of files from the desktop into a table in a dialog.

I'm using Metroworks Code Warrior to generate my dialog.  If you haven't used it before, it basically creates a special form file (.jfrm) which you create your gui in.  After you save it, it writes out the dialog controls etc to your .java file enclosing them in sections you can't edit but it can read for later form design.  You'll see that the bits you can't edit are enclosed between // GENERATED CODE lines.

You'll also see that I've used the dialog designer to add the JScrollPane variable - jFilesScrollPane.  I then call

       jFilesScrollPane.setViewportView(jFilesTable);

a little later on to associate the table with it.  I also found that the only way that I can get drag and drop to the table to work, is to give the table variable jFilesTable a size (dimension):

        jFilesTable = new FilesTable();
        jFilesTable.setSize(new java.awt.Dimension(180, 150));
        jFilesTable.setLocation(new java.awt.Point(20, 30));
        jFilesTable.setVisible(true);

It's as if it doesn't have a size, then there's no designated droppable area defined for it and nothing happens.  Also you HAVE to add the table to the Panel that the ScrollPane's included in, aswell as the ScrollPane itself:

       FilesPanel.add(jFilesTable);
 
I haven't a clue why this is so.

The rest of the code snippets are hopefully self explanatory, but I'll explain more if need be.  I've tried many variations to get this to work, for example

1) trying jFilesScrollPane = new javax.swing.JScrollPane(jFilesTable);
2) removing the FilesPanel.add(jFilesTable); call and just adding jFilesScrollPane to the Panel

I've commented out sections of code, re-introduced it a bit of a time and still I can only get drag and drop to work WITHOUT table headers if I add the line:

       FilesPanel.add(jFilesTable);

If I comment it out then table headers are displayed but drag and drop DOESN'T work:

//       FilesPanel.add(jFilesTable);

I hope the above helps and here's the code below:

Thanks,

public class MyClass extends JDialog implements ActionListener
{

// IMPORTANT: Source code between BEGIN/END comment pair will be regenerated
// every time the form is saved. All manual changes will be overwritten.
// BEGIN GENERATED CODE
    // member declarations
    //
    // ...more control declarations here....
    //
    javax.swing.JScrollPane jFilesScrollPane = new javax.swing.JScrollPane(); // Variable that represents the Scroll Pane
// END GENERATED CODE

    // Variable that represents my table
    private FilesTable jFilesTable;

    public MyClass()
    {
        initComponents();
    }

    public void initComponents()
    {
// IMPORTANT: Source code between BEGIN/END comment pair will be regenerated
// every time the form is saved. All manual changes will be overwritten.
// BEGIN GENERATED CODE
        // the following code sets the frame's initial state
        //
        // ...more control sizing here....
        //
        jFilesScrollPane.setSize(new java.awt.Dimension(180, 150));
        jFilesScrollPane.setLocation(new java.awt.Point(20, 30));
        jFilesScrollPane.setVisible(true);

        // FilesPanel is a JPanel and declared earlier
        FilesPanel.add(jFilesScrollPane);
        getContentPane().add(FilesPanel);

// END GENERATED CODE
        addTableInfo();
        pack();
        show();
    }

    private void addTableInfo()
    {
        jFilesTable = new FilesTable();
        jFilesTable.setSize(new java.awt.Dimension(180, 150));
        jFilesTable.setLocation(new java.awt.Point(20, 30));
        jFilesTable.setVisible(true);

        jFilesTable.setModel(new FileListTableModel( fileArrayList ) );
        jFilesTable.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
        jFilesTable.getModel().addTableModelListener(new FilesListTabelModelListener());

        jFilesTable.getTableHeader().setFont(new Font("Dialog", 0, nFontSize));
              
        jFilesScrollPane.setViewportView(jFilesTable);

        FilesPanel.add(jFilesTable);
    }

    private class FilesListTabelModelListener implements TableModelListener
    {
        public void tableChanged( TableModelEvent e)
        {
            // tableChanged code......
        }
    }

    private class FilesTable extends javax.swing.JTable implements DropTargetListener
    {
        Border originalBorder = null;
        DropTarget dropTarget = new DropTarget(this, this);

        public boolean isDragAcceptable( DropTargetDragEvent event )
        {
            return event.isDataFlavorSupported( DataFlavor.javaFileListFlavor );
        }
        public boolean isDropAcceptable( DropTargetDropEvent event )
        {
            return event.isDataFlavorSupported( DataFlavor.javaFileListFlavor );
        }
        public void dragEnter( DropTargetDragEvent event )
        {
            if( !isDragAcceptable( event ) )
            {
                event.rejectDrag();
                return;
            }

            originalBorder = getBorder();

            LineBorder      theLineBorder = new LineBorder( Color.black, 2 );
            setBorder(theLineBorder);
        }
        public void dragExit( DropTargetEvent event )
        {
            setBorder(originalBorder);
        }
        public void dragOver( DropTargetDragEvent event )
        {
        }
        public void dropActionChanged( DropTargetDragEvent event )
        {
            if( !isDragAcceptable( event ) )
            {
                event.rejectDrag();
                return;
            }
        }
        public void drop( DropTargetDropEvent event )
        {
            if( isDropAcceptable( event ) )
            {
                event.acceptDrop( DnDConstants.ACTION_MOVE );
                Transferable transferable = event.getTransferable();

                try
                {
                    java.util.List filesdropped = (java.util.List)transferable.getTransferData( DataFlavor.javaFileListFlavor );

                    Iterator iter = filesdropped.iterator();
                    while( iter.hasNext() )
                    {
                        java.io.File chosenFile = (java.io.File) iter.next();

                        if (fileArrayList.contains(chosenFile) != true)
                        {
                            fileArrayList.add(chosenFile); // fileArrayList is an ArrayList
                        }
                        else
                        {
                            Toolkit.getDefaultToolkit().beep();
                        }
                    }
                    jFilesTable.revalidate();
                    jFilesTable2.getModel().broadcastTableChanged();
                }
                catch( Exception e)
                {
                    System.out.println("Exception "+ e );
                }
            }
            else
            {
                event.rejectDrop();
                return;
            }
        }
    }

    private class fileListTableModel extends javax.swing.table.AbstractTableModel
    {
        protected ArrayList data = null;

        final String[] columnNames = {"Files/Directories"};

        public fileListTableModel(ArrayList thedata )
        {
            data = thedata;
        }
        public int getColumnCount()
        {
            return 1;
        }
        public int getRowCount()
        {
            return data.size();
        }

        public String getColumnName(int col)
        {
            return columnNames[col];
        }
   
        public Object getValueAt(int row, int col)
        {
            try
            {
                File theFile = (File)data.get(row);
                return theFile.getName();
            }
            catch (Exception e)
            {
                System.out.println(" Exception "+ e );
            }
            return "";
        }
   
        public Class getColumnClass(int c)
        {
            return getValueAt(0, c).getClass();
        }
        public void broadcastTableChanged()
        {
            fireTableChanged(null);
        }
    }
}
   
Thanks for your information both of you.  I've attached snippets of the code for your inspection.  What the code does is basically allow dropping of files from the desktop into a table in a dialog.

I'm using Metroworks Code Warrior to generate my dialog.  If you haven't used it before, it basically creates a special form file (.jfrm) which you create your gui in.  After you save it, it writes out the dialog controls etc to your .java file enclosing them in sections you can't edit but it can read for later form design.  You'll see that the bits you can't edit are enclosed between // GENERATED CODE lines.

You'll also see that I've used the dialog designer to add the JScrollPane variable - jFilesScrollPane.  I then call

       jFilesScrollPane.setViewportView(jFilesTable);

a little later on to associate the table with it.  I also found that the only way that I can get drag and drop to the table to work, is to give the table variable jFilesTable a size (dimension):

        jFilesTable = new FilesTable();
        jFilesTable.setSize(new java.awt.Dimension(180, 150));
        jFilesTable.setLocation(new java.awt.Point(20, 30));
        jFilesTable.setVisible(true);

It's as if it doesn't have a size, then there's no designated droppable area defined for it and nothing happens.  Also you HAVE to add the table to the Panel that the ScrollPane's included in, aswell as the ScrollPane itself:

       FilesPanel.add(jFilesTable);
 
I haven't a clue why this is so.

The rest of the code snippets are hopefully self explanatory, but I'll explain more if need be.  I've tried many variations to get this to work, for example

1) trying jFilesScrollPane = new javax.swing.JScrollPane(jFilesTable);
2) removing the FilesPanel.add(jFilesTable); call and just adding jFilesScrollPane to the Panel

I've commented out sections of code, re-introduced it a bit of a time and still I can only get drag and drop to work WITHOUT table headers if I add the line:

       FilesPanel.add(jFilesTable);

If I comment it out then table headers are displayed but drag and drop DOESN'T work:

//       FilesPanel.add(jFilesTable);

I hope the above helps and here's the code below:

Thanks,

public class MyClass extends JDialog implements ActionListener
{

// IMPORTANT: Source code between BEGIN/END comment pair will be regenerated
// every time the form is saved. All manual changes will be overwritten.
// BEGIN GENERATED CODE
    // member declarations
    //
    // ...more control declarations here....
    //
    javax.swing.JScrollPane jFilesScrollPane = new javax.swing.JScrollPane(); // Variable that represents the Scroll Pane
// END GENERATED CODE

    // Variable that represents my table
    private FilesTable jFilesTable;

    public MyClass()
    {
        initComponents();
    }

    public void initComponents()
    {
// IMPORTANT: Source code between BEGIN/END comment pair will be regenerated
// every time the form is saved. All manual changes will be overwritten.
// BEGIN GENERATED CODE
        // the following code sets the frame's initial state
        //
        // ...more control sizing here....
        //
        jFilesScrollPane.setSize(new java.awt.Dimension(180, 150));
        jFilesScrollPane.setLocation(new java.awt.Point(20, 30));
        jFilesScrollPane.setVisible(true);

        // FilesPanel is a JPanel and declared earlier
        FilesPanel.add(jFilesScrollPane);
        getContentPane().add(FilesPanel);

// END GENERATED CODE
        addTableInfo();
        pack();
        show();
    }

    private void addTableInfo()
    {
        jFilesTable = new FilesTable();
        jFilesTable.setSize(new java.awt.Dimension(180, 150));
        jFilesTable.setLocation(new java.awt.Point(20, 30));
        jFilesTable.setVisible(true);

        jFilesTable.setModel(new FileListTableModel( fileArrayList ) );
        jFilesTable.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
        jFilesTable.getModel().addTableModelListener(new FilesListTabelModelListener());

        jFilesTable.getTableHeader().setFont(new Font("Dialog", 0, nFontSize));
              
        jFilesScrollPane.setViewportView(jFilesTable);

        FilesPanel.add(jFilesTable);
    }

    private class FilesListTabelModelListener implements TableModelListener
    {
        public void tableChanged( TableModelEvent e)
        {
            // tableChanged code......
        }
    }

    private class FilesTable extends javax.swing.JTable implements DropTargetListener
    {
        Border originalBorder = null;
        DropTarget dropTarget = new DropTarget(this, this);

        public boolean isDragAcceptable( DropTargetDragEvent event )
        {
            return event.isDataFlavorSupported( DataFlavor.javaFileListFlavor );
        }
        public boolean isDropAcceptable( DropTargetDropEvent event )
        {
            return event.isDataFlavorSupported( DataFlavor.javaFileListFlavor );
        }
        public void dragEnter( DropTargetDragEvent event )
        {
            if( !isDragAcceptable( event ) )
            {
                event.rejectDrag();
                return;
            }

            originalBorder = getBorder();

            LineBorder      theLineBorder = new LineBorder( Color.black, 2 );
            setBorder(theLineBorder);
        }
        public void dragExit( DropTargetEvent event )
        {
            setBorder(originalBorder);
        }
        public void dragOver( DropTargetDragEvent event )
        {
        }
        public void dropActionChanged( DropTargetDragEvent event )
        {
            if( !isDragAcceptable( event ) )
            {
                event.rejectDrag();
                return;
            }
        }
        public void drop( DropTargetDropEvent event )
        {
            if( isDropAcceptable( event ) )
            {
                event.acceptDrop( DnDConstants.ACTION_MOVE );
                Transferable transferable = event.getTransferable();

                try
                {
                    java.util.List filesdropped = (java.util.List)transferable.getTransferData( DataFlavor.javaFileListFlavor );

                    Iterator iter = filesdropped.iterator();
                    while( iter.hasNext() )
                    {
                        java.io.File chosenFile = (java.io.File) iter.next();

                        if (fileArrayList.contains(chosenFile) != true)
                        {
                            fileArrayList.add(chosenFile); // fileArrayList is an ArrayList
                        }
                        else
                        {
                            Toolkit.getDefaultToolkit().beep();
                        }
                    }
                    jFilesTable.revalidate();
                    jFilesTable2.getModel().broadcastTableChanged();
                }
                catch( Exception e)
                {
                    System.out.println("Exception "+ e );
                }
            }
            else
            {
                event.rejectDrop();
                return;
            }
        }
    }

    private class fileListTableModel extends javax.swing.table.AbstractTableModel
    {
        protected ArrayList data = null;

        final String[] columnNames = {"Files/Directories"};

        public fileListTableModel(ArrayList thedata )
        {
            data = thedata;
        }
        public int getColumnCount()
        {
            return 1;
        }
        public int getRowCount()
        {
            return data.size();
        }

        public String getColumnName(int col)
        {
            return columnNames[col];
        }
   
        public Object getValueAt(int row, int col)
        {
            try
            {
                File theFile = (File)data.get(row);
                return theFile.getName();
            }
            catch (Exception e)
            {
                System.out.println(" Exception "+ e );
            }
            return "";
        }
   
        public Class getColumnClass(int c)
        {
            return getValueAt(0, c).getClass();
        }
        public void broadcastTableChanged()
        {
            fireTableChanged(null);
        }
    }
}
   
ASKER CERTIFIED SOLUTION
Avatar of Mick Barry
Mick Barry
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for your information 'objects'.  I'll look into doing this, and let you know how I get on.  If you can provide me with a quick working example.  I would appreciate it too.
Hopefully the above changes should fix your problems :)
Hello objects - apologies for the delay!

Well using your advice and code snippets, I extracted my jtable out into a new jframe in a small test program, compiled and ran the program, and the drag and dropped worked!  However, here's the crazy thing - the drag and drop always worked but it would only work if the files were dragged OVER an existing row in the jtable.  If the drag was done under the last row, nothing would happen.  I guess this is due to the jtable not filling the entire jscrollpane.  Calling setPreferredSize() on the jtable to make it the same physical size as the jscrollpane allows the drag/drop operation to happen in a larger area, however the vertical scroll bar now doesn't automatically appear when there are more rows in the jtable that would naturally fit.  Also the last row can only be half seen.  I'm going to post this problem in another thread, because it's sort of a separate issue.

Thanks for clearing up the present one though and please have the points.
:-)

http://www.objects.com.au
Brainbench MVP for Java 1
http://www.brainbench.com

PS. What did I need to tell you to get an A :)
You help me out with my other question my friend and I'll definitely give you an 'A'. :o)