Java вторая переменная отклоняет первую - PullRequest
0 голосов
/ 10 февраля 2020

Что мне нужно сделать, так это сделать GUI, чтобы при нажатии на button он начинал прогрессировать с threads; однако мы должны сделать это с внутренним классом, который реализует Runnable interface, а внутри конструктора для этого класса он принимает String и JProgressBar объект. Затем в главном конструкторе мы должны создать 2 JProgressBar объектов и затем создать 2 из объектов класса Inner, используя эти JProgressBars.

Только мой второй JProgressBar обновляется с помощью thread , Я знаю, что мой второй JProgressBar в основном перекрывает мой первый, но я не знаю, как бы я go исправил это, потому что если я попытаюсь изменить конструктор внутреннего класса, установив 2 JProgressBar атрибутов, равных параметр конструктора, то первый JProgessBar просто полностью исчезает из GUI. Вот мой код, спасибо всем, кто может помочь.

    import java.awt.*;
    import javax.swing.*;
    import java.awt.event.*;

    public class Lab4Part2 {
    //Attributes
    private JFrame frame;
    private String progress;
    private JProgressBar jpb;

    //Constructor
    public Lab4Part2() {
      //Create frame with specified grid layout
      frame = new JFrame();
      GridLayout grid = new GridLayout(0,1);
      frame.setLayout(grid);
      JButton jbClick = new JButton("Let's start this show");
      frame.add(jbClick);

      //Add in JProgressBars and create Inner Class objects with them
      JProgressBar jpb1 = new JProgressBar();
      JProgressBar jpb2 = new JProgressBar();
      InnerProgress bar1 = new InnerProgress("Progress 1: ", jpb1);
      InnerProgress bar2 = new InnerProgress("Progress 2: ", jpb2);

      //Anonymous class for the button's action listener
      jbClick.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            Thread t1 = new Thread(bar1);
            Thread t2 = new Thread(bar2);
            t1.start();
            t2.start();
         }
      });

      //Adds inner object to frame
      frame.add(bar1);
      frame.add(bar2);

      //Packing and stuff
      frame.pack();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
    }

      //Inner class
      class InnerProgress extends JPanel implements Runnable {

      //Constructor
      public InnerProgress(String pbar, JProgressBar jpBar) {
         jpBar.setMinimum(0);
         jpBar.setMaximum(80);
         jpBar.setStringPainted(true);
         progress = pbar;
         jpb = jpBar;
         JLabel label = new JLabel(pbar);
         add(label);
         add(jpBar);
      }

      //Thread action
      public void run() {
         System.out.println("We are running " + Thread.currentThread().getName());
         for(int i = 1; i<= 80; i++) {
            try {
               Thread.currentThread().sleep((long)Math.random()*100);
               jpb.setValue(i);
            }
            catch(InterruptedException ie) {
               System.out.println(ie);
            }
         }
         System.out.println("Thread name: " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
      }
     }

      //Main
      public static void main(String[] args) {
      new Lab4Part2();
     }

    }

1 Ответ

1 голос
/ 10 февраля 2020

Ваш внутренний класс должен поддерживать свою собственную ссылку на JProgressBar, что он передан.

Просто возьмите ...

private JProgressBar jpb;

и переместите его в свой внутренний класс

class InnerProgress extends JPanel implements Runnable {

    private JProgressBar jpb;
    //...

Итак, две другие проблемы

Во-первых, (long)Math.random()*100 приводит к тому, что результат Math.random() будет иметь значение int, что приведет к 0.

Вам нужно привести результат операции, например ...

Thread.currentThread().sleep((int)(Math.random() * 500));

(примечание: я сделал 500 для моего тестирования)

Два, Swing не безопасен для потоков. Это означает, что вы не должны обновлять пользовательский интерфейс вне контекста потока диспетчеризации событий.

Итак, вместо ...

jpb.setValue(i);

я написал новый метод, который будет обновлять соответственно, пользовательский интерфейс

protected void updateProgress(int value) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            InnerProgress.this.jpb.setValue(value);
        }
    });
}

(Короче говоря, из-за этого возникают проблемы со ссылками на переменные внутри анонимного контекста)

Затем просто вызывается с помощью updateProgress(i);

Пример запуска ...

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;

public class Lab4Part2 {
//Attributes

    private JFrame frame;
    private String progress;

//Constructor
    public Lab4Part2() {
        //Create frame with specified grid layout
        frame = new JFrame();
        GridLayout grid = new GridLayout(0, 1);
        frame.setLayout(grid);
        JButton jbClick = new JButton("Let's start this show");
        frame.add(jbClick);

        //Add in JProgressBars and create Inner Class objects with them
        JProgressBar jpb1 = new JProgressBar();
        JProgressBar jpb2 = new JProgressBar();
        InnerProgress bar1 = new InnerProgress("Progress 1: ", jpb1);
        InnerProgress bar2 = new InnerProgress("Progress 2: ", jpb2);

        //Anonymous class for the button's action listener
        jbClick.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                Thread t1 = new Thread(bar1);
                Thread t2 = new Thread(bar2);
                t1.start();
                t2.start();
            }
        });

        //Adds inner object to frame
        frame.add(bar1);
        frame.add(bar2);

        //Packing and stuff
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    //Inner class
    class InnerProgress extends JPanel implements Runnable {

        private JProgressBar jpb;

        //Constructor
        public InnerProgress(String pbar, JProgressBar jpBar) {
            jpBar.setMinimum(0);
            jpBar.setMaximum(80);
            jpBar.setStringPainted(true);
            progress = pbar;
            jpb = jpBar;
            JLabel label = new JLabel(pbar);
            add(label);
            add(jpBar);
        }

        //Thread action
        public void run() {
            System.out.println("We are running " + Thread.currentThread().getName());
            for (int i = 1; i <= 80; i++) {
                try {
                    Thread.currentThread().sleep((int)(Math.random() * 500));
                    updateProgress(i);
                } catch (InterruptedException ie) {
                    System.out.println(ie);
                }
            }
            System.out.println("Thread name: " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
        }

    protected void updateProgress(int value) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                InnerProgress.this.jpb.setValue(value);
            }
        });
    }
    }

    //Main
    public static void main(String[] args) {
        new Lab4Part2();
    }

}
...