浮云间
不要在JButton的ActionPerformed事件中创建JScrollPane和JTable。但是,如果您愿意,可以从该事件重新启用 JTable,并将链接应用到 JTable 的模型。如果可以,请在单独的类中创建您的表单。这清理了很多东西,因为它使表单代码杂乱无章,远离手头的主要任务……页面抓取链接。表单类可能如下所示:package webcrawler;public class Form extends javax.swing.JFrame {private static final long serialVersionUID = 101101L;// Member Variables for Form Components public javax.swing.JTextField urlText;public javax.swing.JButton extract;public javax.swing.JLabel title;public javax.swing.JTable table;private javax.swing.JLabel jLabel1;private javax.swing.JPanel jPanel1;private javax.swing.JPanel jPanel2;private javax.swing.JScrollPane scrollPane;private javax.swing.JLabel titleLabel;public Form() { initializeFormComponents(); setLookAndFeel(); openForm();}private void setLookAndFeel() { /* Set the Nimbus look and feel if you have it or even like it. Use whatever you like */ try { for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { javax.swing.UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) { System.out.println(ex.getMessage()); }}private void openForm() { /* Create and display the form */ java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { setVisible(true); setLocationRelativeTo(null); } });}private void initializeFormComponents() { jPanel1 = new javax.swing.JPanel(); jLabel1 = new javax.swing.JLabel(); urlText = new javax.swing.JTextField(); extract = new javax.swing.JButton(); jPanel2 = new javax.swing.JPanel(); scrollPane = new javax.swing.JScrollPane(); table = new javax.swing.JTable(); titleLabel = new javax.swing.JLabel(); title = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("Web Crawler"); setAlwaysOnTop(true); jLabel1.setFont(new java.awt.Font("sansserif", 1, 12)); // NOI18N jLabel1.setText("URL:"); urlText.setName("UrlTextField"); // NOI18N extract.setText("Parse"); extract.setName("RunButton"); // NOI18N javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(urlText, javax.swing.GroupLayout.PREFERRED_SIZE, 667, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(extract, javax.swing.GroupLayout.DEFAULT_SIZE, 84, Short.MAX_VALUE) .addContainerGap()) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel1) .addComponent(urlText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(extract)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); table.setModel(new javax.swing.table.DefaultTableModel( new Object[][]{ {null, null}, {null, null}, {null, null}, {null, null} }, new String[]{ "URL", "TITLE" } ) { private static final long serialVersionUID = 101110L; Class[] types = new Class[]{ java.lang.String.class, java.lang.String.class }; boolean[] canEdit = new boolean[]{ false, false }; @Override public Class getColumnClass(int columnIndex) { return types[columnIndex]; } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return canEdit[columnIndex]; } }); table.setName("TitlesTable"); table.setEnabled(false); table.setGridColor(new java.awt.Color(198,195,195)); table.setInheritsPopupMenu(true); table.setRowHeight(20); table.setShowHorizontalLines(true); table.setShowVerticalLines(true); scrollPane.setViewportView(table); titleLabel.setFont(new java.awt.Font("sansserif", 1, 12)); titleLabel.setText("Title:"); title.setFont(new java.awt.Font("sansserif", 1, 12)); title.setText("None"); title.setName("TitleLabel"); javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); jPanel2.setLayout(jPanel2Layout); jPanel2Layout.setHorizontalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel2Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(scrollPane) .addGroup(jPanel2Layout.createSequentialGroup() .addComponent(titleLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(18, 18, 18) .addComponent(title, javax.swing.GroupLayout.PREFERRED_SIZE, 348, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); jPanel2Layout.setVerticalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(titleLabel) .addComponent(title)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(scrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 478, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) ); pack(); }}然后您的 WebCrawler 类可能如下所示:package webcrawler;import javax.swing.*;import javax.swing.table.DefaultTableModel;import javax.swing.table.TableModel;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.net.URL;import java.nio.charset.StandardCharsets;import java.util.Iterator;import java.util.Map;import java.util.SortedMap;import java.util.TreeMap;import java.util.regex.Matcher;import java.util.regex.Pattern;import javax.swing.table.JTableHeader;import javax.swing.table.TableCellRenderer;public class WebCrawler {private static final long serialVersionUID = 101011L;private Form form;String LINE_SEPARATOR = System.getProperty("line.separator");public static void main(String[] args) { // To eliminate the need for statics. I Don't want it right now. new WebCrawler().startApp(args);}private void startApp(String[] args) { form = new Form(); form.extract.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { clearJTable(); // Clear the JTable String url = form.urlText.getText(); /* Get url from JTextField */ url = url.replaceAll("^\"+ \"+$", ""); final InputStream inputStream = new URL(url).openStream(); final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); final StringBuilder stringBuilder = new StringBuilder(); String nextLine; while ((nextLine = reader.readLine()) != null) { stringBuilder.append(nextLine); stringBuilder.append(LINE_SEPARATOR); } final String siteText = stringBuilder.toString(); Pattern pattern = Pattern.compile("<title>(.+?)</title>", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(siteText); String titleString = matcher.find() ? matcher.group(1) : "null"; form.title.setText(titleString); SortedMap<String, String> links = new TreeMap<>(); Pattern pTag = Pattern.compile("(?i)<a([^>]+)>(.+?)</a>", Pattern.CASE_INSENSITIVE); Pattern pLink = Pattern.compile("\\s*(?i)href\\s*=\\s*(\"([^\"]*\")|'[^']*'|([^'\">\\s]+))", Pattern.CASE_INSENSITIVE); Matcher mTag = pTag.matcher(siteText); try { while (mTag.find()) { String href = mTag.group(1); // get the values of href String linkElem = mTag.group(2); // get the text of link Html Element Matcher mLink = pLink.matcher(href); while (mLink.find()) { String link = mLink.group(1); link = link.substring(1, link.length() - 1); pattern = Pattern.compile("http", Pattern.CASE_INSENSITIVE); matcher = pattern.matcher(link); if (!matcher.find()) { link = String.join("", url, link); } try { //URL urlValidator = new URL(link); //if (urlValidator.getContent().equals("text/html")) { links.put(link, linkElem); //} } catch (Exception ex) { System.out.println(ex); //System.out.println("Exception encountered at " + link); } } } form.table.setEnabled(true); // Enable JTable form.table.setModel(toTableModel(links)); } catch (Exception ex) { System.out.println(ex); } } catch (Exception ex) { System.out.println(ex); } // Is there anything in the table? if (form.table.getModel().getRowCount() == 0) { // NOPE...So Disable JTable. form.table.setEnabled(true); } } }); form.urlText.requestFocus();}private void clearJTable() { DefaultTableModel tableModel = (DefaultTableModel) form.table.getModel(); while (tableModel.getRowCount() > 0) { for (int i = 0; i < tableModel.getRowCount(); i++) { tableModel.removeRow(i); } } // Reset 4 blank rows in the table for looks :) form.table.setModel(new DefaultTableModel( new Object[][]{{null, null}, {null, null}, {null, null},{null, null}}, new String[]{"<html><font color=blue><b>U R L</b></font></html>", "<html><font color=red><b>T I T L E</b></font></html>"})); // Yes...you can use basic HTML in a JTable Header.}public TableModel toTableModel(Map<?, ?> map) { DefaultTableModel model = new DefaultTableModel( new Object[]{"URL", "TITLE"}, 0 ); for (Iterator it = map.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); model.addRow(new Object[]{entry.getKey(), entry.getValue()}); } return model;}}