4

私の問題は次のとおりです。

私の小さな HTML エディターのユーザーが、入力中のテキストの背景色を切り替えることができるようにしたいと考えています。私は最初に、その目的のために CSS スタイルを使用しようとしました。異なるスタイルは異なる背景色を定義しJComboBox、ユーザーはこれらのスタイルを切り替えることができます。内側のそれぞれの位置でスタイルを選択すると、HTMLDocumentタイプの新しい HTML 要素が <span class="style">入力されます。残念ながら、私はこの作品を手に入れることができませんでした。スパン要素は単に作成されませんでした (この問題に関する私の質問を参照してください)。

その間に、私はクラスを見て、StyledEditorKit.ForegroundAction これがどのように機能するかを学びました. 実行するとStyledEditorKit、使用中の入力属性が変更され、新しい前景色が設定されます。後で入力されるテキストは、新しい前景色で表示されます。HTML コードをファイルに書き込むと、テキストは自動的に<font color=".."> ... </font> HTML 要素で囲まれます。そして、複数の段落にまたがる可能性のある選択されたテキストでも機能します。この場合、影響を受けるすべての段落内の影響を受けるテキストは、明らかに<font ...>HTML タグで囲まれています。

テキストの任意のチャンクに背景色を設定するために、同じ機能を実現したいと考えています。しかし、驚くべきことに、これはそれほど簡単ではないようです:-(

StyledEditorKit.foregroundActionJava 7 JDK のような、その目的のための定義済みのアクション クラスが見つかりませんでした 。このようなクラスの作成は複雑ではないようです。前景属性の代わりに背景属性を設定するようにメソッドを変更しForegroundActionたものとほぼ同じ です。actionPerformed

しかし、含まれるテキストの一部に特定の背景色を設定する有効な HTML コードを作成するにはどうすればよいでしょうか? foreground 属性が設定されている のテキストHTMLEditorKitのすべての要素を のどの部分で作成するかは、これまでわかりませんでした。要素を作成する既存のコードから、テキストの任意の領域の背景色を設定するため の要素ではなく、要素を作成する実装を導き出すことはそれほど難しくないと思います。それとも、これらすべてがすでに利用可能で、私が気付かなかっただけですか? どんな助けでも大歓迎です!<font>HTMLDocument<font><span style="background-color:..."><font>

その間に私は大きな一歩を踏み出し、ここにあるコードのおかげで 有効な<span>要素を作成することができました. span 要素では、class属性を使用して定義済みのスタイルを割り当てます。

これが私のコードです:

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JTextPane;
import javax.swing.JToolBar;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleContext;
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 SimpleEditor extends JFrame {

    private static final long   serialVersionUID = 1L;
    private final JTextPane   textPane;
    private final HTMLEditorKit edtKit;
    private final HTMLDocument  doc;
    private final StyleSheet predefStyles;

    public static void main(String[] args) throws BadLocationException, IOException {
        final SimpleEditor editor = new SimpleEditor();
        editor.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        editor.setVisible(true);
    }

    public SimpleEditor() throws BadLocationException, IOException {
        super("Very Simple HTML Editor");
        textPane = new JTextPane();
        edtKit = new HTMLEditorKit();
        textPane.setEditorKit(edtKit);
        predefStyles = new StyleSheet();
        predefStyles.addRule(".MyStyle1 { color:#cc0000; background-color:silver }\n" +
                             ".MyStyle2 { color:#0000cc; background-color:aqua }");
        doc = new HTMLDocument(predefStyles);
        textPane.setDocument(doc);

        final Container content = getContentPane();
        content.add(textPane, BorderLayout.CENTER);
        content.add(createToolBar(), BorderLayout.NORTH);
        setJMenuBar(createMenuBar());
        setSize(500, 240);
    }

    private JToolBar createToolBar() {
        final Vector<String> styleNames = new Vector<String>();
        final Enumeration<?> names = predefStyles.getStyleNames();
        while (names.hasMoreElements()) {
            styleNames.add((String) names.nextElement());
        }
        final DefaultComboBoxModel<String> stylesModel =
                new DefaultComboBoxModel<String>(styleNames);
        final JComboBox<String> cbStyleSel = new JComboBox<String>(stylesModel);
        final JToolBar bar = new JToolBar();
        Action dumpAction = null;
        for (final Action act : edtKit.getActions()) {
            if (act.getValue(Action.NAME).equals("dump-model")) {
                dumpAction = act;
                break;
            }
        }
        bar.add(dumpAction);
        cbStyleSel.setEditable(false);
        cbStyleSel.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                e.getSource();
                @SuppressWarnings("unchecked")
                final JComboBox<CondStyle> cboStyleSel = (JComboBox<CondStyle>) e.getSource();
                final String selItem = (String) cboStyleSel.getSelectedItem();
                final MutableAttributeSet divAttributes = new SimpleAttributeSet();
                if (selItem.equals("default")) {
                    // This does not work!
                    final Style defStyle = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
                    divAttributes.addAttribute(HTML.Tag.CONTENT, defStyle);
                    textPane.setCharacterAttributes(divAttributes, true);
                } else {
                    divAttributes.addAttribute(HTML.Attribute.CLASS, selItem.substring(1));
                    final MutableAttributeSet tagAttributes = new SimpleAttributeSet();
                    tagAttributes.addAttribute(HTML.Tag.SPAN, divAttributes);
                    textPane.setCharacterAttributes(tagAttributes, false);
                }
                textPane.requestFocusInWindow();
            }
        });
        bar.add(cbStyleSel);
        return bar;
    }

    /**
     * Extracts the style attributes except the style's name
     * @param aStyle The style to be processed
     * @return The visual attributes extracted from the style
     */
    AttributeSet extractStyleAttribs(Style aStyle) {
        final MutableAttributeSet attribs = new SimpleAttributeSet();
        final Enumeration<?> attribNames = aStyle.getAttributeNames();
        while (attribNames.hasMoreElements()) {
            final Object attribName = attribNames.nextElement();
            if (attribName == Style.NameAttribute) {
                continue;
            }
            attribs.addAttribute(attribName, aStyle.getAttribute(attribName));
        }
        return attribs;
    }

    private JMenuBar createMenuBar() {
        final JMenuBar menubar = new JMenuBar();
        final JMenu mnuFile = new JMenu("File");
        menubar.add(mnuFile);
        final SaveAction actSave = new SaveAction();
        mnuFile.add(actSave);
        return menubar;
    }

    class SaveAction extends AbstractAction {
        private static final long serialVersionUID = 1L;
        public SaveAction() {
            super("Save");
        }
        @Override
        public void actionPerformed(ActionEvent ev) {
            final JFileChooser chooser = new JFileChooser();
            if (chooser.showSaveDialog(SimpleEditor.this) != JFileChooser.APPROVE_OPTION)
                return;
            final File file = chooser.getSelectedFile();
            if (file == null)
                return;
            FileWriter writer = null;
            try {
                writer = new FileWriter(file);
                textPane.write(writer);
            } catch (final IOException ex) {
                JOptionPane.showMessageDialog(SimpleEditor.this,
                                              "File Not Saved", "ERROR",
                                              JOptionPane.ERROR_MESSAGE);
            } finally {
                if (writer != null) {
                    try {
                        writer.close();
                    } catch (final IOException x) {
                    }
                }
            }
        }
    }
}

ここまでは順調ですね!<span>このソリューションの唯一の問題は、要素に囲まれたテキストから「通常の」テキスト、つまり要素内に配置されていないテキストへの切り替えを実装できなかったこと<span>です。これは大したことではないはずですが、残念ながら、それを達成する方法がわかりませんでした。どんなアイデアでも大歓迎です!

4

1 に答える 1

0

わかった!そして、それはとても簡単です;-) 要素を使用してスタイル付きテキスト エントリから元に戻すには、現在のテキストの入力属性から属性<span>を削除するだけで済みました。HTML.Tag.SPANこれは次のように行われます。

edtKit.getInputAttributes().removeAttribute(HTML.Tag.SPAN);

そのため、(更新された) 質問に投稿したサンプル コードの ActionListener のコードは次のようになります。

        cbStyleSel.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            e.getSource();
            @SuppressWarnings("unchecked")
            final JComboBox<CondStyle> cboStyleSel = (JComboBox<CondStyle>) e.getSource();
            final String selItem = (String) cboStyleSel.getSelectedItem();
            if (selItem.equals("default")) {
                edtKit.getInputAttributes().removeAttribute(HTML.Tag.SPAN);
            } else {
                final MutableAttributeSet divAttributes = new SimpleAttributeSet();
                divAttributes.addAttribute(HTML.Attribute.CLASS, selItem.substring(1));
                final MutableAttributeSet tagAttributes = new SimpleAttributeSet();
                tagAttributes.addAttribute(HTML.Tag.SPAN, divAttributes);
                textPane.setCharacterAttributes(tagAttributes, false);
            }
            textPane.requestFocusInWindow();
        }
    });

その機能の実装に関する問題について複数の質問を投稿しましたが (こちらおよびこちらを参照)、回答がありませんでした。たぶん、問題はあまりにも些細なことでした;-)

于 2013-08-06T12:31:17.873 に答える