簡體   English   中英

如何使 JButton 在 JTable 中可點擊

[英]How to make JButton clickable in JTable

我有一個程序,其中大多數單元格中有一個帶有文本的 JTable,但是每行中的最后一個單元格我需要有一個 JButton。 我正在使用自定義按鈕渲染器和編輯器(我不希望用戶編輯表中任何內容的內容)。 我不確定如何讓我的按鈕可點擊。 我的主要代碼是:

起點.java

import java.util.Vector;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class StartingPoint {
    public static void main(String[] args) {
        String column_names[] = {"Text", "Button"};
        DefaultTableModel dtm = new DefaultTableModel(column_names, 0);

        JButton button1 = new JButton();
        button1.setText("Button 1");
        button1.setToolTipText("Button");

        JButton button2 = new JButton();
        button2.setText("Button 2");
        button2.setToolTipText("Buttonnn");

        Vector<Object> row1 = new Vector<Object>();
        row1.add("Testing");
        row1.add(button1);

        Vector<Object> row2 = new Vector<Object>();
        row2.add("More Testing");
        row2.add(button2);

        dtm.addRow(row1);
        dtm.addRow(row2);

        JTable table = new JTable(dtm);
        JScrollPane scrolly = new JScrollPane(table);
        table.setFillsViewportHeight(true);

        JTableButtonRenderer buttonRenderer = new JTableButtonRenderer();
        JTableButtonEditor buttonEditor = new JTableButtonEditor();
        table.getColumn("Button").setCellRenderer(buttonRenderer);
        table.getColumn("Button").setCellEditor(buttonEditor);

        JFrame frame = new JFrame("Testing");
        frame.getContentPane().add(scrolly);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

JTableButtonRenderer

import java.awt.Component;

import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

public class JTableButtonRenderer implements TableCellRenderer {
    JTableButtonRenderer() {}
    @Override
    public Component getTableCellRendererComponent(JTable table, Object 
value, boolean isSelected, boolean hasFocus, int rows, int columns) {
        JButton button = (JButton)value;
        return button;
    }
}

JTableButtonEditor.java

import java.awt.Component;
import java.util.EventObject;

import javax.swing.JTable;
import javax.swing.event.CellEditorListener;
import javax.swing.table.TableCellEditor;

public class JTableButtonEditor implements TableCellEditor {

    @Override
    public void addCellEditorListener(CellEditorListener arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void cancelCellEditing() {
        // TODO Auto-generated method stub

    }

    @Override
    public Object getCellEditorValue() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isCellEditable(EventObject arg0) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void removeCellEditorListener(CellEditorListener arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean shouldSelectCell(EventObject arg0) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean stopCellEditing() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public Component getTableCellEditorComponent(JTable arg0, Object arg1, 
boolean arg2, int arg3, int arg4) {
        // TODO Auto-generated method stub
        return null;
    }

}

我需要更改渲染器/編輯器類中的某些內容嗎? 我還嘗試在創建按鈕時在我的開始點類中添加動作偵聽器。

“概念上”,這個想法非常簡單,在如何使用表格中有詳細介紹

您需要從定義編輯器(和渲染器)開始。 為簡單起見,我選擇將兩者包裝在一起,因為兩者都重復了大部分功能。

public class TableDeleteButtonEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {

    private File source;
    private JButton button;

    public TableDeleteButtonEditor() {
        button = new JButton();
        button.addActionListener(new LoadActionListener());
    }

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

    protected JButton prepare(JTable table, Object value, boolean isSelected, int row, int column) {
        if (!(value instanceof File)) {
            source = null;
            button.setEnabled(false);
            return null;
        }
        source = (File) value;
        button.setEnabled(true);
        button.setText(source.getName());
        button.setToolTipText(source.getPath());
        return button;
    }

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

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

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

    public class LoadActionListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent evt) {
            // Here, you need to make some decisions about what to do...
            // You have a reference to the File instance
            System.out.println("You clicked " + source);
            stopCellEditing();
        }

    }
}

由於您可能只有一個活動編輯器,因此在調用getTableCellEditorComponent時,您需要獲取對基礎數據的引用(即File引用)。

通常,編輯器會將一個值返回給模型,在這種情況下,我不確定這是否有意義。 不是說你做不到,但我會質疑目的。

對於我的示例,我只需要對File本身的引用,因此,從技術上講,我只需要一列。 相反,我設計了一個需要兩列的模型,但使用File的引用來填充這兩列。 這是一個簡潔的示例,它演示了將“簡單”對象擴展為多個部分並以不同方式由模型表示的能力......

public class FileTableModel extends AbstractTableModel {

    private List<File> files;

    public FileTableModel(List<File> files) {
        this.files = files;
    }

    @Override
    public int getRowCount() {
        return files.size();
    }

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

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

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch (columnIndex) {
            case 1: return File.class;
            default: return String.class;
        }
    }

    @Override
    public Object getValueAt(int row, int col) {
        File file = files.get(row);
        switch (col) {
            case 0: return file.getName();
            case 1: return file;
        }
        return null;
    }

}

現在,這里的重要部分是isCellEditablegetColumnClass方法。 這些有助於確定可以編輯哪些單元格並提供一個入口點來查找JTable渲染器/編輯器,這將我們帶到下一步,您需要配置JTable以支持您的自定義編輯器/渲染器

有幾種方法可以做到這一點,但為了簡單起見, setDefaultRenderersetDefaultEditor應該可以正常工作......

List<File> files = Arrays.asList(new File(".").listFiles());
FileTableModel model = new FileTableModel(files);
JTable table = new JTable(model);
table.setDefaultEditor(File.class, new TableDeleteButtonEditor());
table.setDefaultRenderer(File.class, new TableDeleteButtonEditor());

注意:您可以使用TableDeleteButtonEditor的單個實例,我只是懶得復制和粘貼

從那里,您現在應該能夠在JTable表示File的列表,其中最后一列是一個按鈕(帶有文件名),在此示例中,單擊時將打印File引用

可運行示例...

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Arrays;
import java.util.EventObject;
import java.util.List;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new BorderLayout());

            List<File> files = Arrays.asList(new File(".").listFiles());
            FileTableModel model = new FileTableModel(files);
            JTable table = new JTable(model);
            table.setDefaultEditor(File.class, new TableDeleteButtonEditor());
            table.setDefaultRenderer(File.class, new TableDeleteButtonEditor());

            add(new JScrollPane(table));
        }

    }

    public class FileTableModel extends AbstractTableModel {

        private List<File> files;

        public FileTableModel(List<File> files) {
            this.files = files;
        }

        @Override
        public int getRowCount() {
            return files.size();
        }

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

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

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            switch (columnIndex) {
                case 1:
                    return File.class;
                default:
                    return String.class;
            }
        }

        @Override
        public Object getValueAt(int row, int col) {
            File file = files.get(row);
            switch (col) {
                case 0:
                    return file.getName();
                case 1:
                    return file;
            }
            return null;
        }

    }

    public class TableDeleteButtonEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {

        private File source;
        private JButton button;

        public TableDeleteButtonEditor() {
            button = new JButton();
            button.addActionListener(new LoadActionListener());
        }

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

        protected JButton prepare(JTable table, Object value, boolean isSelected, int row, int column) {
            if (!(value instanceof File)) {
                source = null;
                button.setEnabled(false);
                return null;
            }
            source = (File) value;
            button.setEnabled(true);
            button.setText(source.getName());
            button.setToolTipText(source.getPath());
            return button;
        }

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

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

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

        public class LoadActionListener implements ActionListener {

            @Override
            public void actionPerformed(ActionEvent evt) {
                // Here, you need to make some decisions about what to do...
                // You have a reference to the File instance
                System.out.println("You clicked " + source);
                stopCellEditing();
            }

        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM