Swing Double Click bei Buttons in JTable

Tobf

Mitglied
Hallo zusammen,
ich habe ein Problem mit einer Tabelle. Es ist eine Tabelle welche eine Button-Spalte enthält. In dieser Spalte sind Buttons mit einem Icon, beim Drücken öffnet sich jeweils das Icon nochmal in Groß in einem neuen Dialog. Hierfür habe ich folgendes Beispiel/Tutorial verwendet:
https://tips4java.wordpress.com/2009/07/12/table-button-column/
Das funktioniert auch alles super, hier der Code:
Java:
public class ButtonColumn extends AbstractCellEditor
    implements TableCellRenderer, TableCellEditor, ActionListener, MouseListener
{
    private JTable table;
    private Action action;
    private int mnemonic;
    private Border originalBorder;
    private Border focusBorder;

    private JButton renderButton;
    private JButton editButton;
    private Object editorValue;
    private boolean isButtonColumnEditor;

    /**
     *  Create the ButtonColumn to be used as a renderer and editor. The
     *  renderer and editor will automatically be installed on the TableColumn
     *  of the specified column.
     *
     *  @param table the table containing the button renderer/editor
     *  @param action the Action to be invoked when the button is invoked
     *  @param column the column to which the button renderer/editor is added
     */
    public ButtonColumn(JTable table, Action action, int column)
    {
        this.table = table;
        this.action = action;

        renderButton = new JButton();
        editButton = new JButton();
        editButton.setFocusPainted( false );
        editButton.addActionListener( this );
        originalBorder = editButton.getBorder();
        setFocusBorder( new LineBorder(Color.BLUE) );

        TableColumnModel columnModel = table.getColumnModel();
        columnModel.getColumn(column).setCellRenderer( this );
        columnModel.getColumn(column).setCellEditor( this );
        table.addMouseListener( this );
    }


    /**
     *  Get foreground color of the button when the cell has focus
     *
     *  @return the foreground color
     */
    public Border getFocusBorder()
    {
        return focusBorder;
    }

    /**
     *  The foreground color of the button when the cell has focus
     *
     *  @param focusBorder the foreground color
     */
    public void setFocusBorder(Border focusBorder)
    {
        this.focusBorder = focusBorder;
        editButton.setBorder( focusBorder );
    }

    public int getMnemonic()
    {
        return mnemonic;
    }

    /**
     *  The mnemonic to activate the button when the cell has focus
     *
     *  @param mnemonic the mnemonic
     */
    public void setMnemonic(int mnemonic)
    {
        this.mnemonic = mnemonic;
        renderButton.setMnemonic(mnemonic);
        editButton.setMnemonic(mnemonic);
    }

    @Override
    public Component getTableCellEditorComponent(
        JTable table, Object value, boolean isSelected, int row, int column)
    {
        if (value == null)
        {
            editButton.setText( "" );
            editButton.setIcon( null );
        }
        else if (value instanceof Icon)
        {
            editButton.setText( "" );
            editButton.setIcon( (Icon)value );
        }
        else
        {
            editButton.setText( value.toString() );
            editButton.setIcon( null );
        }

        this.editorValue = value;
        return editButton;
    }

    @Override
    public Object getCellEditorValue()
    {
        return editorValue;
    }

//
//  Implement TableCellRenderer interface
//
    public Component getTableCellRendererComponent(
        JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
    {
        if (isSelected)
        {
            renderButton.setForeground(table.getSelectionForeground());
             renderButton.setBackground(table.getSelectionBackground());
        }
        else
        {
            renderButton.setForeground(table.getForeground());
            renderButton.setBackground(UIManager.getColor("Button.background"));
        }

        if (hasFocus)
        {
            renderButton.setBorder( focusBorder );
        }
        else
        {
            renderButton.setBorder( originalBorder );
        }

//        renderButton.setText( (value == null) ? "" : value.toString() );
        if (value == null)
        {
            renderButton.setText( "" );
            renderButton.setIcon( null );
        }
        else if (value instanceof Icon)
        {
            renderButton.setText( "" );
            renderButton.setIcon( (Icon)value );
        }
        else
        {
            renderButton.setText( value.toString() );
            renderButton.setIcon( null );
        }

        return renderButton;
    }

//
//  Implement ActionListener interface
//
    /*
     *    The button has been pressed. Stop editing and invoke the custom Action
     */
    public void actionPerformed(ActionEvent e)
    {
        int row = table.convertRowIndexToModel( table.getEditingRow() );
        fireEditingStopped();

        //  Invoke the Action

        ActionEvent event = new ActionEvent(
            table,
            ActionEvent.ACTION_PERFORMED,
            "" + row);
        action.actionPerformed(event);
    }

//
//  Implement MouseListener interface
//
    /*
     *  When the mouse is pressed the editor is invoked. If you then then drag
     *  the mouse to another cell before releasing it, the editor is still
     *  active. Make sure editing is stopped when the mouse is released.
     */
    public void mousePressed(MouseEvent e)
    {
        if (table.isEditing()
        &&  table.getCellEditor() == this)
            isButtonColumnEditor = true;
    }

    public void mouseReleased(MouseEvent e)
    {
        if (isButtonColumnEditor
        &&  table.isEditing())
            table.getCellEditor().stopCellEditing();

        isButtonColumnEditor = false;
    }

    public void mouseClicked(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
}
https://tips4java.wordpress.com/2009/07/12/table-button-column/
Nun möchte ich aber dass sich dieser Dialog nur bei einem Doppel Klick öffnet, habe nun auch schon einiges versucht. Die untere Funktion mouseClicked wird nur bei Zelle ausgeführt die keinen Button erhalten. Beim Klicken auf einen Button wird die Funktion actionPerformed ausgeführt, nur kann ich dort irgendwie keinen DoubleClick abfragen.. Ich hoffe ihr könnt mir helfen und mir vielleicht sagen an welcher Stelle es zu implementieren ist.

Vielen Dank!
 
Den Doppel-Klick kannst du in der actionPerformed(ActionEvent) nicht abfangen.

Dazu musst du deinem Button ein MouseListener hinzufügen und dort über das Event den ClickCount und welcher MouseButton dieses Event ausgelöst hat abfragen. Sollte der MouseButton der MouseEvent.BUTTON1 sein und der ClickCount == 2 weißt du, dass der Button 2 mal geklickt wurde 😉
 
Den Doppel-Klick kannst du in der actionPerformed(ActionEvent) nicht abfangen.

Dazu musst du deinem Button ein MouseListener hinzufügen und dort über das Event den ClickCount und welcher MouseButton dieses Event ausgelöst hat abfragen. Sollte der MouseButton der MouseEvent.BUTTON1 sein und der ClickCount == 2 weißt du, dass der Button 2 mal geklickt wurde 😉

Naja müssen muss er gar nicht. Er kann auch beim ersten Click einen Timer starten und wenn ein zweiter Klick kommt bevor der Timer abgelaufen ist ist es ein Doppelklick 🙂

Gruß

Claus
 
Den Doppel-Klick kannst du in der actionPerformed(ActionEvent) nicht abfangen.

Dazu musst du deinem Button ein MouseListener hinzufügen und dort über das Event den ClickCount und welcher MouseButton dieses Event ausgelöst hat abfragen. Sollte der MouseButton der MouseEvent.BUTTON1 sein und der ClickCount == 2 weißt du, dass der Button 2 mal geklickt wurde 😉

Vielen Dank für die Antwort, das habe ich versucht, hat leider nicht funktioniert. Habe im Konstuktor folgenden Code hinzugefügt:
Code:
        renderButton.addMouseListener( new MouseAdapter( )
        {
            public void mouseClicked( MouseEvent e )
            {
                System.out.println( "Render Click" );
                if ( e.getClickCount( ) == 2 )
                {
                    System.out.println( "Render DoubleClick" );
                }
            }
        } );

Hierbei werden die Ausgabe nicht angezeigt. Also der Button blinkt kurz und es wird nichts ausgegeben. Scheinbar liegt das daran dass der Button in einen EditButton und einen RenderButton "aufgeteilt" ist. Jedoch habe ich den Zusammenhang zwischen den beiden nich so wirklich verstanden. Vielleicht kann jemand da ja ein bisschen Licht ins dunkle bringen...
 
Naja müssen muss er gar nicht. Er kann auch beim ersten Click einen Timer starten und wenn ein zweiter Klick kommt bevor der Timer abgelaufen ist ist es ein Doppelklick 🙂

Gruß

Claus
Muss ich da dann nicht auch irgendwie Überprüffen, dass es die selbe Zeile ist? wie würde das denn dann aussehen? Hättest du dazu mal ein bisschen Code wie die actionPerformed Methode dann aussehen würde?
 
Scheinbar liegt das daran dass der Button in einen EditButton und einen RenderButton "aufgeteilt" ist. Jedoch habe ich den Zusammenhang zwischen den beiden nich so wirklich verstanden.
Was meinst du damit? Aus deinem obigen Code geht hervor, dass Edit und RenderButton 2 unterschiedliche JButtons sind.
 
Also hier wäre jetzt das Beispiel. Komischerweise funktioniert jetzt auch die singleClick Funktion nicht mehr.. Auf jeden Fall soll beim DoppelKlick auf "Show" eben die Action ausgeführt werden und "Open Dialog here" ausgegeben werden.. Vielleicht seht ihr ja den Fehler, ich seh den Wald vor lauter Bäumen nicht mehr...


EDIT: Hier nun ein kleines Demo-Beispiel, solltet ihr kompilieren können, beim Drücken wird etwas ausgegeben, nur hätte ich das jetzt gerne als DoppelKlick:
Code:
package me.testproject;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;

public class CopyOfTablePerson extends JFrame
{

    private JPanel contentPane;

    private JTable table;

    public static void main( String [ ] args )
    {
        CopyOfTablePerson frame = new CopyOfTablePerson( );
        frame.setVisible( true );
    }

    public CopyOfTablePerson( )
    {
        setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        setBounds( 100, 100, 450, 300 );
        contentPane = new JPanel( );
        contentPane.setLayout( new BorderLayout( 0, 0 ) );
        setContentPane( contentPane );

        String [ ] columnNames = {
                "First Name" , "Last Name" , ""
        };
        Object [ ][ ] data = {
                {
                        "Homer" , "Simpson" , "delete Homer"
                } , {
                        "Madge" , "Simpson" , "delete Madge"
                } , {
                        "Bart" , "Simpson" , "delete Bart"
                } , {
                        "Lisa" , "Simpson" , "delete Lisa"
                } ,
        };

        DefaultTableModel model = new DefaultTableModel( data, columnNames );
        JTable table = new JTable( model );

        Action delete = new AbstractAction( )
        {
            public void actionPerformed( ActionEvent e )
            {
                System.out.println( "Open Dialog here" );
            }
        };

        ButtonColumn buttonColumn = new ButtonColumn( table, delete, 2 );

        contentPane.add( table );
    }

    public class ButtonColumn extends AbstractCellEditor implements TableCellRenderer , TableCellEditor ,
            ActionListener , MouseListener
    {
        private JTable table;

        private Action action;

        private int mnemonic;

        private Border originalBorder;

        private Border focusBorder;

        private JButton renderButton;

        private JButton editButton;

        private Object editorValue;

        private boolean isButtonColumnEditor;

        public ButtonColumn( JTable table, Action action, int column )
        {
            this.table = table;
            this.action = action;

            renderButton = new JButton( );
            editButton = new JButton( );
            editButton.setFocusPainted( false );
            editButton.addActionListener( this );
            originalBorder = editButton.getBorder( );
            setFocusBorder( new LineBorder( Color.BLUE ) );

            TableColumnModel columnModel = table.getColumnModel( );
            columnModel.getColumn( column ).setCellRenderer( this );
            columnModel.getColumn( column ).setCellEditor( this );
            table.addMouseListener( this );
        }

        public Border getFocusBorder( )
        {
            return focusBorder;
        }

        public void setFocusBorder( Border focusBorder )
        {
            this.focusBorder = focusBorder;
            editButton.setBorder( focusBorder );
        }

        public int getMnemonic( )
        {
            return mnemonic;
        }

        public void setMnemonic( int mnemonic )
        {
            this.mnemonic = mnemonic;
            renderButton.setMnemonic( mnemonic );
            editButton.setMnemonic( mnemonic );
        }

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

            editButton.setText( "" );

            this.editorValue = value;
            return editButton;
        }

        @ Override
        public Object getCellEditorValue( )
        {
            return editorValue;
        }

        //
        // Implement TableCellRenderer interface
        //
        public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected,
                boolean hasFocus, int row, int column )
        {

            if ( hasFocus )
            {
                renderButton.setBorder( focusBorder );
            }
            else
            {
                renderButton.setBorder( originalBorder );
            }

            renderButton.setText( "Delete" );
            renderButton.setIcon( null );

            return renderButton;
        }

        // Implement ActionListener interface

        public void actionPerformed( ActionEvent e )
        {
            int row = table.convertRowIndexToModel( table.getEditingRow( ) );
            fireEditingStopped( );

            ActionEvent event = new ActionEvent( table, ActionEvent.ACTION_PERFORMED, "" + row );
            action.actionPerformed( event );
        }

        // Implement MouseListener interface
        public void mousePressed( MouseEvent e )
        {
            if ( table.isEditing( ) && table.getCellEditor( ) == this )
                isButtonColumnEditor = true;
        }

        public void mouseReleased( MouseEvent e )
        {
            if ( isButtonColumnEditor && table.isEditing( ) )
                table.getCellEditor( ).stopCellEditing( );

            isButtonColumnEditor = false;
        }

        public void mouseClicked( MouseEvent e )
        {
        }

        public void mouseEntered( MouseEvent e )
        {
        }

        public void mouseExited( MouseEvent e )
        {
        }
    }
}
 
Zuletzt bearbeitet:
Ich habe auch noch eine einfache Lösung gefunden.

beim Instanzieren der Tabelle nachfolgendes Überschreiben.
[CODE lang="java" title="Tabelle erstellen"]JTable table = new JTable(){
@Override
protected void processMouseEvent(MouseEvent e) {
if(e.getID() == MouseEvent.MOUSE_PRESSED) {
doubleClick = Utils.isDoubleClick(e);
}
super.processMouseEvent(e);
}};[/CODE]

wobei

[CODE lang="java" title="doubleclick"]private static Point locOnScr;
public static boolean isDoubleClick(MouseEvent e) {
boolean doubleClick = e.getClickCount() > 1 && locOnScr != null && locOnScr.distance(e.getLocationOnScreen())<10;
locOnScr = e.getLocationOnScreen();
return doubleClick;
}[/CODE]

und im Tablemodell die Funktion isCellEditable überschreiben.

[CODE lang="java" title="eigenes Tablemodel"]@Override
public boolean isCellEditable(int row, int column) {
return doubleClick && editable;
}[/CODE]
 

Zurück
Oben