2 回答
TA贡献1829条经验 获得超4个赞
不要在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;
}
}
TA贡献1843条经验 获得超7个赞
我希望在输入 URL 之前表格已经存在
然后,您需要在创建所有其他组件并将其添加到框架的同时创建一个空表并将其添加到框架。
您需要为 JTable 创建一个实例变量才能修改其模型。
将表格添加到框架的代码类似于:
add(title, BorderLayout.LINE_START);
DefaultTableModel model = new DefaultTableModel (new Object[] { "URL", "Title" }, 0);
table = new JTable( model );
add(new JScrollPane(table), BorderLayout.CENTER);
所以现在当您启动应用程序时,您将看到一个只有列的空表。
您的方法中的代码toTableModel(...)现在变成如下所示:
//DefaultTableModel model = new DefaultTableModel (new Object[] { "URL", "Title" }, 0);
DefaultTableModel model = (DefaultTableModel)table.getModel();
model.setRowCount(0);
这只是删除模型中的所有行,因此您的循环代码可以添加每一行新数据。
当然,您还可以删除当前创建 JTable 和 JScrollPane 的 ActionListener 中的代码,因为不再需要它。
另外,有没有办法修复当前布局
您的嵌套面板具有不同的布局管理器,以达到您想要的效果。
例如,您希望表格能够根据表格中的数据增长/缩小,因此应该将其添加到CENTER您的BorderLayout.
但是,顶部到两行是固定的,它们应该添加到子面板中。然后这个面板将被添加到PAGE_START你的BorderLayout. Maybe a verticalBoxLayout` 中。
然后每一行都是另一个子面板。第一行可以是带有水平的面板BoxLayout,第二行可以是带有FlowLayout.
添加回答
举报