Swing JButton in JTable-Zelle: Event-Problem

pcworld

Grünschnabel
JButton in JTable-Zelle: Event-Problem

Hallo,

ich stehe momentan vor dem Problem, dass ich einen interaktiven JButton in eine Zelle einer JTable bauen will. Im Internet findet man auch einiges an Code, allerdings habe ich noch keinen gefunden, der meine Wünsche ganz erfüllt.
Ich will, dass er sich vom Look&Feel nicht unterscheidet von Buttons in richtigen Containern. Sprich er soll seine Animationen beim Herüberfahren, Anklicken, Loslassen der Maustaste usw. beibehalten.
Dabei bin ich im Internet auf diesen Code gestoßen, dieser benutzt die Event-Weiterleitung. Die Methode mit dem TableCellRenderer finde ich nicht wirklich praktisch. Diesen habe ich etwas umgebaut und sieht jetzt so aus:

Java:
import java.awt.*;
import java.awt.event.*;

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

class JTableButtonRenderer implements TableCellRenderer {
    private TableCellRenderer defaultRenderer;

    public JTableButtonRenderer(TableCellRenderer renderer) {
        defaultRenderer = renderer;
    }

    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {
        if (value instanceof Component)
            return (Component) value;
        return defaultRenderer.getTableCellRendererComponent(table, value,
                isSelected, hasFocus, row, column);
    }
}

class JTableButtonModel extends AbstractTableModel {

    JButton buttonOne = new JButton("Button One");
    private Object[][] rows = { { "One", buttonOne },
            { "Two", new JButton("Button Two") },
            { "Three", new JButton("Button Three") },
            { "Four", new JButton("Button Four") } };

    public JTableButtonModel() {
        buttonOne.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                System.out.println("button clicked");
            }
        });
    }

    private String[] columns = { "Numbers", "Buttons" };

    public String getColumnName(int column) {
        return columns[column];
    }

    public int getRowCount() {
        return rows.length;
    }

    public int getColumnCount() {
        return columns.length;
    }

    public Object getValueAt(int row, int column) {
        return rows[row][column];
    }

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

    public Class<?> getColumnClass(int column) {
        return getValueAt(0, column).getClass();
    }
}

class JTableButtonMouseListener implements MouseListener, MouseMotionListener {

    private JTable table;

    private void forwardEventToButton(MouseEvent e) {
        int row = table.rowAtPoint(e.getPoint());
        int column = table.columnAtPoint(e.getPoint());

        Object value;
        JButton button;
        MouseEvent buttonEvent;

        if (row >= table.getRowCount() || row < 0
                || column >= table.getColumnCount() || column < 0)
            return;

        value = table.getValueAt(row, column);

        if (!(value instanceof JButton))
            return;

        button = (JButton) value;

        buttonEvent = (MouseEvent) SwingUtilities.convertMouseEvent(table, e,
                button);
        button.dispatchEvent(buttonEvent);
        // This is necessary so that when a button is pressed and released
        // it gets rendered properly. Otherwise, the button may still appear
        // pressed down when it has been released.
        table.repaint();
    }

    private JButton oldEntered = null;

    public JTableButtonMouseListener(JTable table) {
        this.table = table;
    }

    public void mouseClicked(MouseEvent e) {
        forwardEventToButton(e);
    }

    public void mouseEntered(MouseEvent e) {
        // forwardEventToButton(e);
    }

    public void mouseExited(MouseEvent e) {
        // forwardEventToButton(e);
    }

    public void mousePressed(MouseEvent e) {
        forwardEventToButton(e);
    }

    public void mouseReleased(MouseEvent e) {
        forwardEventToButton(e);
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        // TODO Auto-generated method stub
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        MouseEvent enteredEvent = new MouseEvent(e.getComponent(),
                MouseEvent.MOUSE_ENTERED, e.getWhen(), e.getModifiers(), e
                        .getX(), e.getY(), e.getClickCount(), e
                        .isPopupTrigger(), e.getButton());
        forwardEventToButton(enteredEvent);
    }
}

public final class JTableButton extends JFrame {
    private JTable table;
    private JScrollPane scrollPane;

    public JTableButton() {
        super("JTableButton Demo");
        TableCellRenderer defaultRenderer;

        table = new JTable(new JTableButtonModel());
        defaultRenderer = table.getDefaultRenderer(JButton.class);
        table.setDefaultRenderer(JButton.class, new JTableButtonRenderer(
                defaultRenderer));
        table.setPreferredScrollableViewportSize(new Dimension(400, 200));
        JTableButtonMouseListener listener = new JTableButtonMouseListener(
                table);
        table.addMouseListener(listener);
        table.addMouseMotionListener(listener);

        scrollPane = new JScrollPane(table);
        setContentPane(scrollPane);
    }

    public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

        JFrame frame;
        frame = new JTableButton();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

Ich habe auch einen MouseMotion-Listener eingebaut, mit dem ich es auch hingebracht habe, ein mouseMoved-Event in ein MouseEvent.MOUSE_ENTERED-Event zu verwandeln. D. h., es wird eine Animation angezeigt, wenn ich mit der Maus über die Buttons fahre. Allerdings habe ich da das Probleme, dass wenn ich die JTable verlasse, der zuletzt "berührte" Button noch verfärbt ist, da er kein MouseEvent.MOUSE_EXITED-Event erhält. Auch da habe ich schon rumprobiert und habe versucht, den zuletzt berührten Button abzuspeichern und dann gegebenfalls ein MOUSE_RELEASED-Event zu senden, ganz geklappt hat das allerdings nicht.
Auch besteht das Problem, dass der Button auf Klicks nicht reagiert - warum, weiß ich noch nicht.

Wäre nett, wenn mir jemand helfen könnte - vielen Dank für die Antworten schon einmal im Voraus!
 
Zuletzt bearbeitet:
Zurück