【问题标题】:How to create a instance如何创建实例
【发布时间】:2015-02-11 07:39:01
【问题描述】:

我有两个类,一个主类和一个扩展 JPanel 并实现 Runnable 的类。我正在尝试在 actionListener 中为 JPanel 类的同一个实例创建两个线程,但我只是不知道在哪里创建 JPanel1 对象...

//编辑:按钮1是应用程序的开始。之后,按钮2将出现一个带有标签的快速动画,当点击它时(按钮2)也将启动相同的动画。每当单击这些按钮之一以启动运行方法时,我该怎么办?

public void run() {

            if(isTom){

            repaint();
            revalidate();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {

            }
            panel.removeAll();
            panel.add(tomLabel1);
            repaint();
            revalidate();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
            }
            panel.add(tomLabel2);
            repaint();
            revalidate();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                }
            panel.add(tomLabel3);
            repaint();
            revalidate();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {

            }
            panel.add(tomLabel4);
            repaint();
            revalidate();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                }
            panel.add(tomLabel5);
            repaint();
            revalidate();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                }


            panel.removeAll();
            repaint();
            revalidate();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
            }

            }



public Game(){

        JFrame frame = new JFrame();
        Panel1 key = new Panel1();
        key.addKeyListener(key);
        frame.add(key);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        frame.setUndecorated(true);
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        new Game();

    }

    public class Panel1 extends JPanel implements KeyListener,Runnable{
    JButton button1 = new JButton("BUTTON1");
    JButton button2 = new JButton("BUTTON2");
    add(button1);add(button2);

        Thread t = new Thread(this); // This works, but i need it inside the actionListener.

         button1.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e){
                    System.out.println("button1");
                    Thread x = new Thread(j);//'j' is an JPanel1 object. I need something like this i guess
                    x.setName("Thread x");});

         button2.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e){
                    System.out.println("button2");
                    Thread y = new Thread(j);
                    y.setName("Thread y");
                                           });

public void run(){
     System.out.println(Thread.currentThread().getName());
}

【问题讨论】:

  • 不确定这里的问题是什么,您应该添加更多关于您正在尝试做什么的信息,例如,这些线程将要做什么。看起来您可能偏离了您正在尝试做的事情,因此提供该信息可能是最好的。
  • 围绕 Runnable 的单个实例创建线程将使线程同时执行 runnable。如果您不希望这样,请让面板类创建一个 Runnable 并通过 getter 将其返回
  • 记住,swing 是单线程的,不是线程安全的
  • 我也不确定我是否理解它,但也许你想要这个:Thread y = new Thread(this.Panel1); 这将在你的 Panel1 类的同一个实例中运行你的线程。

标签: java swing


【解决方案1】:

首先,Swing 不是线程安全的!这意味着您永远不应该从事件调度线程的上下文之外创建或修改 UI!

其次,Swing 是一个单线程环境,这意味着您永远不应该在 Event Dispatching Thread 的上下文中阻塞或执行长时间运行的代码,这将导致 UI 冻结,直到阻塞被移除。

你的概念是正确的,你的实现是错误的,你应该使用 Swing Timer 来代替。

不要删除和添加标签,而是使用单个标签并更改其属性(文本/图标等)

请参阅Concurrency in SwingHow to use Swing Timers 了解更多详情

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                try {
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException exp) {
                    exp.printStackTrace();
                }
            }
        });
    }

    public class TestPane extends JPanel {

        private JButton button1;
        private JButton button2;

        private SplashScreen splashScreen;

        public TestPane() throws IOException {
            button1 = new JButton("Button One");
            button2 = new JButton("Button Two");

            JPanel buttons = new JPanel();
            buttons.add(button1);
            buttons.add(button2);

            button1.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    splashScreen.run();
                }
            });

            button2.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    splashScreen.run();
                }
            });

            splashScreen = new SplashScreen();

            setLayout(new BorderLayout());
            add(splashScreen);
            add(buttons, BorderLayout.SOUTH);
        }

    }

    public static  class SplashScreen extends JPanel {

        protected static final int IMAGE_COUNT = 4;

        private JLabel label;
        private Timer timer;

        private int delta;
        private int count;
        private Icon[] icons;

        private Dimension preferredSize;

        public SplashScreen() throws IOException {
            String path = "/images/splash";
            String ext = ".png";
            icons = new Icon[IMAGE_COUNT];
            int maxWidth = 0;
            int maxHeight = 0;
            for (int index = 0; index < IMAGE_COUNT; index++) {
                String name = path + (index + 1) + ext;
                System.out.println(name);
                icons[index] = new ImageIcon(ImageIO.read(getClass().getResource(name)));
                maxWidth = Math.max(maxWidth, icons[index].getIconWidth());
                maxHeight = Math.max(maxHeight, icons[index].getIconHeight());
            }
            preferredSize = new Dimension(maxWidth, maxHeight);

            timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (count >= IMAGE_COUNT) {
                        count = IMAGE_COUNT - 2;
                        delta = -1;
                    } else if (count < 0) {
                        ((Timer)e.getSource()).stop();
                    } else {
                        label.setIcon(icons[count]);
                        count += delta;
                    }
                }
            });

            setLayout(new BorderLayout());
            label = new JLabel();
            add(label);
        }

        @Override
        public Dimension getPreferredSize() {
            return preferredSize;
        }

        public void run() {

            if (!timer.isRunning()) {

                delta = 1;
                count = 0;
                timer.start();

            }

        }

    }

}

【讨论】:

  • 我不能使用单个标签。我有 5 个图像,我想像这样显示:添加第 1 个,等待,添加第 2 个,等待,添加第 3 个等等,直到最后一个,但是每个图像仍然显示,同时仍然添加更多,然后删除所有它们和重新运行。所以它就像一个加载屏幕
  • 是的,您可以,您将图像放入一个数组中,然后使用JLabel#setIcon 更改单个图标
  • 是的,但是使用计时器,我无法获得与使用线程相同的效果。我的意思是 Thread.sleep()。我需要在我的计时器方法中延迟,而不是在执行之间
  • 垃圾,Timer 会定期(比如 100 毫秒)设置一个回调,您可以在其中决定要做什么和显示什么,这就像一个伪循环
  • 我添加了一个例子,播放4张图片,甚至回放,每张图片在屏幕上显示250毫秒,按照Timer的要求!
【解决方案2】:

使用您的 Panel1 类实例创建一个新的线程实例:

button1.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                System.out.println("button1");
                Thread x = new Thread(Panel1.this);
                x.start();
                x.setName("Thread x");});

使用新的 Thread 对象重复另一个按钮:

button2.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                System.out.println("button2");
                Thread y = new Thread(Panel1.this);
                y.start();
                y.setName("Thread y"); });

Panel1.this 指的是当前正在运行的 Panel1 类的实例,确保您的线程正在执行该实例的 run()。

【讨论】:

  • 而这两个面板与显示的那个有什么关系?
  • 我也试过了,但它说“Panel1 无法解析或不是字段”。
  • @MadProgrammer 两个面板?我只有 1 个面板(Panel1 类)
  • 对不起,应该是Panel1.this,已编辑答案
  • 那么,“Panel1.this”更具体是什么意思?它调用 Panel1 的实例?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
  • 2013-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-26
相关资源
最近更新 更多