如何在第二个窗口中更新jFrame?

我正在限时制作一个学校项目,导致混淆代码和混乱。 我正在尝试打开两个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 ,这样可以使代码更好地反映学校项目。 除此之外的所有类,如Logic或Dictionary都可以正常工作。 代码不会抛出任何错误。 我编辑了图像的文件名以保护隐私,但它们在代码中已满。

我确信此代码中还有其他问题,因为我通常不是图形专家,但如果您能够专注于更新问题,我将非常感激。

谢谢。

那么,你想要尝试的两个基本概念,让你的头脑……

第一种,为了在其他类上调用方法,需要对它进行引用。 您并不总是希望自己创建该引用,有时,您只是希望获得预先创建的引用,这允许您修改引用对象的实际底层实现,而无需修改依赖它的代码。 ..

这通常是通过使用interface最好地实现的,因为它减少了实现的暴露并且阻止了API的其余部分使用它们不应该的引用,但这是另一个讨论点……

基本上,您需要将图像帧的引用传递给图形框架,以便图形框架可以在需要时调用图像框架。 在下面的示例中,这是由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线程的上下文中调用已注册的ActionListeneractionPerformed方法,从而可以安全地从内部更新UI。

这可确保UI线程不会被阻止,并可继续处理新事件,同时为我们提供执行延迟回调的便捷机制

有关更多详细信息,请参阅Swing中的Concurrency和如何使用Swing Timers

 import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.GridBagLayout; import java.awt.Image; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.ImageIO; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class SlideShow { public static void main(String[] args) { new SlideShow(); } public SlideShow() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gd = ge.getDefaultScreenDevice(); Rectangle bounds = gd.getDefaultConfiguration().getBounds(); System.out.println(bounds); SlideShowPane slideShowPane = new SlideShowPane(); JFrame frame = new JFrame("Image"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(slideShowPane); frame.pack(); int x = (bounds.x + (bounds.width / 2)) - frame.getWidth(); int y = (bounds.y + (bounds.height - frame.getHeight()) / 2); frame.setLocation(x, y); frame.setVisible(true); JFrame browser = new JFrame("Browser"); browser.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); browser.add(new BrowserPane(slideShowPane)); browser.pack(); x = (bounds.x + (bounds.width / 2)) + browser.getWidth(); y = (bounds.y + (bounds.height - browser.getHeight()) / 2); browser.setLocation(x, y); browser.setVisible(true); } }); } public class BrowserPane extends JPanel { private SlideShowPane slideShowPane; private JFileChooser chooser; private BrowserPane(SlideShowPane pane) { this.slideShowPane = pane; setLayout(new GridBagLayout()); JButton browse = new JButton("..."); add(browse); browse.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (chooser == null) { chooser = new JFileChooser(); chooser.setMultiSelectionEnabled(false); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); } switch (chooser.showOpenDialog(BrowserPane.this)) { case JFileChooser.APPROVE_OPTION: File path = chooser.getSelectedFile(); slideShowPane.setPath(path); break; } } }); } } public class SlideShowPane extends JPanel { private File path; private Timer timer; private List imageList; private int nextImage; private Image currentImage; public SlideShowPane() { imageList = new ArrayList<>(25); timer = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (imageList != null && !imageList.isEmpty()) { nextImage++; if (nextImage >= imageList.size()) { nextImage = 0; } System.out.println("NextImage = " + nextImage); do { try { File file = imageList.get(nextImage); System.out.println("Load " + file); currentImage = ImageIO.read(file); } catch (IOException ex) { currentImage = null; nextImage++; ex.printStackTrace(); } } while (currentImage == null && nextImage < imageList.size()); repaint(); } } }); timer.setInitialDelay(0); } public void setPath(File path) { System.out.println("SetPath"); this.path = path; timer.stop(); imageList.clear(); currentImage = null; if (path.isDirectory()) { File files[] = path.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { String name = pathname.getName().toLowerCase(); return name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".png") || name.endsWith(".bmp") || name.endsWith(".gif"); } }); if (files != null) { System.out.println("Found " + files.length + " matches"); imageList.addAll(Arrays.asList(files)); } } if (imageList.isEmpty()) { repaint(); } else { System.out.println("Start timer..."); nextImage = -1; timer.restart(); } } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } protected void paintComponent(Graphics g) { super.paintComponent(g); if (currentImage != null) { Graphics2D g2d = (Graphics2D) g.create(); int x = (getWidth() - currentImage.getWidth(this)) / 2; int y = (getHeight() - currentImage.getHeight(this)) / 2; g2d.drawImage(currentImage, x, y, this); g2d.dispose(); } } } }