我的问题如下:
我正在尝试向使用 HTMLEditorKit 和 HTMLDocument 类在 Java Swing 中实现的 HTML 编辑器添加功能。这个想法是提供在 HTML 编辑器中编辑文本期间在不同样式之间切换的可能性。不同的样式定义了背景/前景颜色、字体等。
我已经设法以编程方式加载样式表文件。代码如下所示:
class HtmlEditor extends JFrame implements Keylistener, MouseListener {
private HTMLDocument m_doc;
private HTMLEditorKit m_kit;
[...]
public HtmlEditor(...) {
[...]
final URL formats = HtmlEditor.class.getResource("/formats.css");
predefStyles = new StyleSheet();
predefStyles.importStyleSheet(formats);
m_kit.getStyleSheet().addStyleSheet(predefStyles);
[...]
}
样式表文件如下所示:
.style1 { background-color:silver }
.style2 { background-color:aqua }
.style3 { background-color:teal }
将该样式表添加到 HTMLEditorKit 实例的 StyleSheet 后,我已经可以在使用其源编辑器将内容插入 HTML 编辑器时使用这些样式(在源编辑器中,可以直接插入 HTML 代码,例如“<span class="style1">Styled文本</span>”)。为了允许在 WYSIWYG 部分中使用样式,我在编辑器的工具栏中添加了一个 JComboBox,它显示“formats.css”中的样式名称(样式名称中的前导“.”被删除)。在 JComboBox 的 ActionListener 中,我现在尝试设置“类”属性。我的代码如下所示:
cbStyles = new JComboBox<String>(getStyleNames());
cbStyles.setToolTipText("Select Style");
cbStyles.setMaximumSize(null);
cbStyles.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
currStyle = cbStyles.getSelectedItem().toString();
final SimpleAttributeSet attr = new SimpleAttributeSet();
attr.addAttribute(HTML.Attribute.CLASS, currStyle);
m_kit.getInputAttributes().addAttributes(attr);
m_editor.requestFocusInWindow();
}
});
m_toolBar.add(cbStyles);
不幸的是,这似乎不起作用。至少,在更改样式后,我没有将其应用于我之后输入的文本,并且在源视图中,“类”属性不会出现在包含的 HTML 组件中。我检查了管理设置另一种字体的 HtmlEditor 类中的代码,看看我是否也可以使用与更改字体相同的技术来达到我的目的。附加到提供字体选择的 JComboBox 的相应动作侦听器如下所示:
cbFonts.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
m_fontName = m_cbFonts.getSelectedItem().toString();
final MutableAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setFontFamily(attr, m_fontName);
m_kit.getInputAttributes().addAttributes(attr);
m_editor.requestFocusInWindow();
}
});
正如我们在这里看到的,StyleConstants 类用于将属性设置为新字体。令我困惑的是 StyleConstants 类似乎没有提供设置“类”属性的方法。从它的 Javadoc 中可以看出,有很多方法可以设置对齐、字体系列、粗体等属性。可能我的方法很简单是不正确的。也许我还没有正确理解在 HTMLDocument 中使用 CSS 的概念。任何帮助,将不胜感激!
根据我对 HTML CSS 的理解,可以按如下方式使用:
<head> 部分内的 <style> 元素定义样式类。例子:
<style type="text/css">;
.style1 { background-color:silver }
.style2 { background-color:aqua }
.style3 { background-color:teal }
</style>
然后在 HTML 内部,这些类可以通过 HTML 元素内部的通用属性“class”来引用。例子:
<span class="style1">style1 中的文本</span>
因此,应该可以以某种方式将具有预定义样式的“类”属性作为其值插入到由 HTMLEditorKit 管理的 HTMLDocument 中的元素中。我的小 HTML 编辑器提供了在文档内当前插入符号位置激活样式的功能。所以让我们假设插入符号的位置在这样的段落内:
<p>一些没有样式的文字</p>
在结束段落标记之前的“样式”一词之后。
现在我想激活,比如说,style1。这应该会产生如下结构:
<p>一些没有样式的文本<span class="style1"> </span></p>
现在插入符号的位置应该在新的 <span> 元素内。
或者如果插入符号位于空段落的开头:
<p></p>
应用样式后,结构应如下所示:
<p class="style1"> </p>
我认为这应该没什么大不了的,但不知道如何完成这项工作。
在这之间,我尝试了另一种方法来解决我的问题,但没有成功。这是完整的示例代码(希望不要太多;-):
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.StringWriter;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.border.EmptyBorder;
import javax.swing.text.BadLocationException;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
public class HTMLEditor extends JFrame {
private static final long serialVersionUID = 1L;
private final JEditorPane jep;
private final HTMLEditorKit edtKit;
private final HTMLDocument doc;
public static void main(String[] args) {
final HTMLEditor editor = new HTMLEditor();
editor.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
editor.setVisible(true);
}
public HTMLEditor() {
super("Simple HTML Editor");
jep = new JEditorPane();
edtKit = new HTMLEditorKit();
jep.setEditorKit(edtKit);
addMyStyles();
doc = (HTMLDocument) edtKit.createDefaultDocument();
jep.setDocument(doc);
jep.setText("<html><head></head>" +
"<body><div class=\"style1\">STYLE1</div>" +
"</body>");
final Container content = getContentPane();
content.add(jep, BorderLayout.CENTER);
content.add(createToolBar(), BorderLayout.NORTH);
setJMenuBar(createMenuBar());
setSize(320, 240);
}
/**
* Adds three simple style definitions to the HTMLEditorKit's style sheet.
*/
void addMyStyles() {
final StyleSheet styles = edtKit.getStyleSheet();
styles.addRule(".style1 { background-color:silver; }");
styles.addRule(".style2 { background-color:aqua; }");
styles.addRule(".style3 { background-color:teal; }");
}
/**
* Creates the toolbar with two buttons:
* <li>Button to switch between bold and normal text
* <li>Button for activating a style class
* @return The toolbar
*/
protected JToolBar createToolBar() {
final JToolBar bar = new JToolBar();
final Action boldAct = jep.getActionMap().get("font-bold");
boldAct.putValue(Action.NAME, "Bold");
bar.add(boldAct);
bar.addSeparator();
final Action styleAct = new StyleAction();
jep.getActionMap().put("activate-style", styleAct);
bar.add(styleAct);
return bar;
}
/**
* Creates the menu bar. It only offers and action to display the HTML source
* in a popup window.
* @return The menu bar
*/
protected JMenuBar createMenuBar() {
final JMenuBar menubar = new JMenuBar();
final JMenu view = new JMenu("View");
menubar.add(view);
final JMenuItem preview = new JMenuItem("Preview");
view.add(preview);
preview.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
final HTMLPreview previewer =
new HTMLPreview(HTMLEditor.this, getDocSource());
previewer.setVisible(true);
}
});
return menubar;
}
/**
* Helper method to extract the HTML source code from the HTML document
* @return The HTML source code
*/
private String getDocSource() {
final StringWriter sw = new StringWriter();
try {
edtKit.write(sw, doc, 0, doc.getLength());
} catch (IOException | BadLocationException e1) {
e1.printStackTrace();
}
try {
sw.close();
} catch (final IOException e1) {
e1.printStackTrace();
}
return sw.toString();
}
/**
* Implements the action for insertion of a user supplied style (should be
* "style1", "style2" or "style3").
*
*/
public class StyleAction extends StyledEditorKit.StyledTextAction {
private static final long serialVersionUID = 1L;
public StyleAction() {
super("Activate a Style");
}
@Override
public void actionPerformed(ActionEvent ae) {
final JEditorPane editor = getEditor(ae);
if (editor == null)
return;
final String value = JOptionPane.showInputDialog(HTMLEditor.this,
"Style Name:");
try {
final String text = "<span class=\"" + value + "\"></span>";
edtKit.insertHTML(doc, editor.getCaretPosition(),
text, 0, 0, HTML.Tag.SPAN);
} catch (final Exception e) {
e.printStackTrace();
}
}
}
}
/**
* Popup window for display of the current contents of the editor as HTML
* source code.
*/
class HTMLPreview extends JDialog {
private static final long serialVersionUID = 1L;
public HTMLPreview(JFrame parent, String source) {
super(parent, "HTML Source", true);
final JPanel pp = new JPanel(new BorderLayout());
pp.setBorder(new EmptyBorder(10, 10, 5, 10));
final JTextArea srcTxtArea = new JTextArea(source, 20, 60);
srcTxtArea.setFont(new Font("Courier", Font.PLAIN, 12));
final JScrollPane sp = new JScrollPane(srcTxtArea);
pp.add(sp, BorderLayout.CENTER);
final JPanel p = new JPanel(new FlowLayout());
final JPanel p1 = new JPanel(new GridLayout(1, 2, 10, 0));
final JButton closeBtn = new JButton("Close");
closeBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
p1.add(closeBtn);
p.add(p1);
pp.add(p, BorderLayout.SOUTH);
getContentPane().add(pp, BorderLayout.CENTER);
pack();
setResizable(true);
setLocationRelativeTo(parent);
}
}
从ctor中可以看出。类 HTMLEditor 我首先添加了三个用户定义的样式 (style[1-3]),然后通过插入使用 style1 进行格式化的文本来检查它们是否工作。我希望在用户定义的文本格式样式之间切换应该以类似于在粗体和普通字体显示之间切换文本的方式完成。所以我的问题是:如何将用户定义的 CSS 样式应用于 HTMLDocument 中的元素?非常感谢任何提示。