我正在尝试在用Java生成的html文档中实现用户可选择的文本对齐。我试过了:
JMenuItem leftAlignMenuItem =
new JMenuItem(new StyledEditorKit.AlignmentAction("Left Align", StyleConstants.ALIGN_LEFT));
JMenuItem centerMenuItem =
new JMenuItem(new StyledEditorKit.AlignmentAction("Center", StyleConstants.ALIGN_CENTER));
JMenuItem rightAlignMenuItem =
new JMenuItem(new StyledEditorKit.AlignmentAction("Right Align", StyleConstants.ALIGN_RIGHT));
以及此主题的各种变化。选择菜单项会使文本在文本窗格中正确对齐,并将相应的html标记添加到保存的文档中。问题是,添加标签后,单击另一个对齐菜单项并不会更改它,因此无法多次更改默认(左)文本对齐并保存更改。
我知道我不是第一个遇到此问题的人,但到目前为止我还没有找到任何解决方案,所以任何帮助都会受到最高的赞赏。
这是我的" M" CVE,遗憾的是仍然很大,但我无法删除更多代码,或者它不会证明问题:
package aligntest;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.JFrame;
public class AlignTest extends JFrame implements ActionListener {
private HTMLDocument doc; // Stores the formatted text.
private JTextPane textPane = new JTextPane(); // The Pane itself.
String FilePath = ""; // Stores the file path.
public AlignTest() { // This method is called automatically when the app is launched.
HTMLEditorKit editorKit = new HTMLEditorKit();
doc = (HTMLDocument)editorKit.createDefaultDocument();
init(); // Calls interface method below.
}
public static void main(String[] args) {
AlignTest editor = new AlignTest();
}
public void init(){
JMenuBar menuBar = new JMenuBar();
getContentPane().add(menuBar, BorderLayout.NORTH);
JMenu fileMenu = new JMenu("File");
JMenu alignMenu = new JMenu("Text Align");
menuBar.add(fileMenu);
menuBar.add(alignMenu);
JMenuItem openItem = new JMenuItem("Open"); //
JMenuItem saveItem = new JMenuItem("Save"); //
openItem.addActionListener(this);
saveItem.addActionListener(this);
fileMenu.add(openItem);
fileMenu.add(saveItem);
JMenuItem leftAlignMenuItem = new JMenuItem(new StyledEditorKit.AlignmentAction("Left Align", StyleConstants.ALIGN_LEFT));
JMenuItem centerMenuItem = new JMenuItem(new StyledEditorKit.AlignmentAction("Center", StyleConstants.ALIGN_CENTER));
JMenuItem rightAlignMenuItem = new JMenuItem(new StyledEditorKit.AlignmentAction("Right Align", StyleConstants.ALIGN_RIGHT));
leftAlignMenuItem.setText("Left");
centerMenuItem.setText("Center");
rightAlignMenuItem.setText("Right");
alignMenu.add(leftAlignMenuItem);
alignMenu.add(centerMenuItem);
alignMenu.add(rightAlignMenuItem);
textPane = new JTextPane(doc); // Create object from doc and set this as value of textPane.
textPane.setContentType("text/html"); // textPane holds html.
JScrollPane scrollPane = new JScrollPane(textPane); // textPane in JScrollPane to allow scrolling if more text than space.
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); // Get screen size to use below.
Dimension scrollPaneSize = new Dimension(1*screenSize.width/2,1*screenSize.height/2); // Together with next line, sets dimensions of textPane relative to screen size.
scrollPane.setPreferredSize(scrollPaneSize);
getContentPane().add(scrollPane, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null);
show(); // Actually displays the interface.
}
public void actionPerformed(ActionEvent ae) { // Method called with action commands from interface objects above. Which action depends on the text of the interface element.
String actionCommand = ae.getActionCommand();
if (actionCommand.compareTo("Open") == 0){ // Calls method when action command received.
openDocument();
} else if (actionCommand.compareTo("Save") == 0){
saveDocument();
}
}
public void saveDocument(){
String FP = FilePath; // This paragraph calls Save As instead of Save if file not already saved.
String unsaved = "";
int saved = FP.compareTo(unsaved);
if (saved == 0) {
saveDocumentAs();
} else {
save();
}
}
public void saveDocumentAs(){
JFileChooser SaveDialog = new javax.swing.JFileChooser();
int returnVal = SaveDialog.showSaveDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
java.io.File saved_file = SaveDialog.getSelectedFile();
FilePath = saved_file.toString();
save();
}
}
public void save(){
try {
WriteFile objPane = new WriteFile(FilePath, false);
String PaneText = textPane.getText(); // Gets text from Title Pane.
objPane.writeToFile(PaneText);
}
catch (Exception ex) {
}
}
public void openDocument(){
JFileChooser OpenDialog = new javax.swing.JFileChooser(); // Creates file chooser object.
int returnVal = OpenDialog.showOpenDialog(this); // Defines 'returnVal' according to what user clicks in file chooser.
if (returnVal == JFileChooser.APPROVE_OPTION) { // Returns value depending on whether user clicks 'yes' or 'OK' etc.
java.io.File file = OpenDialog.getSelectedFile(); // Gets path of selected file.
FilePath = file.toString( ); // Converts path of selected file to String.
// The problem seems to be related to the code that starts here...
try {
ReadFile readPane = new ReadFile(FilePath); // Creates "readPane" object from "FilePath" string, using my ReadFile class.
String[] aryPane = readPane.OpenFile(); // Creates string array "aryPane" from "readPane" object.
int i; // Creates integer variable "i".
String PaneText = "";
for (i=0; i < aryPane.length; i++) { // Creates a for loop with starting "i" value of 0, adding 1 to i each time round and ending when i = the number of lines in the aryLines array.
PaneText = PaneText + aryPane[i]; // Add present line to "PaneText".
}
textPane.setText(PaneText); // Displays "PaneText" in "TextPane".
} catch (Exception ex) {
// and ends here. This code also calls ReadFile, so code in that class may be at fault.
}
}
}
}
它还必须调用以下两个类中的方法才能工作:
package aligntest;
import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;
public class ReadFile {
private String path;
public ReadFile(String file_path) {
path = file_path;
}
public String[] OpenFile() throws IOException {
FileReader fr = new FileReader(path);
BufferedReader textReader = new BufferedReader(fr);
int numberOfLines = readLines( );
String[] textData = new String[numberOfLines];
int i;
for (i=0; i < numberOfLines; i++) {
textData[i] = textReader.readLine();
}
textReader.close( );
return textData;
}
int readLines() throws IOException {
FileReader file_to_read = new FileReader(path);
BufferedReader bf = new BufferedReader(file_to_read);
String aLine;
int numberOfLines = 0;
while ((aLine = bf.readLine()) != null) {
numberOfLines++;
}
bf.close();
return numberOfLines;
}
}
&安培;
package aligntest;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.IOException;
public class WriteFile {
private String path;
private boolean append_to_file = false;
public WriteFile(String file_path) {
path = file_path;
}
public WriteFile(String file_path, boolean append_value) {
path = file_path;
}
public WriteFile(File SectionPath, boolean success) {
throw new UnsupportedOperationException("Not yet implemented");
}
public void writeToFile( String textLine ) throws IOException {
FileWriter write = new FileWriter(path, append_to_file);
PrintWriter print_line = new PrintWriter(write);
print_line.printf( "%s" + "%n" , textLine);
print_line.close();
}
}
问题似乎与打开文档(第126-138行)或“ReadFile&#39; class:在另一个程序中查看保存的文件时,我可以看到标签正在更改,直到文档关闭,然后再次使用&#39; AlignTest&#39;。在此之后,任何对齐更改都不会反映在html中。
希望有人能提供帮助。
编辑:以下是&#39; AlignTest&#39;制作的一些HTML。如果将其粘贴到文本文件中,然后在&#39; AlignTest&#39;中打开。它应该重现问题:&#39; AlignTest&#39;无法更改对齐标记。
<html>
<head>
<meta id="_moz_html_fragment">
</head>
<body>
<p align="right" style="margin-top: 0pt">
Another
</p>
</body>
</html>
答案 0 :(得分:1)
事实证明这比我想象的要困难得多。让我解释一下幕后发生的事情然后我会给出几个场景。
AlignmentAction
的操作会将setParagraphAttributes
设置为boolean replace
来调用文档的false
。在setParagraphAttributes
中,通过Alignment.XXX
将给定属性(MutableAttributeSet.addAttributes
)添加到段落标记的当前属性列表中。效果如下:
align="xxx"
。该文件将使用此新属性保存。text-align=xxx
。该文件仅使用HTML属性保存(CSS属性被丢弃,我不知道为什么,"
可能需要替换为'
)。摘要是,由于某种原因,无论运行时存在哪些属性,都只能保存HTML属性。由于未进行修改,因此必须先将其删除,然后再添加新属性。可能需要使用不同的作者。
尝试解决方案的一种方法是创建自己的对齐操作并将替换值设置为true
。问题是它取代了整个段落元素:
<html>
<head>
<meta id="_moz_html_fragment">
</head>
<body>
<body align="center">
Another
</body>
</body>
</html>
您需要做的是访问元素并“手动”替换属性。创建一个扩展HTMLDocument
和@override
setParagraphAttributes
的类,使其包含行
// attr is the current attribute set of the paragraph element
attr.removeAttribute(HTML.Attribute.ALIGN); // remove the HTML attribute
前
attr.addAttributes(s); // s is the given attributes containing the Alignment.XXX style.
然后按照上述1-4个方案保存文件将保持正确对齐。
最终,您会想要使用HTML解析器,例如jsoup;只是Google for Java HTML解析器。另请参阅Which HTML Parser is the best?
答案 1 :(得分:0)
以下是我在JTextPane中更改文本对齐方式(也可以在其他Swing组件中使用):
public void alignLeft() {
String text = textPane.getText();
text = text.replace("<p style=\"margin-top: 0\">", "<p align=left style=\"margin-top: 0\">");
text = text.replace("align=\"center\"", "align=\"left\"");
text = text.replace("align=\"right\"", "align=\"left\"");
textPane.setText(text);
和中心和右对齐的等价物。
如果有人在考虑使用请注意:
答案 2 :(得分:0)
我试图实现@ user1803551建议的解决方案,但是就像我在上面的评论中所说的那样,我找不到在只读的AttributeSet上使用removeAttribute()的方法。
我实现了建议的解决方案的不同版本,克隆了除对齐相关属性外的所有段落的AttributeSet。然后,使用带有replace = true的setParagraphAttributes覆盖当前属性,并使用带有replace = false的setParagraphAttributes应用请求的修改。看来效果很好。
public class ExtendedHTMLDocument extends HTMLDocument {
@Override
public void setParagraphAttributes(int offset, int length, AttributeSet attr, boolean replace) {
AttributeSet paragraphAttributes = this.getParagraphElement(offset).getAttributes();
MutableAttributeSet to = new SimpleAttributeSet();
Enumeration<?> keys = paragraphAttributes.getAttributeNames();
String value = "";
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (key instanceof CSS.Attribute) {
if (!key.equals(CSS.Attribute.TEXT_ALIGN)) {
value = value + " " + key + "=" + paragraphAttributes.getAttribute(key) + ";";
}
}
else {
if (!key.equals(HTML.Attribute.ALIGN)) {
to.addAttribute(key, paragraphAttributes.getAttribute(key));
}
}
}
if (value.length() > 0) {
to.addAttribute(HTML.Attribute.STYLE, value);
}
super.setParagraphAttributes(offset, length, to, true);
super.setParagraphAttributes(offset, length, attr, replace);
}
}