Swing Custom JToggleButton in JTable - Click-Event geht erst beim zweiten Mal

v7t4

Mitglied
Hallo alle,

ich kriege leider keine Lösung im Internet für das folgende Problem. Es gibt ein selbst gebastelter Button, der mehrere JLabels und andere Widgets beinhalten soll und von JToggleButton erbt. Wenn ich diesen in eine Zelle von JTable tun, funktioniert das Click-Event nur beim zweiten Drucken auf die Zelle, wenn ich jedoch alle Widgets von dem Button entferne, kommt das Event sofort an dem Button an.

Gibt es vielleicht ein Workaround, dass auch das erste Click-Event an den Button durchreicht wird? Hier ist ein Beispielcode. Vielen Dank.

Java:
package sandbox;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.AbstractCellEditor;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

public class ClickableCustomButtonInTable extends JToggleButton {

	public ClickableCustomButtonInTable() {
		Dimension d = new Dimension(100, 100);
		JLabel lFirst = new JLabel("1st label");
		lFirst.setPreferredSize(d);

		JLabel lSecond = new JLabel("2nd label");
		lSecond.setPreferredSize(d);

		JPanel panel = new JPanel();
		panel.setOpaque(true);

		panel.setLayout(new BorderLayout());
		panel.add(lFirst, BorderLayout.NORTH);
		panel.add(lSecond, BorderLayout.SOUTH);
		add(panel); //if i comment this line out the click event gets triggered immediately as expected
		addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				System.out.println("Button clicked");
			}
		});
	}

	private static class CustomButtonRenderer implements TableCellRenderer {

		private final ClickableCustomButtonInTable button = new ClickableCustomButtonInTable();

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

	private static class CustomButtonEditor extends AbstractCellEditor
			implements TableCellEditor {

		private final ClickableCustomButtonInTable button = new ClickableCustomButtonInTable();

		@Override
		public Object getCellEditorValue() {
			return button.getText();
		}

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

	}

	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.setSize(new Dimension(200, 200));
		Container content = frame.getContentPane();
		TableModel model = new AbstractTableModel() {

			@Override
			public Object getValueAt(int rowIndex, int columnIndex) {
				return null;
			}

			@Override
			public int getRowCount() {
				return 1;
			}

			@Override
			public int getColumnCount() {
				return 1;
			}

			@Override
			public boolean isCellEditable(int rowIndex, int columnIndex) {
				return true;
			}

			@Override
			public Class<?> getColumnClass(int columnIndex) {
				return ClickableCustomButtonInTable.class;
			}
		};

		JTable table = new JTable(model);
		// table.setBounds(new Rectangle(0, 0, content.getWidth(), content
		// .getHeight()));
		table.setRowHeight(frame.getHeight());
		table.setDefaultRenderer(ClickableCustomButtonInTable.class,
				new CustomButtonRenderer());
		table.setDefaultEditor(ClickableCustomButtonInTable.class,
				new CustomButtonEditor());

		content.add(table);
		content.setVisible(true);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}
 
Also ich bekomme in meinem beispiel die Events genau wie erwartet.

Java:
/* (@)CellEditorFun.java */

/* Copyright 2012 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventObject;

import javax.swing.*;
import javax.swing.table.TableCellEditor;

/**
 * Tests a toggle button as table cell editor.
 * 
 * @version $Revision$ as of $Date$
 * @author Sebastian Haufe
 * @since Playground-3.8
 */
public class CellEditorFun {

  /** Creates the GUI. Call on EDT, only! */
  static void createAndShowGui() {
    final JTable table = new JTable(2, 2);
    final ToggleButtonCellEditor edi = new ToggleButtonCellEditor();
    table.setDefaultEditor(Object.class, edi);

    final JPanel contentPane = new JPanel(new BorderLayout(6, 6));
    contentPane.add(table);

    final JFrame f = new JFrame("Test Frame: CellEditorFun"); //$NON-NLS-1$
    f.setContentPane(contentPane);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.setVisible(true);
  }

  /** @param args ignored */
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

      public void run() {
        createAndShowGui();
      }
    });
  }

  private static class ToggleButtonCellEditor extends AbstractCellEditor
    implements TableCellEditor {

    private static final long serialVersionUID = 1L;
    private final JToggleButton button = new JToggleButton("Click");

    /** Creates a new {@code CellEditorFun.ToggleButtonCellEditor}. */
    public ToggleButtonCellEditor() {
      button.addActionListener(new ActionListener() {

        public void actionPerformed(ActionEvent e) {
          System.out.println("Clicked");
        }
      });
    }

    @SuppressWarnings("boxing")
    public Object getCellEditorValue() {
      return button.isSelected();
    }

    public Component getTableCellEditorComponent(
          JTable table,
          Object value,
          boolean isSelected,
          int row,
          int column) {
      button.setSelected(Boolean.TRUE.equals(value));
      return button;
    }

    @Override
    public boolean shouldSelectCell(EventObject anEvent) {
      return false;
    }
  }
}
Ebenius
 
Ja, das geht, aber nur solange der Button keinen Panel drin hat.

Das folgende würde nicht mehr gehen
add ( new JLabel("first label"))
add ( new JLabel("second label"))
 
Ähem du addest ein Panel auf einen Button? Kannst du mir den Sinn dahinter erklären? Ich bin mir nämlich nicht sicher ob das überhaupt funktionieren sollte.
 
Hm, also ein InputEvent (Mouse, Key) wird immer an die Komponente gesandt die am weitesten oben in der Z-Order liegt. Wenn Du einen Button bedeckst, dann funktioniert der ggf. nicht richtig. Wozu benötigst Du denn ein Panel das auf einem JToggleButton liegt?

Ebenius
 

Zurück
Oben