Быстрая запись в JEditorPane
В приведенном ниже коде я хотел бы записать на JEditorPane числа от 0 до 10000. Однако JEditorPane не отображает ничего, если только это не будет полностью выполнено (печать всех от 0 до 10000 за раз) или когда ОС дает время для обновления и показать содержимое. В любом случае, приложение перестает отвечать на запросы, которые пользователь считает сбойными. Можно ли в любом случае заставить jEditorPane отображать обновленное содержимое, даже если оно все еще занято? Я пробовал invokeAndWait, но здесь это не помогает, так как мы не можем вызвать invokeAndWait из потока диспетчера событий.
Другими словами, если я заменю Thread.sleep(0)
с Thread.sleep(50)
, он работает нормально и отображает распечатку результатов по мере их появления, но добавление задержки 50 мс делает его чрезвычайно медленным. все, что я хочу, это время от времени обновлять JEditorPane, чтобы пользователь не думал, что приложение потерпело крах. Я предпочитаю только модифицировать updateMessages(). Вот мой код:
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
public class CMessageWindowStack {
private static final String MESSAGE = "msg";
private JScrollPane scrollPane;
public JEditorPane editorPane;
private HTMLEditorKit kit;
private String msgBuffer=new String("");
private static CMessageWindowStack window=null;
private static JFrame frameContainer=null;
private CMessageWindowStack()
{
editorPane = new JEditorPane ();
editorPane.setEditable(false);
editorPane.setContentType("text/html");
kit = new HTMLEditorKit();
editorPane.setEditorKit(kit);
StyleSheet styleSheet = kit.getStyleSheet();
styleSheet.addRule("."+MESSAGE+" {font: 10px monaco; color: black; }");
Document doc = kit.createDefaultDocument();
editorPane.setDocument(doc);
scrollPane = new JScrollPane(editorPane);
}
public static CMessageWindowStack getInstance(){
if (null==window)
{window=new CMessageWindowStack();}
return window;
}
/**
* The core
* @param sMessage
* @param sType
*/
private void updateMessages(final String sMessage, final String sType)
{
SwingUtilities.invokeLater( new Runnable() {
public void run() {
String sMessageHTML="";
String sTypeText="";
if (!sMessage.equals("\r\n")){
sTypeText = sType+": ";
}
sMessageHTML = sMessage.replaceAll("(\r\n|\n)", "<br/>");
if (!sMessageHTML.equals("<br/>"))
{
sMessageHTML = "<SPAN CLASS="+sType+">"+ sTypeText+sMessageHTML + "</SPAN>";
}
msgBuffer=msgBuffer.concat( sMessageHTML);
editorPane.setText(msgBuffer);
if ((editorPane.getDocument()).getLength()>1){
editorPane.setCaretPosition((editorPane.getDocument()).getLength()-1);
}
}
});
}
public void setContainerFrame(JFrame jFrame){
frameContainer = jFrame;
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(frameContainer.getContentPane());
frameContainer.getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(scrollPane)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 217, Short.MAX_VALUE))
);
}
public void setVisible(boolean bVisible){
editorPane.setVisible(bVisible);
scrollPane.setVisible(bVisible);
}
public void printMsg(String sMessage){
String sType = MESSAGE;
updateMessages(sMessage,sType);
}
public void printlnMsg(String sMessage){
sMessage=sMessage.concat("\r\n");
printMsg(sMessage);
}
public static void main(String args[]){
CMessageWindowStack m_LogMgr;
JFrame frame = new JFrame();
m_LogMgr=CMessageWindowStack.getInstance();
m_LogMgr.setContainerFrame(frame);
frame.setVisible(true);
frame.setSize(500, 500);
for(int i=0;i<10000;++i){
try {
Thread.sleep(0);//becomes unresponsive if sleep(0)
} catch (Exception e) {
}
m_LogMgr.printlnMsg(i+"-----------------------");
}
}
}
3 ответа
Вы, вероятно, должны использовать SwingWorker. Начните с начальной загрузки JEditorPane с вашим основным HTML. Тогда вам нужно будет publish
каждая строка данных. Когда данные будут опубликованы, вам нужно будет вставить текст в панель редактора.
Основная идея в том, что вы не можете просто создать всю строку HTML сразу.
Я никогда не мог по-настоящему понять, как использовать JEditorPane с динамически меняющимся HTML. Может быть, вы можете просто использовать JTextPane. Он поддерживает разные шрифты и цвета и его гораздо проще динамически обновлять.
Хорошо - как взломать вы можете попробовать что-то вроде этого:
for(int i=0;i<10000;++i){
try {
if( i%100 == 0 ) {
Thread.sleep(10);//becomes unresponsive if sleep(0)
}
} catch (Exception e) {
}
m_LogMgr.printlnMsg(i+"-----------------------");
}
Вы можете попробовать использовать Thread и придать ему наивысший приоритет. Также вы можете добавить опцию -XmX2020 в java.exe.
Другое решение может быть, если вы используете JTextArea вместо JEdiorPane
, Кажется, что все, что вы делаете с HTML, это стилизация шрифтов. Вы можете сделать это используя java.awt.Font
собственность на JTextArea.