#java #swing #jtextpane #styleddocument #word-processor
Вопрос:
Я работаю над программой базы данных, в которой графический интерфейс имеет несколько областей ввода, некоторые из которых являются областями JTextPanes, где пользователь может устанавливать стили полужирного, подчеркивания и курсива в своем тексте. Например, когда пользователь помещает курсор непосредственно рядом с областью, которая уже выделена жирным шрифтом, я хочу, чтобы следующий текст, который они вводят, также был выделен жирным шрифтом. Пока единственное, что происходит, — это то, что текст, набранный сразу после выделенного жирным шрифтом текста, выделен жирным шрифтом, но я не могу сделать так, чтобы текст, набранный непосредственно перед выделенным жирным шрифтом, был также выделен жирным шрифтом.
Я не уверен, что все это было менее чем запутанно, поэтому вот пример: предположим, что предложение «Java-это весело». уже находится в одной из областей JTextPanes.
Если пользователь помещает курсор слева или справа от «есть», я хочу, чтобы все, что они печатают рядом, также было выделено жирным шрифтом. Вот так, «Веселая Java—панель».
До сих пор я только получаю: «Java foo-это весело».
Ниже приведен метод, который я использую для добавления функций определения стиля в каретку JTextPane, и то, что, как я думал, сработает для этого.
Я также попытался добавить дополнительный новый StyledEditorKit.BoldAction().actionPerformed(null)
до или после boldButton.setSelected(true), но это не возымело никакого эффекта. Я также попытался tp.getStyledDocument().setCharacterAttributes(caretPosition -1, 1, asPrev, true)
, и хотя это сделало следующий текст выделенным жирным шрифтом, результаты были непредсказуемыми, со случайными разрывами строк и пропущенными символами. Changing boldButton.setSelected(true)
чтобы boldButton.doClick()
не имело никакого эффекта, равно как и использование моего класса ButtonAction для выделения текста жирным шрифтом.
int lastCaretPosition;
public void formatAndAddFunctions(Component c) {
Font normalFont = new Font("Tahoma", Font.PLAIN, 11);
c.setFont(normalFont);
if (c instanceof JTextField) {
((JTextField) c).setAlignmentX(Component.LEFT_ALIGNMENT);
((JTextField) c).addFocusListener(new java.awt.event.FocusAdapter() {
@Override
public void focusGained(java.awt.event.FocusEvent evt) {
((JTextField) c).selectAll();
activeComponent = c;
}
});
UndoTool.addUndoFunctionality((JTextField) c);
}
if (c instanceof JScrollPane) {
((JScrollPane) c).setAlignmentX(Component.LEFT_ALIGNMENT);
JViewport vp = ((JScrollPane) c).getViewport();
JTextPane tp = (JTextPane) vp.getView();
tp.setContentType("text/html");
tp.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, true);
tp.addFocusListener(new java.awt.event.FocusAdapter() {
@Override
public void focusGained(java.awt.event.FocusEvent evt) {
activeComponent = tp;
}
});
UndoTool.addUndoFunctionality(tp);
//look at the character attibutes before and after the caret to see if they are
//formatted bold, underline, and/or italic
lastCaretPosition = -1;
tp.addCaretListener((CaretEvent ce) -> {
int caretPosition = tp.getCaretPosition();
if(caretPosition != lastCaretPosition) {
lastCaretPosition = caretPosition;
Element charElementPrev = tp.getStyledDocument().getCharacterElement(caretPosition - 1);
AttributeSet asPrev = charElementPrev.getAttributes();
Element charElementAfter = tp.getStyledDocument().getCharacterElement(caretPosition);
AttributeSet asAfter = charElementAfter.getAttributes();
if ((StyleConstants.isBold(asPrev) || StyleConstants.isBold(asAfter)) amp;amp; !boldButton.isSelected()) {
boldButton.setSelected(true);
} else if((!StyleConstants.isBold(asPrev) amp;amp; !StyleConstants.isBold(asAfter)) amp;amp; boldButton.isSelected()) {
boldButton.setSelected(false);
}
if ((StyleConstants.isUnderline(asPrev) || StyleConstants.isUnderline(asAfter)) amp;amp; !ulButton.isSelected()) {
ulButton.setSelected(true);
} else if ((!StyleConstants.isUnderline(asPrev) amp;amp; !StyleConstants.isUnderline(asAfter)) amp;amp; ulButton.isSelected()) {
ulButton.setSelected(false);
}
if ((StyleConstants.isItalic(asPrev) || StyleConstants.isItalic(asAfter)) amp;amp; !itButton.isSelected()) {
itButton.setSelected(true);
} else if ((!StyleConstants.isItalic(asPrev) amp;amp; !StyleConstants.isItalic(asAfter)) amp;amp; itButton.isSelected()) {
itButton.setSelected(false);
}
}
});
tp.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_B, java.awt.event.InputEvent.CTRL_DOWN_MASK), "boldKeystroke");
tp.getActionMap().put("boldKeystroke", new ButtonAction("bold"));
tp.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_U, java.awt.event.InputEvent.CTRL_DOWN_MASK), "underlineKeystroke");
tp.getActionMap().put("underlineKeystroke", new ButtonAction("underline"));
tp.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_I, java.awt.event.InputEvent.CTRL_DOWN_MASK), "italicKeystroke");
tp.getActionMap().put("italicKeystroke", new ButtonAction("italic"));
}
}
И, для справки, код boldButton:
boldButton = new JToggleButton();
boldButton.setIcon(allIcons[39]);
boldButton.setRolloverIcon(allIcons[40]);
boldButton.setSelectedIcon(allIcons[41]);
boldButton.setToolTipText("Bold");
boldButton.setBorderPainted(false);
boldButton.setContentAreaFilled(false);
boldButton.setFocusable(false);
boldButton.setBorder(null);
boldButton.setMargin(noInset);
boldButton.addActionListener((java.awt.event.ActionEvent e) -> {
new StyledEditorKit.BoldAction().actionPerformed(e);
activeComponent.requestFocusInWindow();
});
Странно то, что если я установлю курсор прямо перед выделенным жирным шрифтом текстом, а затем нажму на кнопку переключения жирного шрифта в пользовательском интерфейсе, следующий набранный текст будет выделен жирным шрифтом. Но я, кажется, не могу добиться этого программно. Есть какие-нибудь идеи?
Комментарии:
1. Именно так работают редакторы, подобные Word. Типизированный символ наследует атрибуты предыдущего символа. … затем нажмите на переключатель, выделенный жирным шрифтом… — это временная настройка атрибута ввода. Да, если вы наберете сразу, вы получите текст, выделенный жирным шрифтом. Однако, если вы нажмете кнопку, выделенную жирным шрифтом, затем щелкните в другом месте, а затем вернетесь в предыдущее место, вы не получите текст, выделенный жирным шрифтом. Есть какие- нибудь идеи? — Я бы не стал пытаться изменить это поведение. Это не интуитивно понятно.
2. Хм…ты прав. Я только что проверил в Word, и это действительно так. Типизированный символ наследует атрибуты предыдущего символа, но не следующего. Исключением из этого правила является, если строка начинается с отформатированного символа; тогда ввод в начале строки наследует атрибуты следующего символа. Возможно, стоило бы просто оставить все как есть.