DefaultTableCellRenderer

本文深入探讨了Java Swing中JTable的编辑和表现机制,包括如何通过TableCellEditor和TableCellRenderer接口灵活定制表格的编辑与显示行为,以及如何控制编辑状态的转换。

 

JTable 的编辑和表现

2006-06-04 19:53:08 来自: 卡卡西

在文档中对JTable 解释是:用来显示和编辑规则的二维单元表。
  也就是说JTable的类型定义决定了它是一个规则的二维单元表,但是对于二维单元表内单元格的显示和编辑组件的选择又是极其灵活的.
  有如下两个接口:
  TableCellEditor
  Component   getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column);
  
  TableCellRenderer
  Component   getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
  
  所有实现这两个接口的对象都可以配置到JTable.JTable自身定义了单元格的状态:表现或编辑.
  
  当JTabel处于表现状态时它会调用
  ableCellRenderer的Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)请求表现组件.
  
  当JTabel处于编辑状态时它会调用TableCellEditor的Component   getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column);请求编辑组件.
  
  这样我们实现TableCellEditor,TableCellRenderer这两个接口就可以灵活的控制表格单元格的编辑和显示.
  当然为了方便swing已经定义了这两个接口的默认实现,如DefaultCellEditor,DefaultTableCellRenderer.

@import url("/css/pop_login4.css");
  • 2006-06-07 11:23:42 卡卡西

    虽然我们有了灵活控制编辑和表现的接口,但是如何控制编辑和表现状态的转换呢!
    首先单元格可不可以编辑由表格的模型控制。因为通常可不可以编辑取决于数据内容,所以将它定义在模型中是合理的!

    TableModel 接口有如下一个方法:
    boolean isCellEditable(int rowIndex, int columnIndex) ;
    JTabel会通过他来确定可不可以编辑。

    在可编辑的情况下,通过JTabel的 boolean editCellAt(int row, int column) ,可以启动单元格进入编辑状态。那么如何控制从编辑状态退出呢?
    这个稍微复杂一点,因为从编辑状态退出还很可能意味着要将编辑器的内容放入表格模型。
    这里有一个接口
    public interface CellEditor{
    void addCellEditorListener(CellEditorListener l)

    Object getCellEditorValue()

    void removeCellEditorListener(CellEditorListener l)

    void cancelCellEditing()

    boolean stopCellEditing()
    .................
    }

    TableCellEditor继承自它,也就是说swing对单元格编辑器作了更抽象的定义。因为不仅仅是表格需要编辑。这里有个监听器的注册方法,看一下CellEditorListener的定义
    public interface CellEditorListener extends EventListener
    {
    void editingCanceled(ChangeEvent e)

    void editingStopped(ChangeEvent e)
    }

    很显然编辑状态结束的关键在CellEditor上。你可以主动发出事件通知CellEditorListener说结束了。也可以由外部调用
    void cancelCellEditing()
    boolean stopCellEditing()
    触发。而CellEditorListener得到通知后通常可以调用
    Object getCellEditorValue()来获得编辑器的值。例如JTable 就实现了CellEditorListener,当你将你的TableCellEditor设置到JTable时,JTable就会注册上去。

  • 2006-06-08 12:11:47 卡卡西

    有了灵活控制编辑和表现的接口,也有了控制编辑和表现状态的转换机制.不过完全从这些接口开始构建一套自己的实现,也是很累的。显然swing已经有一套比较通用的实现。
    首先看一下对于控制编辑和表现状态的转换,JTable有自己的一套定义,在外部事件触发下单元格编辑和表现状态的转换,比如在单元格上双击会使 得该单元格进入编辑状态,当编辑状态的单元格失去焦点时,该单元格离开编辑状态进入表现状态。在同一时刻只有一个单元格可以进入编辑状态等。

    再来看一下DefaultTableCellRenderer和DefaultCellEditor

    DefaultTableCellRenderer继承JLabel实现TableCellRenderer 接口。也就是说表格通常的单元格表现都是JLabel组件。
    这个实现其实有一个巧妙之处,在实现 
    Component   getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    。。。。。。。。。。。
    return this;
    }这个方法中
    最后一句return this;表明不管单元格有多少,JLabel对象一直只有一个,只是针对不同的单元格JLabel对象的状态不一样,但实例只有一个,俭省很多资源。

    DefaultCellEditor继承AbstractCellEditor,而AbstractCellEditor 实现了TableCellEditor。这里顺便讲一下,swing对很多接口的实现都有这两个层次,对于default的都是一个可用的实现,而 Abstract多是抽象类,他只实现了接口的一部分,而这一部分通常都是很通用的。如果觉得default不能满足要求,而觉得实现整个接口又麻 烦,Abstract的就很有用。
    DefaultCellEditor有三个构造函数:
    DefaultCellEditor(JCheckBox checkBox)

    DefaultCellEditor(JComboBox comboBox)

    DefaultCellEditor(JTextField textField)
    因为编辑不像表现那么单纯,通常使用编辑器的对象(如JTable)都要获得编辑器的值,然而不同编辑器的对外接口又是非常繁多的,所以CellEditor有这样一个方法
    Object getCellEditorValue() ;也就是说使用编辑器的对象(如JTable)不管实际编辑器有多繁杂,它就只通过Object getCellEditorValue()这个方法获取值。那么当你要把你的编辑器用到比如JTable上,那么就要考虑如何将你的编辑器接口适配到 JTable期望的Object getCellEditorValue() 上。
    DefaultCellEditor的构造函数就是一个提供了可以将三种编辑器进行适配。其实这是一种适配器模式。也就是DefaultCellEditor可以适配三种编辑器。

  • 2006-06-09 11:41:12 卡卡西

    忽略了一个很重要的问题,就是如何将我们的编辑器或表现器注册到JTable上?
    这个看是很简单的问题,其实也并非想象当中那么简单。
    先看一下JTable提供的明显的注册接口
    void setCellEditor(TableCellEditor anEditor) ;

    void setDefaultEditor(Class<?> columnClass, TableCellEditor editor)

    void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer)

    第一个接口很显然整个表格单元格的编辑器将由这个注册的编辑器接管。
    后面两个是基于数据类型进行配置的,也就是说这种数据类型的单元格编辑器将由注册的编辑器接管。
    那么如何决定数据类型呢?看表格模型TableModel里有一个方法
    Class<?> getColumnClass(int columnIndex);
    很明显和是否可编辑一样,数据类型由模型决定。
    除此之外还有另外的注册方法,那就是表格本身也是有其他元素组成,在JTable中下一级元素是列,TableColumn。它有这两个方法
    void setCellEditor(TableCellEditor cellEditor)

    void setCellRenderer(TableCellRenderer cellRenderer)
    可以将编辑器和表现器直接注册在列上,那么这一列的编辑或表现将由你注册的东西接管。

  • 2006-06-09 14:07:34 卡卡西

    JTable 的编辑和表现机制大致是这样,请各位高手指教!

  • 2006-06-14 13:59:59 _Juhn (山上的格桑花开的好美丽)

    不错,继续!

  • 2009-07-20 14:23:56 longkas

    标记一下,慢慢学习

  • 2009-07-22 00:24:06 骑着自行车去浪漫

    lZ说的这么详细实在佩服 不过貌似有些方法在实际项目中很少用的到...


@import url("/css/pop_login4.css");

这个小组的成员也喜欢去   · · · · · · 

Java编程
Java编程 (3051)
eclipse
eclipse (1098)
NetBeans
NetBeans (219)
^_^的程序员
^_^的程序员 (226)
Thinking In Java
Thinking In Java (312)
JBoss
JBoss (43)

package bzsh_dhqk; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.net.InetAddress; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellRenderer; @SuppressWarnings("serial") public class IndexGUI extends JFrame { private static int originalValue = 100; Object[] columnNames = {"单据编号"," 到货批号","供应商","料号", "料品名称", "料品规格", "实到数量(计价单位)","供方批号","收货程序","质检单结果","状态"}; String sql="SELECT * FROM [Xiling888].[dbo].dyfgs_bzsh1"; boolean ip; Object[][] data; DefaultTableModel df; JTable table; Thread thread; public IndexGUI() { super("标准收获-到货情况"); this.setVisible(true); this.setBounds(0, 0, 780, 500); this.setLocationRelativeTo(null);//让窗口在屏幕中间显示 this.setResizable(true);//让窗口大小可改变 this.setLayout(new BorderLayout()); ip=ping1("192.168.7.250",1000); if(ip) { data = Select.getGoods(sql); df = new DefaultTableModel(data, columnNames); table = new ZTable(df); } table.getTableHeader().setForeground (Color.white); table.getTableHeader().setBackground(new Color(16,50,80)); // 设置单元格选择方式 table.setSelectionBackground(new Color(47,117,181)); table.setSelectionForeground(Color.WHITE); table.setRowHeight(40); table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); TableCellRenderer tcr = new ColorTableCellRenderer(); table.setDefaultRenderer(Object.class,tcr);//为JTable增加渲染器,因为是针对于表格中的所有单元格,所有用Object.class table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); table.getTableHeader ().setFont (new Font ("微软雅黑", 0, 20)); table.setFont (new Font ("微软雅黑", Font.BOLD, 20)); table.getTableHeader().setReorderingAllowed(false);//列不能移动 table.getTableHeader().setResizingAllowed(true);//不可拉动表格 table.setModel(df); JScrollPane jp = new JScrollPane(table,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); this.add(jp, BorderLayout.CENTER); jp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); jp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); jp.setViewportView(table); final JScrollBar vBar = jp.getVerticalScrollBar(); vBar.addAdjustmentListener(new AdjustmentListener() { public void adjustmentValueChanged(AdjustmentEvent e) { vBar.setValue(getOriginalValue()); if(getOriginalValue()!=e.getValue()) { setOriginalValue(e.getValue()); } } }); JButton sx = new JButton("刷新"); sx.setBounds(440, 400, 100, 30); sx.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //thread.interrupt(); ip=ping1("192.168.7.250",1000); if(ip) { data = Select.getGoods(sql); df.setDataVector(data, columnNames); int No1=table.getColumnCount(); if(No1==11&&table!=null) { table.getTableHeader().getColumnModel().getColumn(0).setPreferredWidth(230); table.getTableHeader().getColumnModel().getColumn(1).setPreferredWidth(100); table.getTableHeader().getColumnModel().getColumn(2).setPreferredWidth(330); table.getTableHeader().getColumnModel().getColumn(3).setPreferredWidth(130); table.getTableHeader().getColumnModel().getColumn(4).setPreferredWidth(200); table.getTableHeader().getColumnModel().getColumn(5).setPreferredWidth(150); table.getTableHeader().getColumnModel().getColumn(6).setPreferredWidth(100); table.getTableHeader().getColumnModel().getColumn(7).setPreferredWidth(150); table.getTableHeader().getColumnModel().getColumn(8).setPreferredWidth(230); table.getTableHeader().getColumnModel().getColumn(9).setPreferredWidth(130); table.getTableHeader().getColumnModel().getColumn(10).setPreferredWidth(130); table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); } table.setModel(df); } } }); JPanel p=new JPanel(); this.add(p,BorderLayout.SOUTH); p.add(sx); this.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); }}); thread = new Thread(new Runnable() { @Override public void run() { while (true) { ip=ping1("192.168.7.250",1000); if(ip) { try {//每隔5秒钟更新JTable data = Select.getGoods(sql); df.setDataVector(data, columnNames); int No1=table.getColumnCount(); if(No1==11&&table!=null) { table.getTableHeader().getColumnModel().getColumn(0).setPreferredWidth(230); table.getTableHeader().getColumnModel().getColumn(1).setPreferredWidth(100); table.getTableHeader().getColumnModel().getColumn(2).setPreferredWidth(330); table.getTableHeader().getColumnModel().getColumn(3).setPreferredWidth(130); table.getTableHeader().getColumnModel().getColumn(4).setPreferredWidth(200); table.getTableHeader().getColumnModel().getColumn(5).setPreferredWidth(150); table.getTableHeader().getColumnModel().getColumn(6).setPreferredWidth(100); table.getTableHeader().getColumnModel().getColumn(7).setPreferredWidth(150); table.getTableHeader().getColumnModel().getColumn(8).setPreferredWidth(230); table.getTableHeader().getColumnModel().getColumn(9).setPreferredWidth(130); table.getTableHeader().getColumnModel().getColumn(10).setPreferredWidth(130); table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); } table.setModel(df); Thread.sleep(5000); System.out.println("5秒更新一次"); } catch (ArrayIndexOutOfBoundsException|InterruptedException e) { //e.printStackTrace(); } }else { try { Thread.sleep(5000); System.out.println("5秒连接一次"); } catch (ArrayIndexOutOfBoundsException|InterruptedException e) { //e.printStackTrace(); } } } } }); thread.start(); } /* public void run() { // TODO 自动生成的方法存根 while (true) { ip=ping1("192.168.7.250",1000); if(ip==true) { Object[] columnNames4 = {"单据编号"," 业务日期","供应商","料号", "料品名称", "料品规格", "实到数量(计价单位)","批号","收货程序", "状态"}; String sql4="SELECT * FROM [Xiling888].[dbo].dyfgs_bzsh1 "; Object[][] data4 = bzsh_dhqk.Select.getGoods(sql4); df.setDataVector(data4, columnNames4); try { Thread.sleep(5000); System.out.println("5秒更新一次"); } catch (ArrayIndexOutOfBoundsException |InterruptedException e) { e.printStackTrace(); } } else { try { Thread.sleep(5000); System.out.println("5秒重连一次"); } catch (ArrayIndexOutOfBoundsException |InterruptedException e) { // TODO 自动生成的 catch 块 System.out.println(e.getMessage()); } break; } } } */ class ZTable extends JTable{ private static final long serialVersionUID = 1L; public ZTable(DefaultTableModel df) { // TODO 自动生成的构造函数存根 } public boolean isCellEditable(int rowIndex, int columnIndex) //重写方法改编可编辑性 { return false; } public JTableHeader getTableHeader() { JTableHeader tableHeader=super.getTableHeader(); tableHeader.setReorderingAllowed(false); DefaultTableCellRenderer hr=(DefaultTableCellRenderer)tableHeader.getDefaultRenderer(); hr.setHorizontalAlignment(DefaultTableCellRenderer.CENTER); return tableHeader; } public TableCellRenderer getDefaultRenderer(Class<?>columnClass) { DefaultTableCellRenderer cr=(DefaultTableCellRenderer)super.getDefaultRenderer(columnClass); cr.setHorizontalAlignment(DefaultTableCellRenderer.CENTER); return cr; } } public static boolean ping1(String ip, int timeout) { try { return InetAddress.getByName(ip).isReachable(timeout); // 当返回值是true时,说明host是可用的,false则不可。 } catch (Exception ex) { return false; } } class ColorTableCellRenderer extends DefaultTableCellRenderer { /** * */ private static final long serialVersionUID = -8327550537377223504L; DefaultTableCellRenderer renderer=new DefaultTableCellRenderer(); public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean getflag, int row, int column) { int No1=table.getColumnCount(); if(No1==11&&table!=null) { table.getTableHeader().getColumnModel().getColumn(0).setPreferredWidth(230); table.getTableHeader().getColumnModel().getColumn(1).setPreferredWidth(100); table.getTableHeader().getColumnModel().getColumn(2).setPreferredWidth(330); table.getTableHeader().getColumnModel().getColumn(3).setPreferredWidth(130); table.getTableHeader().getColumnModel().getColumn(4).setPreferredWidth(200); table.getTableHeader().getColumnModel().getColumn(5).setPreferredWidth(150); table.getTableHeader().getColumnModel().getColumn(6).setPreferredWidth(100); table.getTableHeader().getColumnModel().getColumn(7).setPreferredWidth(150); table.getTableHeader().getColumnModel().getColumn(8).setPreferredWidth(230); table.getTableHeader().getColumnModel().getColumn(9).setPreferredWidth(130); table.getTableHeader().getColumnModel().getColumn(10).setPreferredWidth(130); } if(column <1){ //调用基类方法 setBackground(new Color(191,191,191)); setForeground(Color.BLACK); return super.getTableCellRendererComponent(table, value, isSelected,getflag, row, column); }else if(column ==8){ if (value != null && value.toString().contains("到货-质检中-质验完成") && table.getValueAt(row, 10).equals("到货")) { table.setValueAt("<html><font color='red'>到货</font>-质检中-质验完成</html>", row, 8); } else if (value != null && value.toString().contains("到货-质检中-质验完成") && table.getValueAt(row, 10).equals("质检中")) { table.setValueAt("<html></font>到货-<font color='blue'>质检中</font>-质验完成</html>", row, 8); } else if (value != null && value.toString().contains("到货-质检中-质验完成") && table.getValueAt(row, 10).equals("质验完成")) { table.setValueAt("<html></font>到货-质检中-<font color='green'>质验完成</html>", row, 8); } /* else { c.setForeground(Color.BLACK); } */ return super.getTableCellRendererComponent(table, value, isSelected,getflag, row, column); } else{ setBackground(new Color(217,217,217)); setForeground(Color.BLACK); return super.getTableCellRendererComponent(table, value, isSelected,getflag, row, column); } } } private static void setOriginalValue(int value) { originalValue = value; } private static int getOriginalValue() { return originalValue; } @SuppressWarnings("unused") private class ScrollListener implements AdjustmentListener { private int previousValue; @Override public void adjustmentValueChanged(AdjustmentEvent e) { if (e.getValueIsAdjusting()) { previousValue = e.getValue(); } } public int getPreviousValue() { return previousValue; } } } 如何为这个UI界面的滚动条添加相同功能
最新发布
09-05
import javax.swing.*; import javax.swing.table.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import java.util.concurrent.*; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; class FileResourceSearcher extends JFrame { private JTextField keywordField; private DefaultTableModel tableModel; private volatile boolean isSearching = false; public FileResourceSearcher() { setTitle("文件资源搜索器"); setSize(1000, 600); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLayout(new BorderLayout()); // 顶部输入面板 JPanel topPanel = new JPanel(new FlowLayout()); topPanel.add(new JLabel("关键字:")); keywordField = new JTextField(30); topPanel.add(keywordField); JButton fullSearchBtn = new JButton("全盘搜索"); JButton chooseDirBtn = new JButton("选择目录搜索"); JButton cancelBtn = new JButton("取消搜索"); topPanel.add(fullSearchBtn); topPanel.add(chooseDirBtn); topPanel.add(cancelBtn); // 表格模型和表格 String[] columns = {"文件名", "文件路径"}; tableModel = new DefaultTableModel(columns, 0); JTable resultTable = new JTable(tableModel) { @Override public boolean isCellEditable(int row, int column) { return false; } }; // 自定义渲染器:路径显示为蓝色可点击 resultTable.setDefaultRenderer(Object.class, new HyperlinkCellRenderer()); resultTable.addMouseListener(new HyperlinkMouseListener(resultTable)); JScrollPane scrollPane = new JScrollPane(resultTable); // 添加组件 add(topPanel, BorderLayout.NORTH); add(scrollPane, BorderLayout.CENTER); // 全盘搜索按钮 fullSearchBtn.addActionListener(e -> { isSearching = true; tableModel.setRowCount(0); new Thread(this::searchAllDrives).start(); }); // 自定义目录搜索按钮 chooseDirBtn.addActionListener(e -> { JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { String selectedDir = fc.getSelectedFile().getAbsolutePath(); isSearching = true; tableModel.setRowCount(0); new Thread(() -> searchDirectory(selectedDir)).start(); } }); // 取消搜索按钮 cancelBtn.addActionListener(e -> isSearching = false); } // 全盘搜索 private void searchAllDrives() { try { ProcessBuilder pb; String keyword = keywordField.getText().toLowerCase(); if (System.getProperty("os.name").toLowerCase().contains("win")) { pb = new ProcessBuilder("cmd.exe", "/c", "dir", "/s", "/b", "*" + keyword + "*"); } else { pb = new ProcessBuilder("sh", "-c", "find / -type f -name \"*" + keyword + "*\""); } Process process = pb.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; java.util.List<String> results = new CopyOnWriteArrayList<>(); while ((line = reader.readLine()) != null && isSearching) { results.add(line); } // 更新 UI SwingUtilities.invokeLater(() -> { for (String path : results) { File file = new File(path); tableModel.addRow(new Object[]{file.getName(), path}); } JOptionPane.showMessageDialog(this, "全盘搜索完成,共找到 " + results.size() + " 个文件。"); }); } catch (IOException ex) { ex.printStackTrace(); SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(this, "全盘搜索出错: " + ex.getMessage())); } } // 指定目录搜索 private void searchDirectory(String dir) { try { ProcessBuilder pb; String keyword = keywordField.getText().toLowerCase(); if (System.getProperty("os.name").toLowerCase().contains("win")) { pb = new ProcessBuilder("cmd.exe", "/c", "dir", "/s", "/b", "*" + keyword + "*"); } else { pb = new ProcessBuilder("sh", "-c", "find " + dir + " -type f -name \"*" + keyword + "*\""); } Process process = pb.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; List<String> results = new CopyOnWriteArrayList<>(); while ((line = reader.readLine()) != null && isSearching) { results.add(line); } // 更新 UI SwingUtilities.invokeLater(() -> { for (String path : results) { File file = new File(path); tableModel.addRow(new Object[]{file.getName(), path}); } JOptionPane.showMessageDialog(this, "目录搜索完成,共找到 " + results.size() + " 个文件。"); }); } catch (IOException ex) { ex.printStackTrace(); SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(this, "目录搜索出错: " + ex.getMessage())); } } // 自定义渲染器:显示为超链接样式 static class HyperlinkCellRenderer extends DefaultTableCellRenderer { private final JLabel label = new JLabel(); public HyperlinkCellRenderer() { label.setForeground(Color.BLUE); label.setCursor(new Cursor(Cursor.HAND_CURSOR)); label.setFont(label.getFont().deriveFont(Font.PLAIN)); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { label.setText(value != null ? value.toString() : ""); label.setToolTipText("点击打开路径"); return label; } } // 鼠标点击监听器:打开文件/文件夹 class HyperlinkMouseListener extends MouseAdapter { private final JTable table; public HyperlinkMouseListener(JTable table) { this.table = table; } @Override public void mouseClicked(MouseEvent e) { int row = table.rowAtPoint(e.getPoint()); int col = table.columnAtPoint(e.getPoint()); if (col == 1 && row != -1) { String path = (String) table.getValueAt(row, col); openFileOrFolder(path); } } } // 打开文件/文件夹 private void openFileOrFolder(String path) { if (path == null || path.isEmpty()) { JOptionPane.showMessageDialog(this, "路径为空,无法打开。"); return; } File file = new File(path); if (!file.exists()) { JOptionPane.showMessageDialog(this, "路径不存在: " + path, "错误", JOptionPane.ERROR_MESSAGE); return; } try { // 使用 Desktop API(适用于文件和文件夹) if (Desktop.isDesktopSupported()) { Desktop desktop = Desktop.getDesktop(); if (desktop.isSupported(Desktop.Action.OPEN)) { if (file.isDirectory()) { desktop.open(file); } else { desktop.open(file.getParentFile()); // 打开文件所在文件夹 } return; } } // Windows 下使用 explorer.exe 打开资源管理器并定位文件 if (System.getProperty("os.name").toLowerCase().contains("win")) { Runtime.getRuntime().exec("explorer.exe /select,\"" + file.getAbsolutePath().replace("/", "\\") + "\""); return; } // macOS 使用 open if (System.getProperty("os.name").toLowerCase().contains("mac")) { Runtime.getRuntime().exec(new String[]{"open", file.getParent()}); return; } // Linux 使用 xdg-open if (System.getProperty("os.name").toLowerCase().contains("nix") || System.getProperty("os.name").toLowerCase().contains("nux")) { Runtime.getRuntime().exec("xdg-open \"" + file.getParent() + "\""); } } catch (Exception ex) { JOptionPane.showMessageDialog(this, "无法打开路径,请手动查看。\n错误信息: " + ex.getMessage(), "打开失败", JOptionPane.WARNING_MESSAGE); } } public static void main(String[] args) { SwingUtilities.invokeLater(() -> { new FileResourceSearcher().setVisible(true); }); } } 这串代码为啥只在f盘搜索
08-16
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值