Java 在main()外部实例化类时GUI无响应

Java 在main()外部实例化类时GUI无响应,java,swing,opencv,Java,Swing,Opencv,我开始学习Java,我想使用OpenCV创建一个简单的摄像头提要查看器。 当从自己的main()方法实例化时,或者从调用方类的main()方法中进行调用时,MyCV类工作正常。 然后,我构建了一个“MyClient”类,其中包含一个main()方法和一个简单的GUI(实际上只有一个JFrame和一个JButton),因为我希望在MyClient GUI中按下按钮时显示MyCV GUI 问题是,当“调用者”类有自己的JFrame和关联的GUI元素时,我单击按钮,整个GUI冻结,MyCV类的框架显示

我开始学习Java,我想使用OpenCV创建一个简单的摄像头提要查看器。 当从自己的main()方法实例化时,或者从调用方类的main()方法中进行调用时,MyCV类工作正常。 然后,我构建了一个“MyClient”类,其中包含一个main()方法和一个简单的GUI(实际上只有一个JFrame和一个JButton),因为我希望在MyClient GUI中按下按钮时显示MyCV GUI

问题是,当“调用者”类有自己的JFrame和关联的GUI元素时,我单击按钮,整个GUI冻结,MyCV类的框架显示为空,两个窗口都没有响应

我还尝试了使用
SwingUtilities.invokeLater()
的类,但没有成功

正如我所说,我是Java/Swing的新手,在我看来这就像是一个paintComponent()问题,但就我个人而言,我无法解决它

非常感谢您的帮助

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;


public class MyCV {
    public static void main(String args[]){
        MyCV cv=new MyCV();
    }

    public MyCV(){
        System.loadLibrary( Core.NATIVE_LIBRARY_NAME );
        //-- Video capture structure
        VideoCapture feed=new VideoCapture(0);
        //-- Mat structures
        Mat imgFeed1=new Mat();
        Mat imgFeed2=new Mat();
        Mat imgFeed3=new Mat();
        Mat imgFeed4=new Mat();

        imgPanel feedPanel1=new imgPanel(); feedPanel1.setPreferredSize(new Dimension(400,400));
        imgPanel feedPanel2=new imgPanel(); feedPanel2.setPreferredSize(new Dimension(400,400));
        imgPanel feedPanel3=new imgPanel(); feedPanel3.setPreferredSize(new Dimension(400,400));
        imgPanel feedPanel4=new imgPanel(); feedPanel4.setPreferredSize(new Dimension(400,400));
        JPanel container=new JPanel(); container.setPreferredSize(new Dimension(800,800)); 
        container.add(feedPanel1);
        container.add(feedPanel2);
        container.add(feedPanel3);
        container.add(feedPanel4);

        JFrame f=new JFrame("MyChild");
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        f.add(container);
        f.setSize(1300, 800);
        f.setVisible(true);

        //-- clear resources on exit
        f.addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent e){
                feed.release();
                f.dispose();
            }
        });

        //-- main loop
        while(true){
             if(!feed.isOpened()) break;
             feed.read(imgFeed1);           
             if(imgFeed1.size().width==0) break;

             //-- display images in panels (Colors +Feed +Norm)
             feedPanel1.setimagewithMat(imgFeed1);
             feedPanel2.setimagewithMat(imgFeed1);
             feedPanel3.setimagewithMat(imgFeed1);
             feedPanel4.setimagewithMat(imgFeed1);

             // repaint frame
             container.repaint();
        }

    }


    class imgPanel extends JPanel{
        private static final long serialVersionUID=1L;
        private BufferedImage image;
        //public imgPanel(){ super(); }
        private BufferedImage getimage(){ return image; }
        public void setimage(BufferedImage newimage){image=newimage; return; }
        //-- called method
        public void setimagewithMat(Mat newimage){
            image=matToBufferedImage(newimage); 
            return; 
        }       
        //--
        //--
        public BufferedImage matToBufferedImage(Mat matrix) {  
             int cols = matrix.cols();  
             int rows = matrix.rows();  
             int elemSize = (int)matrix.elemSize();  
             byte[] data = new byte[cols * rows * elemSize];  
             int type;  
             matrix.get(0, 0, data);  
             switch (matrix.channels()) {  
               case 1:  
                 type = BufferedImage.TYPE_BYTE_GRAY;  
                 break;  
               case 3:  
                 type = BufferedImage.TYPE_3BYTE_BGR;  
                 // bgr to rgb  
                 byte b;  
                 for(int i=0; i<data.length; i=i+3) {  
                   b = data[i];  
                   data[i] = data[i+2];  
                   data[i+2] = b;  
                 }  
                 break;  
               default:  
                 return null;  
             }  
             BufferedImage image2 = new BufferedImage(cols, rows, type);  
             image2.getRaster().setDataElements(0, 0, cols, rows, data);
             return image2;  
           }

        @Override
        protected void paintComponent(Graphics g){
            super.paintComponent(g);
            BufferedImage temp=getimage();
            if(temp!=null){
                g.drawImage(temp,  0,  0,  temp.getWidth(), temp.getHeight(), this);
            }
        }
    }
}
上面是一个无限循环,在事件分派线程(aka
EDT
)上运行
Swing
是单线程的-所有事件、绘画等…都发生在一个线程(EDT)上-如果该线程由于任何原因被束缚在工作中,那么它的任何其他责任都不会发生(换句话说,看起来您的用户界面被锁定)。
main
方法在一个单独的线程上运行,因此您不会看到相同的行为(尽管对Swing组件的所有调用都应该放在EDT上,所以我不一定会用正确的方式调用它来绕过该行为)。三种选择:

  • 启动一个或多个新线程,并在该线程中放置任何长时间运行的任务(请注意,对Swing组件的任何调用都应使用SwingUtilities放置在EDT上)
  • 使用
  • 如果希望定期执行某些操作,例如动画,可以使用java.swing.Timer
  • 示例1:

    //long running task inside a new Thread
    new Thread(new Runnable(){
    
        @Override
        public void run(){
            while(true){
    
            }
        }
    
    });
    
    上面是一个无限循环,在事件分派线程(aka
    EDT
    )上运行
    Swing
    是单线程的-所有事件、绘画等…都发生在一个线程(EDT)上-如果该线程由于任何原因被束缚在工作中,那么它的任何其他责任都不会发生(换句话说,看起来您的用户界面被锁定)。
    main
    方法在一个单独的线程上运行,因此您不会看到相同的行为(尽管对Swing组件的所有调用都应该放在EDT上,所以我不一定会用正确的方式调用它来绕过该行为)。三种选择:

  • 启动一个或多个新线程,并在该线程中放置任何长时间运行的任务(请注意,对Swing组件的任何调用都应使用SwingUtilities放置在EDT上)
  • 使用
  • 如果希望定期执行某些操作,例如动画,可以使用java.swing.Timer
  • 示例1:

    //long running task inside a new Thread
    new Thread(new Runnable(){
    
        @Override
        public void run(){
            while(true){
    
            }
        }
    
    });
    

    while(true){
    这在EDT上运行一个无限循环。@copeg:我认为循环内容器面板的repaint()应该解决这个问题。此外,为什么只有在main()外调用MyCV时while循环才成问题?
    main
    是一个与EDT不同的线程-因此它在EDT外运行该循环(因此你看不到这个问题)。但是
    ActionListener
    代码是在EDT上运行的,就像
    SwingUtilities.invokeLater
    -所以这两个都进入了这个循环,阻塞了EDT
    ,而(true){
    这在EDT上运行了一个无限循环。@copeg:我认为重新绘制()循环内容器面板的线程应该注意这一点。此外,为什么只有在main()外部调用MyCV时while循环才会出现问题?
    main
    与EDT是不同的线程-因此它在EDT外部运行该循环(因此您没有看到此问题)但是,
    ActionListener
    代码和
    SwingUtilities.invokeLater
    -都是在EDT上运行的,所以这两个都落入了这个循环,阻塞了EDT。感谢您的清晰解释。它确实解决了我的问题。正如我所写的,我刚刚开始学习Java,还没有深入研究多线程。还有很多东西需要学习。谢谢您的帮助清楚的解释。它确实解决了我的问题。正如我所写的,我刚刚开始学习Java,还没有深入研究多线程。对我来说还有很多东西要学习。
    //long running task inside a new Thread
    new Thread(new Runnable(){
    
        @Override
        public void run(){
            while(true){
    
            }
        }
    
    });