JTextPane无法显示来自其他类的追加字符串问题
问题:TestRun类无法向UI的JTextPane追加文本
我创建了两个类:urlTestUI.java(用Eclipse Window Builder创建)和TestRun.java(普通类)。点击urlTestUI里的按钮调用TestRun的方法时,TestRun中的字符串无法显示在JTextPane中,但urlTestUI自身的字符串能正常追加到JTextPane。目前TestRun的方法能正常执行(控制台有输出),因为后续要加文本颜色功能所以用了JTextPane而非JTextArea。
相关代码
urlTestUI.java
import java.awt.Color; import javax.swing.JFrame; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.text.BadLocationException; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import javax.swing.JButton; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import javax.swing.JScrollPane; import javax.swing.JTextPane; public class urlTestUI { private JFrame frame; static urlTestUI window; // AppendingTextPane atp = new AppendingTextPane(); AppendTextPane atp1= new AppendTextPane(); SwingWorker<Object, String> worker; /** * Launch the application. */ public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { // EventQueue.invokeLater(new Runnable() { public void run() { try { window = new urlTestUI(); window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the application. */ public urlTestUI() { initialize(); } /** * Initialize the contents of the frame. */ private void initialize() { frame = new JFrame(); frame.setBounds(100, 100, 822, 473); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().setLayout(null); JButton btnNewButton = new JButton("Start"); btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { TestRun tr =new TestRun(); tr.method1(); atp1.appendText("helloText1"); }; }); btnNewButton.setBounds(367, 111, 89, 23); frame.getContentPane().add(btnNewButton); JScrollPane scrollPane = new JScrollPane(); scrollPane.setBounds(10, 169, 790, 258); frame.getContentPane().add(scrollPane); JTextPane textPane = new JTextPane(); scrollPane.setViewportView(atp1); } public class AppendTextPane extends JTextPane { JTextPane textpane; // public AppendTextPane(JTextPane textpane) { // this.textpane=textpane; // } public void appendText(String str) { // Document doc = getDocument(); StyledDocument doc = getStyledDocument(); Style style = doc.addStyle("MyStyle", null); StyleConstants.setForeground(style, Color.BLACK); StyleConstants.setFontSize(style, 12); StyleConstants.setFontFamily(style, "Arial"); try { doc.insertString(doc.getLength(), str, style); } catch (BadLocationException e) { e.printStackTrace(); } } } }
TestRun.java
public class TestRun extends urlTestUI { // AppendingTextPane atp=new AppendingTextPane(); boolean isSomthing=true; public void method1() { if(isSomthing=true) { atp1.appendText("helloText2"); System.out.println("helloText3"); }else { System.out.println("helloText4"); atp1.appendText("helloText5"); } } public void method2() { atp1.appendText("helloTest6"); } }
问题原因与解决方案
核心原因
你创建的TestRun对象是urlTestUI的子类实例,它内部的atp1是全新的AppendTextPane实例,和界面上显示的那个atp1不是同一个对象。所以TestRun里调用atp1.appendText()是给新的、未挂载到界面的组件加文本,自然看不到效果。
解决方案
方案1:解除继承,传递组件引用(推荐)
把TestRun改成普通类,通过构造方法传入界面上的AppendTextPane实例,让它直接操作显示中的组件:
修改TestRun.java:
public class TestRun { private AppendTextPane targetPane; boolean isSomthing=true; // 构造方法传入要操作的文本面板 public TestRun(AppendTextPane targetPane) { this.targetPane = targetPane; } public void method1() { if(isSomthing) { // 修正原代码的赋值操作=,改为直接判断布尔值 targetPane.appendText("helloText2\n"); System.out.println("helloText3"); }else { System.out.println("helloText4"); targetPane.appendText("helloText5\n"); } } public void method2() { targetPane.appendText("helloTest6\n"); } }
修改urlTestUI的按钮点击事件:
btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // 传入界面上正在显示的atp1实例 TestRun tr = new TestRun(atp1); tr.method1(); atp1.appendText("helloText1\n"); } });
方案2:复用已有的UI实例(不推荐,耦合性高)
如果要保留继承关系,不要新建TestRun实例,而是用当前已有的window静态实例:
修改按钮点击事件:
btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // 复用已初始化的window实例,强制转为TestRun类型 ((TestRun)window).method1(); atp1.appendText("helloText1\n"); } });
同时需要修改urlTestUI类定义,让它继承TestRun,否则强制类型转换会报错。这种方式会让类耦合度变高,后续维护成本大,不推荐使用。
额外注意点
- 原代码中
if(isSomthing=true)是赋值操作,永远为true,应改为if(isSomthing)或if(isSomthing == true)。 - 追加文本时建议加上
\n换行,让内容排版更清晰。 - 如果TestRun的方法是耗时操作,必须改用
SwingWorker执行,避免阻塞EDT(事件调度线程)导致界面卡顿。
内容的提问来源于stack exchange,提问作者naveenjtrn
相关产品推荐
相关产品推荐

