在JTable中使用JEditorPane而不是默认的JLabel

时间:2013-09-16 22:13:56

标签: java swing hyperlink jtable jeditorpane

尝试将JTditorPane用于JTable中的一列而没有任何成功。主要原因是我想添加一个hyperLinkListener,而JEditorPane显然应该是比默认JLabel更好的选择。

private void createQueueTable (String[] columnNames){
Object[][] rows 

    queueModel      = new DefaultTableModel(rows,columnNames){
        @Override
        public Class getColumnClass(int colNum) {
            switch (colNum) {
                case 0:
                    return String.class;
                ...
                case 9:
                    return String.class;    //Comment
                default:
                    return String.class;
            }
        }
    };

    queueTable.setModel(queueModel)    
    TableColumnModel queueTableColumnModel  = queueTable.getColumnModel();      
    TableCellRenderer tcr = new CustomTableCellRenderer();  
    TableCellRenderer scr = new        CustomTablePaneCellRenderer();                       

    int counter =0
    while(counter<columnNames.size()-1){
        queueTableColumnModel.getColumn(counter).setCellRenderer(tcr);
        counter++
    }

    queueTableColumnModel.getColumn(counter).setCellRenderer(scr);      
    ...     
}    
    public class CustomTablePaneCellRenderer extends JTextPane implements TableCellRenderer {
        public CustomTablePaneCellRenderer() {
            setContentType("text/html");
        }

         public Component getTableCellRendererComponent (JTable table, Object obj, boolean isSelected, boolean hasFocus, int row, int column) {
            Component cell = super.getTableCellRendererComponent(table, obj, isSelected, hasFocus, row, column);    
                if (isSelected) {
                 } 
                 else{
                      if (row % 2 == 0) 
                            cell.setBackground(new Color(248,248,248))
                      else
                          cell.setBackground(Color.white)
                 } 
                 return cell;
        }           
    }

Exception in thread "AWT-EventQueue-0" groovy.lang.MissingMethodException: No signature of method: CustomTablePaneCellRenderer.getTableCellRendererComponent() is applicable for argument types: (EMSMonster$1, java.lang.String, java.lang.Boolean, java.lang.Boolean, java.lang.Integer, java.lang.Integer) values: [EMSMonster$1[,0,0,1280x304,alignmentX=0.0,alignmentY=0.0,border=,flags=251658568,maximumSize=,minimumSize=,preferredSize=,autoCreateColumnsFromModel=true,autoResizeMode=AUTO_RESIZE_OFF,cell
SelectionEnabled=true,editingColumn=-1,editingRow=-1,gridColor=javax.swing.plaf.ColorUIResource[r=122,g=138,b=153],preferredViewportSize=java.awt.Dimension[width=450,height=400],rowHeight=16,rowMargin=1,rowSelectionAllowed=true,selectionBackground=javax.swing.plaf.ColorUIResource[r=184,g=207,b=229],selectionForeground=sun.swing.PrintColorUIResource[r=51,g=51,b=51],showHorizontalLines=true,showVerticalLines=true], ...]
Possible solutions: getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuperN(ScriptBytecodeAdapter.java:130)
        at CustomTablePaneCellRenderer.getTableCellRendererComponent(EMSMonster.groovy:2613)
        at javax.swing.JTable.prepareRenderer(JTable.java:5731)
        at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2114)
        at javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2016)
        at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1812)
        at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
        at javax.swing.JComponent.paintComponent(JComponent.java:778)
        at javax.swing.JComponent.paint(JComponent.java:1054)
        at javax.swing.JComponent.paintChildren(JComponent.java:887)
        at javax.swing.JComponent.paint(JComponent.java:1063)
        at javax.swing.JViewport.paint(JViewport.java:731)
        at javax.swing.JComponent.paintChildren(JComponent.java:887)
        at javax.swing.JComponent.paint(JComponent.java:1063)
        at javax.swing.JComponent.paintChildren(JComponent.java:887)
        at javax.swing.JComponent.paint(JComponent.java:1063)
        at javax.swing.JComponent.paintChildren(JComponent.java:887)
        at javax.swing.JComponent.paint(JComponent.java:1063)
        at javax.swing.JComponent.paintToOffscreen(JComponent.java:5221)
        at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1512)
        at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1443)
        at javax.swing.RepaintManager.paint(RepaintManager.java:1236)
        at javax.swing.JComponent._paintImmediately(JComponent.java:5169)
        at javax.swing.JComponent.paintImmediately(JComponent.java:4980)
        at javax.swing.RepaintManager$3.run(RepaintManager.java:796)
        at javax.swing.RepaintManager$3.run(RepaintManager.java:784)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:784)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:757)
        at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:706)
        at javax.swing.RepaintManager.access$1000(RepaintManager.java:62)
        at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1651)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:727)
        at java.awt.EventQueue.access$200(EventQueue.java:103)
        at java.awt.EventQueue$3.run(EventQueue.java:688)
        at java.awt.EventQueue$3.run(EventQueue.java:686)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:697)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

这应该是或多或少的样子。 Screenshot

阅读其他几篇文章我开始怀疑是否可能在同一个表格单元格中包含文本和可点击链接。

非常感谢任何进一步的帮助!!

1 个答案:

答案 0 :(得分:2)

  

这个的主要原因是我想添加一个   hyperLinkListener和JEditorPane显然应该是更好的选择   为此而不是默认的JLabel。

我实际上反对这一点。主要原因是,单元格渲染器只是它渲染器组件的“快照”,它不是活动组件。这意味着它不会响应用户输入,例如键或鼠标侦听器。

就个人而言,我会简单地“渲染”DefaultTableCellRenderer看起来像标准超链接。

然后我会建立一个“特殊”编辑器,它只响应鼠标点击并相应地激活超链接......

例如......

enter image description here

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.EventObject;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractCellEditor;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;

public class TableHyperLink {

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

    public TableHyperLink() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                try {
                    MyModel model = new MyModel();
                    JTable table = new JTable(model);
                    table.setDefaultRenderer(URL.class, new URLTableCellRenderer());
                    table.setDefaultEditor(URL.class, new URLTableCellEditor());

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new JScrollPane(table));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (MalformedURLException exp) {
                    exp.printStackTrace();
                }
            }
        });
    }

    public class MyModel extends DefaultTableModel {

        public MyModel() throws MalformedURLException {
            super(new Object[][]{{new URL("http://stackoverflow.com")}}, 
                    new Object[]{"Link"});
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return URL.class; // Only have one column :P
        }

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

    }

    public class URLTableCellRenderer extends DefaultTableCellRenderer {

        public URLTableCellRenderer() {
            setForeground(Color.BLUE);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); //To change body of generated methods, choose Tools | Templates.
            if (value instanceof URL) {
                value = "<html><u>" + ((URL)value).toString() + "</u></html>";
                setText(value.toString());
            }
            setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
            return this;
        }

    }

    public class URLTableCellEditor extends AbstractCellEditor implements TableCellEditor {

        private URL url;

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

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            JLabel editor = new JLabel("Clicked");
            if (value instanceof URL) {
                url = (URL) value;
                editor.setText("<html><ul>" + url.toString() + "</ul></html>");
            }
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    stopCellEditing();
                    try {
                        Desktop.getDesktop().browse(url.toURI());
                    } catch (IOException | URISyntaxException ex) {
                        ex.printStackTrace();
                    }
                }
            });
            return editor;
        }

        @Override
        public boolean isCellEditable(EventObject e) {
            boolean editable = false;
            if (e instanceof MouseEvent) {
                MouseEvent me = (MouseEvent) e;
                if (me.getClickCount() == 1 && SwingUtilities.isLeftMouseButton(me)) {
                    editable = true;
                }
            }
            return editable;
        }
    }        
}

您的另一个选择是将MouseListener附加到表格并监控鼠标点击。这将涉及您必须将鼠标点转换为列索引并确定列是否是模型中的正确列,查找模型中的值,然后根据需要对其进行处理。

它更麻烦,更不便携,容易出错 - 恕我直言

基于反馈的其他示例

我只想指出这是黑客攻击。网址提取基于Handling hyperlink right clicks on a JTextPane

的答案
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.EventObject;
import javax.swing.AbstractCellEditor;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.text.AttributeSet;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;

public class TableHyperLink {

    public static final String PASSWORD_PROMPT = "";

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

    public TableHyperLink() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                try {
                    MyModel model = new MyModel();
                    JTable table = new JTable(model);
                    TableColumn column = table.getColumn(table.getColumnName(0));
                    column.setCellEditor(new URLTableCellEditor());
                    column.setCellRenderer(new URLTableCellRenderer());

                    column = table.getColumn(table.getColumnName(1));
                    column.setCellEditor(new URLTableCellEditor());
                    column.setCellRenderer(new URLTableCellRenderer());

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new JScrollPane(table));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (MalformedURLException exp) {
                    exp.printStackTrace();
                }
            }
        });
    }

    public class MyModel extends DefaultTableModel {

        public MyModel() throws MalformedURLException {
            super(new Object[][]{
                {"<html>This is a <a href='https://stackoverflow.com/questions/18838196/using-jeditorpane-instead-of-default-jlabel-in-jtable/18838244?noredirect=1#comment27831752_18838244'>Test</a>",
                    "<html>This is a <a href='https://stackoverflow.com/questions/18838196/using-jeditorpane-instead-of-default-jlabel-in-jtable/18838244?noredirect=1#comment27831752_18838244'>Test</a>"}},
                    new Object[]{"Link", "Link1"});
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return String.class; // Only have one column :P
        }

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

    }

    /**
     * JEditorPane based renderer.  This gives me issues with fonts, so
     * you may need to do some more playing around with this to 
     * get it to work the way you want
     */
    public class URLTableCellRenderer extends JEditorPane implements TableCellRenderer {

        public URLTableCellRenderer() {
            // Set the content type
            setContentType("text/html");
            // Get rid of the default border
            setBorder(new EmptyBorder(1, 1, 1, 1));
            // Get rid of any margins
            setMargin(new Insets(0, 0, 0, 0));
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            setText(value == null ? null : value.toString());
            return this;
        }

    }

    /**
     * Drop in editor, this really is just a event factory used to capture the events
     * and process them...
     */
    public class URLTableCellEditor extends AbstractCellEditor implements TableCellEditor {

        // This is the value returned to the table model, because I've used a DefaultTableModel
        // this is very important
        private Object value;
        // The point that the mouse click occured
        private Point clickPoint;
        // The url to open
        private URL url;

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

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            // Capture the current cell value
            this.value = value;
            // Something to return to the table...
            JLabel editor = new JLabel(value == null ? null : value.toString());

            // Get the cell renderer for the current cell
            TableCellRenderer renderer = table.getCellRenderer(row, column);
            // Get the cell component for the renderer (expecting a JEditorPane)
            Component comp = table.prepareRenderer(renderer, row, column);
            // Set the bounds of the component to meet the requirements for the cell rect
            comp.setBounds(table.getCellRect(row, column, false));
            if (comp instanceof JEditorPane) {
                // Get the JEditorPane
                JEditorPane editPane = (JEditorPane) comp;
                // Asdjust the click point to be within the
                // editor context
                clickPoint.x -= comp.getLocation().x;
                clickPoint.y -= comp.getLocation().y;
                try {
                    // Try and get the hyperlink that was clicked
                    url = getHyperlink(editPane, clickPoint);
                } catch (MalformedURLException ex) {
                    ex.printStackTrace();
                }
            }

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    // Dispose of the editor...
                    // You could use cancelCellEditing() instead and the table won't
                    // try and update the model...
                    stopCellEditing();
                    // Open the URL if possible
                    if (url != null) {
                        try {
                            Desktop.getDesktop().browse(url.toURI());
                        } catch (IOException | URISyntaxException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            });
            return editor;
        }

        @Override
        public boolean isCellEditable(EventObject e) {
            boolean editable = false;
            if (e instanceof MouseEvent) {
                MouseEvent me = (MouseEvent) e;
                if (me.getClickCount() == 1 && SwingUtilities.isLeftMouseButton(me)) {
                    editable = true;
                    // We need to the point that the mouse event occured...
                    clickPoint = me.getPoint();
                }
            }
            return editable;
        }

        /*
         * Try and extract the URL from the hyperlink at the given point
         */
        protected URL getHyperlink(JEditorPane editor, Point p) throws MalformedURLException {
            int pos = editor.viewToModel(p);
            return getHyperlink(editor.getDocument(), pos);
        }

        /*
         * Get the hyperlink from the supplied document at the given position in the document
         */
        protected URL getHyperlink(Document doc, int pos) throws MalformedURLException {
            URL url = null;
            Element h = getHyperlinkElement(doc, pos);
            if (h != null) {
                Object attribute = h.getAttributes().getAttribute(HTML.Tag.A);
                if (attribute instanceof AttributeSet) {
                    AttributeSet set = (AttributeSet) attribute;
                    String href = (String) set.getAttribute(HTML.Attribute.HREF);
                    if (href != null) {
                        url = new URL(href);
                    }
                }
            }
            return url;
        }

        /*
         * Get the element from the document that represents a hyperlink based on the position
         * within teh document.  null if it's not a hyperlink element...
         */
        protected Element getHyperlinkElement(Document doc, int pos) {
            if (pos >= 0 && doc instanceof HTMLDocument) {
                HTMLDocument hdoc = (HTMLDocument) doc;
                Element elem = hdoc.getCharacterElement(pos);
                if (elem.getAttributes().getAttribute(HTML.Tag.A) != null) {
                    return elem;
                }
            }
            return null;
        }
    }
}