java - 如何在 Swing 中制作适当的表格,并使用适当的布局将所有元素放在各自的位置?
问题描述
我正在开发一个网络爬虫并分几个阶段实施它。
此阶段获取网站上提到的所有链接,并在 JTable 中显示带有标题的网页的有效链接。
但是,我希望表格在我输入要解析的 TextField 中的 URL 之前已经存在(这是此分配的要求)。
另外,有没有办法修复当前布局(Macintosh 窗口的第一张图片) Current Swing Window ,以便我可以在指定位置正确显示所有 JFrame 元素,如下图所示:
我曾尝试使用空布局来解决布局问题,它只会让任务成为一场噩梦,而且桌子会在我眼前消失。
在我开始输入链接之前,我找不到让表格存在的方法。
package crawler;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import java.awt.*;
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;
public class WebCrawler extends JFrame {
public WebCrawler() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Web Crawler");
setLocationRelativeTo(null);
setSize(600, 400);
JTextField urlText = new JTextField();
urlText.setName("UrlTextField");
// urlText.setBounds(10,10,300,20);
urlText.setSize(300,20);
JLabel title = new JLabel();
JLabel titleLabel = new JLabel();
title.setFont(new Font("Helvetica Nueve", Font.BOLD, 12));
title.setLocation(10,30);
title.setName("TitleLabel");
titleLabel.setFont(new Font("Helvetica Nueve", Font.BOLD, 12));
titleLabel.setText("Title:\t");
JButton extract = new JButton();
extract.setText("Parse");
extract.setName("RunButton");
extract.setSize(40,20);
var LINE_SEPARATOR = System.getProperty("line.separator");
extract.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
String url = 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";
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("Exception encountered at " + link );
}
}
}
JTable table = new JTable(toTableModel(links));
table.setName("TitlesTable");
JScrollPane scrollPane = new JScrollPane(table);
table.disable();
add(scrollPane, BorderLayout.CENTER);
table.clearSelection();
}
catch (Exception ex){
System.out.println(ex.getMessage());
}
}
catch(Exception ex){ System.out.println(ex.getMessage());}
}
});
add(urlText, BorderLayout.PAGE_START);
add(extract, BorderLayout.PAGE_END);
add(titleLabel, BorderLayout.WEST);
add(title, BorderLayout.LINE_START);
//TODO: change design and layout
setVisible(true);
}
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;
}
}
当我运行作业的测试工具给出的测试时,它显示“找不到合适的表格元素”。
发生这种情况是因为它甚至在将测试用例 URL 输入文本字段进行解析之前就需要检测活动表。
解决方案
我希望表格在我输入 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 vertical
BoxLayout` 中。
然后每一行都是另一个子面板。第一行可以是一个水平面板,BoxLayout
第二行是一个面板FlowLayout
。
阅读Layout Manager上的 Swing 教程,然后使用适当的布局管理器对子面板上的组件进行逻辑分组。
推荐阅读
- php - Google Sheets API 安装问题 - quickstart.php 没有做任何事情
- javascript - 将数据转换为 HTML 对象的最佳方法
- jquery - 如何确定哪类元素里面有一个数字
- javascript - 如何在 aws lambda 中调用 javascript 类处理函数
- react-native - 如何在 React Native 中使用免提蓝牙?
- excel - 如何修复“运行时错误 '424 Object required 错误
- c# - 使用 C# 修改运行时 > 探测属性 web.config
- java - Node如何处理线程池中只有少数线程的密集文件操作?
- android - 清洁架构用例/领域层的相关性
- json - Symfony JSON 官方认证器示例