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

标签 java image swing jframe updates

我正在有限的时间内完成一个学校项目,导致代码困惑和困惑。我试图打开两个 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,这样做是为了使代码更好地反射(reflect)学校项目。除此以外的所有类(例如逻辑或字典)都可以正常工作。该代码不会引发任何错误。出于隐私考虑,我编辑了图像的文件名,但它们在代码中已完整。

我确信此代码中还存在大量其他问题,因为我通常不是图形专家,但如果您能关注更新问题,我将不胜感激。

谢谢。

最佳答案

那么,您需要尝试并理解两个基本概念......

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

这通常最好通过使用接口(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线程不被阻塞并且可以继续处理新事件,同时为我们提供了执行延迟回调的便捷机制

看看Concurrency in SwingHow to Use 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<File> 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();
            }
        }

    }

}

关于java - 如何在第二个窗口中更新 jFrame?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24111940/

相关文章:

java - 不使用 MNIST 的 Tensorflow 初学者示例

java - 十字路口的线程同步

java - 将 JLabel 拖到 JFrame 之外

在调整窗口大小之前,javafx SwingNode 不工作

使用 Maven 的 NetBeans 中的 Java 路径

java - 缓存和使缓存的 Mono 失效

php - 如何解析 xml 站点地图中的图像标签?

CSS如何在不裁剪的情况下保持图像大小

iphone - 关于 Apple 的 LazyTableImages 示例的问题 - 行为与应用程序商店不完全相同

java - 手动关闭java swing窗口