3

I'm getting a strange bug. I have my song's list on the right side of a JFrame. When I click once on any item it does what i want: set color to Gray. But on double click it shows the Class' descriptor of my Custom table cell.

When I click once (correct)

enter image description here

When I click twice (bug)

enter image description here

Heres my code

PanelItem class

package dierplayer;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

/**
 * @author srnec
 */
public class PanelItem extends javax.swing.JPanel implements TableCellRenderer {

    private Thread focusThread;
    private int startPosX, startPosY;

    public PanelItem() {
        initComponents();
        this.setPreferredSize(new Dimension(20, 30));
        startPosX = songLabel.getX();
        startPosY = songLabel.getY();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        songLabel = new javax.swing.JLabel();

        songLabel.setText("Song");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(songLabel)
                .addGap(0, 88, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(songLabel)
                .addGap(0, 45, Short.MAX_VALUE))
        );
    }// </editor-fold>                        


    // Variables declaration - do not modify                     
    private javax.swing.JLabel songLabel;
    // End of variables declaration                   

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

        this.setSelected(isSelected);

        return this;

    }

    public void setSelected(boolean isSelected) {
        if (isSelected) {
            this.setBackground(Color.GRAY);
        } else {
            this.setBackground(Color.WHITE);
        }
    }
}   

PanelItemEditor class

package dierplayer;

import java.awt.Component;
import java.util.EventObject;
import javax.swing.JTable;
import javax.swing.event.CellEditorListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

/**
 * @author srnec
 */
public class PanelItemEditor extends DefaultTableModel implements  TableCellEditor{


    @Override
    public boolean isCellEditable(int row,int column)
    {
        return false;
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public Object getCellEditorValue() {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public boolean isCellEditable(EventObject anEvent) {
     return false;
    }

    @Override
    public boolean shouldSelectCell(EventObject anEvent) {
       return true;
    }

    @Override
    public boolean stopCellEditing() {
        return true;
    }

    @Override
    public void cancelCellEditing() {

    }

    @Override
    public void addCellEditorListener(CellEditorListener l) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void removeCellEditorListener(CellEditorListener l) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

}

MainContext class

package dierplayer;

import java.io.File;
import java.util.Vector;
import javax.swing.JFileChooser;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

/**
 * @author srnec
 */
public class MainContext extends javax.swing.JFrame 
{

    private DierPlayer mainPlayer;
    public MainContext() 
    {
        initComponents();
        mainPlayer=new DierPlayer();

        songList.setCellEditor(new PanelItemEditor());
        songList.getColumnModel().getColumn(0).setCellRenderer(new PanelItem());

        DefaultTableModel dtm = (DefaultTableModel) songList.getModel();

        Vector v = new Vector();
        v.add(new PanelItem());
        dtm.addRow(v);  
        v.clear();
        v.add(new PanelItem());
        dtm.addRow(v);
        v.clear();
        v.add(new PanelItem());
        dtm.addRow(v);

    }


    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        progressPanel = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        songList = new javax.swing.JTable();
        MainMenuBar = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        OpenMenuItem = new javax.swing.JMenuItem();
        jMenu2 = new javax.swing.JMenu();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        progressPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());

        javax.swing.GroupLayout progressPanelLayout = new javax.swing.GroupLayout(progressPanel);
        progressPanel.setLayout(progressPanelLayout);
        progressPanelLayout.setHorizontalGroup(
            progressPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 582, Short.MAX_VALUE)
        );
        progressPanelLayout.setVerticalGroup(
            progressPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 55, Short.MAX_VALUE)
        );

        songList.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "Title 1"
            }
        ));
        jScrollPane2.setViewportView(songList);

        jMenu1.setText("File");

        OpenMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        OpenMenuItem.setText("Open");
        OpenMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                OpenMenuItemActionPerformed(evt);
            }
        });
        jMenu1.add(OpenMenuItem);

        MainMenuBar.add(jMenu1);

        jMenu2.setText("Edit");
        MainMenuBar.add(jMenu2);

        setJMenuBar(MainMenuBar);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(progressPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 0, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 488, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(progressPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );

        pack();
    }// </editor-fold>                        

    private void OpenMenuItemActionPerformed(java.awt.event.ActionEvent evt) {                                             
        JFileChooser chooser = new JFileChooser();
        chooser.setMultiSelectionEnabled(true);
        chooser.showOpenDialog(this);
        File[] files = chooser.getSelectedFiles();

    }                                            

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(MainContext.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(MainContext.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(MainContext.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(MainContext.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new MainContext().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JMenuBar MainMenuBar;
    private javax.swing.JMenuItem OpenMenuItem;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenu jMenu2;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JPanel progressPanel;
    private javax.swing.JTable songList;
    // End of variables declaration                   
}
dic19
  • 17,821
  • 6
  • 40
  • 69
Ján Srniček
  • 505
  • 1
  • 10
  • 34
  • My bad,sorry for that – Ján Srniček Feb 01 '14 at 18:00
  • 2
    You'll need to provide an appropriate editor capable of representing the alue within th cell. Based on your image, you should avoid mixing components within models where possible... – MadProgrammer Feb 01 '14 at 22:22
  • what do you really want to do, (only) to use JPanel (with some JComponents) as TableCellEditor and TableCellRenderer, then answer is very simple never to put JComponents to the XxxTableModel, there could be stored only reference for TableCellRenderer, and initial value for TableCellEditor – mKorbel Feb 03 '14 at 22:57
  • What exactly were you trying to accomplish with this? Why have a `JPanel` if all you need it text? – Paul Samsotha Feb 04 '14 at 06:41
  • in this version there is a text,later there will be more informations,i want to create something like that panels in windows 8 on that left bar – Ján Srniček Feb 04 '14 at 08:51
  • So you want to be able to edit the text in the panel of the cell? Do I understand correctly? Also what else may possibly be included in the panel? – Paul Samsotha Feb 04 '14 at 09:11
  • no no,the text will be static,it will be content of for example ID3 tag(artist,album,..) the i also want to show there a delete button that will delete current component – Ján Srniček Feb 04 '14 at 12:12
  • So what do you want to occur when you double click? Also note if you want to notify a specific person, us the `@` for example @peeskillet. Or else they will not know about your comment. Since this is your question, I do not have to do that. You will automatically get notified. And what exactly is an `ID3 tag`? The reason I ask is so I could maybe work up an example, _not_ using your code. Also, _why a table_ and not a `JList` is it's only one columns? – Paul Samsotha Feb 05 '14 at 11:29
  • 1
    @peeskillet ID3 tag is part of every MP3 file,it is info about Artist,Song title,album,etc... On the double click,the song that is represented by that specific table cell will be played,also on right click there will be some menu shown(remove,...). I was first using a JList ,but in some examples on this site i found that the JTable will be bether solution,because of TableCellRenderer ,so i can render custom table cell – Ján Srniček Feb 05 '14 at 17:17

2 Answers2

1

You have stated in a comment:

On the double click,the song that is represented by that specific table cell will be played,also on right click there will be some menu shown(remove,...).

I think you're mixing up the concepts of TableCellRenderer and TableCellEditor (see Concepts: Editors and Renderers). The cell renderer should display some text, let's say the song's title, while the cell editor should allow users to modify this value. Since cell editor is automatically called when user double-clicks (or press F2 key) on a cell then providing a cell editor is not what you want. To achieve your goal you would have to follow this hints:

Prevent editing the cells

Since you want to play a song when user double-clicks on a cell then you must prevent the cell be editable (so the cell editor will not be called):

    DefaultTableModel model = new DefaultTableModel(new Object[]{"Songs list"}, 0) {
        @Override
        public boolean isCellEditable(int row, int column) {
            return false;
        }
    };

Provide a cell renderer to display the song's name

You have done this step already. Note if the only thing it will do is change the background/selection colors then you can get rid of it and simply do as follows:

    table.setBackground(Color.WHITE);
    table.setSelectionBackground(Color.GRAY);

Attach a MouseListener to the table

In order to listen double-clicks and right-clicks from user you need to attach a MouseListener to the table:

    table.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            if(e.isPopupTrigger()) {
                // show JPopupMenu here
            } else if(e.getClickCount() >= 2){
                // play the song here
            }
        }
    });

You might want to take a look to:


Example

Here's a little example you can use as a start point. Some notes:

  • IPlayableSong: this interface establishes a contract to create a self-playable song object. It's up to the implementation the way on how are these methods implemented (f.i.: library used, multithreading if needed, etc).

  • Song: it's a default implementation of previous interface. As you can see it doesn't really implement anything (throws UnsupportedOperationException) because I don't have any library to play MP3 files. But hope you get the idea.

  • Use of SwingWorker: you'll see I've used a SwingWorker to create the songs and add them to the table's model. This is because you want to get some ID3 tags from the MP3 files which implies a lot of IO operations. This kind of operations could be very time consuming and may block the Event Dispatch Thread (a.k.a. EDT) causing the GUI becomes unresponsive (freezing). So the swing worker performs these operations in a background thread and update the table model in the EDT. See more in Concurrency in Swing trial.

Code

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

public class Demo {

    private JTable table;
    private IPlayableSong currentPlayingSong;

    private void createAndShowGUI() {

        DefaultTableModel model = new DefaultTableModel(new Object[]{"Songs list"}, 0) {
            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };

        table = new JTable(model);
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                Color background = isSelected ? Color.GRAY : Color.WHITE;
                setBackground(background);

                if(value instanceof Song) {
                    Song song = (Song)value;
                    setText(song.getTitle());
                }
                return this;
            }
        });

        table.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if(e.isPopupTrigger()) {
                    // show JPopupMenu here
                } else if(e.getClickCount() >= 2){
                    int row = table.rowAtPoint(e.getPoint());
                    int column = table.columnAtPoint(e.getPoint());

                    if(currentPlayingSong != null) {
                        currentPlayingSong.stop();
                    }

                    IPlayableSong song = (IPlayableSong)table.getValueAt(row, column);
                    song.play();
                    currentPlayingSong = song;
                }
            }

        });

        JMenuItem addDir = new JMenuItem("Add dir...");
        addDir.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                addSongs();
            }
        });

        JMenu fileMenu = new JMenu("File");
        fileMenu.add(addDir);

        JMenuBar menuBar = new JMenuBar();
        menuBar.add(fileMenu);

        JFrame frame = new JFrame("Demo");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setJMenuBar(menuBar);
        frame.getContentPane().add(new JScrollPane(table));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private void addSongs() {
        final List<File> fileList = new ArrayList<>();

        File file = new File(System.getProperty("user.dir"));
        JFileChooser fileChooser = new JFileChooser(file);
        fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);        
        fileChooser.setMultiSelectionEnabled(true);
        fileChooser.setAcceptAllFileFilterUsed(false);
        fileChooser.setDialogTitle("Please select a directory");

        if(fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION && fileChooser.getSelectedFile().isDirectory()){
            File selectedDirectory = fileChooser.getSelectedFile();
            FilenameFilter filenameFilter = new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    return name.toUpperCase().endsWith("MP3");
                }
            };
            fileList.addAll(Arrays.asList(selectedDirectory.listFiles(filenameFilter)));

            DefaultTableModel model = (DefaultTableModel)table.getModel();
            model.setRowCount(0);

            SwingWorker<Void, Song> worker = new SwingWorker<Void, Song>() {
                @Override
                protected Void doInBackground() throws Exception {

                    for(File aFile : fileList) {
                        Song song = new Song(aFile, aFile.getName());
                        publish(song);
                    }
                    return null;
                }

                @Override
                protected void process(List<Song> chunks) {
                    DefaultTableModel model = (DefaultTableModel)table.getModel();
                    for(Song song: chunks) {
                        model.addRow(new Object[]{song});
                    }
                }
            };
            worker.execute();
        }

    }

    public interface IPlayableSong {

        public void play();

        public void stop();
    }

    public class Song implements IPlayableSong {

        private final String title;
        private final File file;

        public Song(File file, String title){
            this.file = file;
            this.title = title;
        }

        public String getTitle() {
            return title;
        }

        @Override
        public void play() {
            String message = String.format("Not supported yet! Trying to play %s", title);
            throw new UnsupportedOperationException(message);
        }

        @Override
        public void stop() {
            String message = String.format("Not supported yet! Trying to stop %s", title);
            throw new UnsupportedOperationException(message);
        }
    }

    public static void main(String[] args) {   
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {                
                new Demo().createAndShowGUI();
            }
        });
    }

}
dic19
  • 17,821
  • 6
  • 40
  • 69
0

I don't know exactly about your case but this is my suggest ...use that model in songList

songList.setModel(new model());

TableModel class "model"

class model extends DefaultTableModel{

model(){

super( new Object [][] {

     },
        new String [] {
            "Title 1"
        }
    );
}
    public boolean isCellEditable(int row,int column){
        return false;
    }
}
Aung Thet
  • 3,051
  • 3
  • 13
  • 18