我正在限时制作学校项目,导致代码混淆和混乱。我正在尝试打开两个jFrame,一个显示聊天界面,另一个显示图像。从第一个窗口调用actionPerformed()
后,我想调用一种方法,多次更改第二个窗口上的图像,两者之间有一些延迟。但是,图像不会改变。
我认为我的问题出现了,因为在文本窗口中使用了一段示例代码,并尝试合并我自己的修改,而不是完全理解前者。在尝试查找这个问题时,我发现人们只是根据计时器和actionPerformed()
更新了他们的jFrame,这实际上不是我想要的行为。
以下是有问题的代码:
package main;
import java.awt.event.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
public class Runner extends JPanel implements ActionListener {
JFrame fFrame = new JFrame("Leonardo");
protected JTextField textField;
protected JTextPane textArea;
private final static String newline = "\n";
Dictionary dict = new Dictionary();
StyleContext uContext = new StyleContext();
StyleContext rContext = new StyleContext();
Style uStyle;
Style rStyle;
JLabel lbl=new JLabel();
public Runner() {
super(new GridBagLayout());
styleInit();
textField = new JTextField(20);
textField.addActionListener(this);
textArea = new JTextPane();
textArea.setEditable(false);
textArea.setBackground(Color.BLACK);
JScrollPane scrollPane = new JScrollPane(textArea);
//Add Components to this panel.
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.HORIZONTAL;
add(textField, c);
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.weighty = 1.0;
add(scrollPane, c);
}
public void actionPerformed(ActionEvent evt) {
String text = textField.getText();
StyledDocument doc = textArea.getStyledDocument();
try {
doc.insertString(doc.getLength(), "You: " + text + newline, uStyle);
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
textArea.setStyledDocument(doc);
try { //this is the section which is not working properly
changeLeonardo("Leonardo_Thinking.jpg");
repaint();
TimeUnit.SECONDS.sleep(1);
for(int i = 0; i<3; i++){
changeLeonardo("Leonardo_Talking1.jpg");
TimeUnit.SECONDS.sleep(1);
changeLeonardo("Leonardo_Talking2.jpg");
TimeUnit.SECONDS.sleep(1);
}
} catch (InterruptedException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
try {
doc.insertString(doc.getLength(), "Leonardo: " + Logic.respondIntelligent(text, dict)+ newline, rStyle);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
textArea.setStyledDocument(doc);
textField.selectAll();
textArea.setCaretPosition(textArea.getDocument().getLength());
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event dispatch thread.
*/
private void styleInit(){
uStyle = uContext.addStyle("User", null);
uStyle.addAttribute(StyleConstants.Foreground, Color.WHITE);
uStyle.addAttribute(StyleConstants.FontFamily, Font.SANS_SERIF);
uStyle.addAttribute(StyleConstants.FontSize, new Integer(16));
rStyle = rContext.addStyle("Robot", null);
rStyle.addAttribute(StyleConstants.Foreground, Color.GREEN);
rStyle.addAttribute(StyleConstants.FontFamily, Font.MONOSPACED);
rStyle.addAttribute(StyleConstants.FontSize, new Integer(20));
}
private void changeLeonardo(String imgName){
BufferedImage img = null;
try {
img = ImageIO.read(new File("C:\\resources\\" + imgName));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("C:\\resources\\" + imgName);
ImageIcon icon=new ImageIcon(img);
lbl.setIcon(icon);
revalidate();
repaint();
}
private void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("Leonardo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fFrame.setLayout(new FlowLayout());
changeLeonardo("Leonardo_Idle.jpg");
frame.add(new Runner());
frame.pack();
frame.setVisible(true);
fFrame.pack();
fFrame.setVisible(true);
fFrame.add(lbl);
}
public static void main(String[] args) {
//Schedule a job for the event dispatch thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
Runner runner = new Runner ();
runner.createAndShowGUI();
}
});
}
}
有些注意事项:
请原谅任何奇怪的名字,例如fFrame
这样做可以使代码更好地反映学校项目。除此之外的所有类,如逻辑或字典都可以正常工作。代码不会抛出任何错误。我编辑了图像的文件名以保护隐私,但它们在代码中已满。
我确定此代码中还有其他问题,因为我通常不是图形专家,但如果您能够专注于更新问题,我将非常感谢。
谢谢。
答案 0 :(得分:2)
所以,你想尝试两个基本概念,让你了解......
首先,为了在其他类上调用方法,需要对它进行引用。您并不总是希望自己创建该引用,有时,您只想提交预先创建的引用,这允许您修改引用对象的实际底层实现,而无需修改依赖于的代码它...
这通常是通过使用interface
来实现的,因为它可以减少实施的风险,并且可以防止API的其余部分使用他们不应该参考的内容,但是这样做了#39}。另一个讨论点......
基本上,您需要将图像帧的引用传递给图形框架,以便图形框架可以在需要时调用图像框架。在下面的示例中,这是由BrowserPane
完成的,需要SlideShowPane
的实例通过它的构造函数传递给它...
SlideShowPane slideShowPane = new SlideShowPane();
//...
browser.add(new BrowserPane(slideShowPane));
BrowserPane
可以使用此引用来调用SlideShowPane
上的方法,特别是setPath
方法......
slideShowPane.setPath(path);
这将导致SlideShowPane
根据过去的目录/路径的内容开始新的幻灯片放映。
第二个概念是Swing是一个单线程环境,它也是一个事件驱动的环境。
第一部分意味着您无法阻止UI线程,否则它无法处理重绘请求等。第二部分重点介绍了一种可以解决此问题的方法。
在此示例中,我只使用javax.swing.Timer
在图像之间设置了1秒的延迟。计时器在后台等待(在它自己的线程中),当被触发时,将在UI线程的上下文中调用已注册的ActionListener
的{{1}}方法,使其成为可能可以安全地从内部更新UI。
这确保UI线程不会被阻止,并且可以继续处理新事件,同时为我们提供了一种执行延迟回调的便捷机制
请查看Concurrency in Swing和How to Use Swing Timers了解详情
actionPerformed