經過自定義單元格渲染器在Jtable中顯示超連接

轉載:http://www.tuicool.com/articles/qE7FNvhtml

 

在JTable中自定義單元格渲染器是很是簡單和容易的。對於單元格渲染器來講,它的主要任務就是爲目標單元格返回一個Component對象,以呈現其內容。說到Component,就應該豁然開朗了,由於在Swing中,全部可在屏幕上顯示的圖形控件都是Component的直接或間接子類,也就是說,理論上你能夠在JTable單元格中顯示任意圖形控件!java

固然,實際上有一些控件是不能在單元格中顯示的,好比JFrame這樣的獨立窗口控件,爲了不循環引用也不容許將當前表格做爲渲染器,但即使是這樣,咱們的可用選擇仍然多的數不清。咱們只須要繼承任意可用的Component子類,同時實現TableCellRenderer接口,就能夠製做一個本身的單元格渲染器。做爲Swing自帶的默認單元格渲染器,DefaultTableCellRenderer的使用頻率很是高,該類繼承自JLabel,是最簡單的單元格渲染器實現。參考這一實現,咱們能夠嘗試分別繼承自JComboBox、JButton、JCheckBox、JProgressBar等,實如今表格單元格中顯示下拉框、按鈕、複選框和進度條等稍微高級的UI控件。瀏覽器

值得注意的是,單元格的UI控件沒有攔截事件的能力,也就是說,他們僅僅作數據呈現工做,不可以與用戶交互(由於事件被JTable在上層攔截並處理),這也意味着某些以下拉框、複選框等可交互的UI控件「只能看不能用」。不過咱們能夠經過監聽JTable的鼠標事件並經過接口轉換到對應的單元格和藉助單元格編輯器的方式分別解決上述兩個問題。編輯器

以下代碼,演示瞭如何經過自定義單元格渲染器實如今表格中顯示超連接並在連接被點擊時自動打開對應頁面的功能:ide

package cn.ysh.studio.jtable;

import java.awt.*; import java.awt.event.MouseEvent; import java.net.URL; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.event.MouseInputListener; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableModel; /** * 顯示超連接的JTable單元格渲染器 * @author 楊勝寒 * @date 2013-06-20 16:08:36 */ public class LinkCellRenderer extends DefaultTableCellRenderer implements MouseInputListener { //鼠標事件所在的行 private int row = -1; //鼠標事件所在的列 private int col = -1; //當前監聽的Table private JTable table = null; @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { //恢復默認狀態 this.table = table; super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); this.setForeground(Color.black); table.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); this.setText(value.toString()); //若是當前須要渲染器的單元格就是鼠標事件所在的單元格 if (row == this.row && column == this.col) { //若是是第二列(第二列是顯示超連接的列) if (column == 1) { //改變前景色(文字顏色) this.setForeground(Color.blue); //改變鼠標形狀 table.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); //顯示超連接樣式 this.setText("<html><u>" + value.toString() + "</u></html>"); } setBackground(table.getSelectionBackground()); } else if (isSelected) { //若是單元格被選中,則改變前景色和背景色 setForeground(table.getSelectionForeground()); setBackground(table.getSelectionBackground()); } else { //其餘狀況下恢復默認背景色 setBackground(Color.white); } return this; } /** * 鼠標移出事件 * @param e */ public void mouseExited(MouseEvent e) { if (table != null) { int oldRow = row; int oldCol = col; //鼠標移出目標表格後,恢復行列數據到默認值 row = -1; col = -1; //當以前的行列數據有效時重畫相關區域 if (oldRow != -1 && oldCol != -1) { Rectangle rect = table.getCellRect(oldRow, oldCol, false); table.repaint(rect); } } } /** * 鼠標拖動事件 * @param e */ public void mouseDragged(MouseEvent e) { mouseMoved(e); } /** * 鼠標移動事件 * @param e */ public void mouseMoved(MouseEvent e) { if (table != null) { Point p = e.getPoint(); int oldRow = row; int oldCol = col; row = table.rowAtPoint(p); col = table.columnAtPoint(p); //重畫原來的區域 if (oldRow != -1 && oldCol != -1) { Rectangle rect = table.getCellRect(oldRow, oldCol, false); table.repaint(rect); } //重畫新的區域 if (row != -1 && col != -1) { Rectangle rect = table.getCellRect(row, col, false); table.repaint(rect); } } } /** * 鼠標單擊事件 * @param e */ public void mouseClicked(MouseEvent e) { //獲取事件所在的行列座標信息 Point p = e.getPoint(); int c = table.columnAtPoint(p); if(c != 1){ return; } int r = table.rowAtPoint(p); try { //取得目標單元格的值,即連接信息 URL url = new URL(table.getValueAt(r, c).toString()); //在系統默認瀏覽器中打開連接 Desktop.getDesktop().browse(url.toURI()); } catch (Exception ex) { Logger.getLogger(LinkCellRenderer.class.getName()).log(Level.SEVERE, null, ex); } } /** * 鼠標按下事件 * @param e */ public void mousePressed(MouseEvent e) { } /** * 鼠標釋放事件 * @param e */ public void mouseReleased(MouseEvent e) { } /** * 鼠標進入事件 * @param e */ public void mouseEntered(MouseEvent e) { } /** * 測試方法 * @param args */ public static void main(String[] args) { //將在表格中呈現的數據 Object[] header = new String[]{"標題", "連接"}; Object[][] data = new String[10][2]; for (int i = 0; i < 10; i++) { data[i][0] = "網頁標題"; data[i][1] = "http://www.yshjava.cn/post/529.html"; } //構建表格數據模型 TableModel model = new DefaultTableModel(data, header); //建立表格對象 JTable table = new JTable(model); //建立單元格渲染器暨鼠標事件監聽器 LinkCellRenderer renderer = new LinkCellRenderer(); //注入渲染器 table.setDefaultRenderer(Object.class, renderer); //注入監聽器 table.addMouseListener(renderer); table.addMouseMotionListener(renderer); //爲表格增長愛滾動窗格 JScrollPane sp = new JScrollPane(table); //建立窗口程序 JFrame f = new JFrame("JTable 單元格超連接測試"); f.getContentPane().add(sp, BorderLayout.CENTER); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setSize(800, 600); f.setLocationRelativeTo(null); //顯示窗口 f.setVisible(true); } }

效果圖以下所示:post

 

在上面的例子中,僅僅演示瞭如何經過監聽JTable的鼠標事件來影響對應單元格的行爲和外觀,可是並未涉及到如何解決交互型UI在JTable單元格中不可用的問題。解決這個問題,須要藉助TableCellEditor單元格編輯器的配合來實現,簡單來講,展示靠渲染器,交互操做靠編輯器。測試

TableCellEditor跟TableCellRenderer的原理幾乎是同樣的,都是接口,Swing都提供了簡單的默認實現,都負責生成UI控件來展示或供編輯單元格的數據,不一樣的是TableCellEditor有接收交互事件的能力,而TableCellRenderer沒有,所以能夠簡單認爲「編輯器是動態的,負責編輯,而渲染器是靜態的,負責展示」。單元格編輯器不是本文的主題,不作過多說明。放一張NetBeans可視化UI設計器的一個窗口截圖,圖中的表格就是經過自定義渲染器和編輯器實現的。ui

相關文章
相關標籤/搜索