Ошибка ActionListener при передаче массивов в качестве аргументов для безопасности потока - PullRequest
0 голосов
/ 23 ноября 2011

Я переписываю некоторый код для повышения безопасности потоков. Я пытаюсь передать массивы в качестве аргументов, а не хранить их в переменных класса. Но возникает ошибка, когда в моем графическом интерфейсе требуется кнопка для обновления / перезагрузки содержимого панели в моем графическом интерфейсе.

Похоже, мне нужно как-то передать эти массивы в кнопку или в ActionListener, но я не знаю, как это сделать. Поскольку проблема скрыта во многих тысячах строк неактуального кода, я заново создал соответствующие аспекты в примере кода ниже. Единственная другая проблема с кодом ниже состоит в том, что по какой-то причине она не делает кнопку видимой. Но в остальном приведенный ниже код точно воссоздает ошибку, возникающую в моем приложении. Обратите внимание, что код печатает сообщение, когда панель перезагружается с данными в двух массивах.

Может кто-нибудь показать мне, как изменить приведенный ниже код, чтобы он мог передавать массивы в качестве аргументов при нажатии кнопки для обновления содержимого панели?

Код в трех файлах выглядит следующим образом:

Parent.java

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Panel;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JTabbedPane;

public class Parent extends JFrame{
private static final long serialVersionUID = 1L;
JLayeredPane desktop;
JInternalFrame internalFrame;

public Parent() {
    super("title goes here");
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setPreferredSize(new Dimension(800, 400));
    double[] myDBL = {2.3,5.4,6.5,7.8,2.4,6.4,9.0,5.3,8.1};
    String[] mySTR = {"ko","lp","dk"};
    Panel p = new Panel();
    this.add(p, BorderLayout.SOUTH);
    desktop = new JDesktopPane();
    this.add(desktop, BorderLayout.CENTER);
    this.pack();
    this.setSize(new Dimension(800, 600));
    this.setLocationRelativeTo(null);
        int ifWidth = 600;
        int ifHeight = 300;
        internalFrame = new JInternalFrame("title", true, true, true, true);
        // create jtabbed pane
        JTabbedPane jtp = createTabbedPane(myDBL,mySTR);
        internalFrame.add(jtp);
        desktop.add(internalFrame);
        internalFrame.pack();
        internalFrame.setSize(new Dimension(ifWidth,ifHeight));
        internalFrame.setVisible(true);
}
private JTabbedPane createTabbedPane(double[] myDBL, String[] mySTR) {
    JTabbedPane jtp = new JTabbedPane();
    jtp.setMinimumSize(new Dimension(600,300));
    createTab(jtp, "Data",myDBL,mySTR);
    return jtp;
}
private void createTab(JTabbedPane jtp, String s,double[] myDBL, String[] mySTR) {
    if(s=="Data"){
        PanelGUI myTimeSeriesGUI = new PanelGUI(myDBL,mySTR);
        jtp.add(s,myTimeSeriesGUI);
    }
    else{jtp.add(s, new JLabel("TabbedPane " + s, JLabel.CENTER));}
}
public static void main(String args[]) {
    Parent myParentFrame = new Parent();
    myParentFrame.setVisible(true);
}
}

PanelGUI.java (В ЭТОМ ФАЙЛЕ СОДЕРЖИТСЯ ЛИНИЯ, КОТОРЫЕ ВЫБИРАЕТ СООБЩЕНИЕ ОБ ОШИБКЕ ПРИ ЗАТМЕНИИ.)

import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class PanelGUI extends JPanel implements ActionListener{
private static final long serialVersionUID = 1L;
public int visiblePoints;
public int newStartingPoint;
ToolBar myToolBar;
int frameWidth = 600;
int frameHeight = 300;

public PanelGUI(double[] myDBL, String[] mySTR){
    newStartingPoint = 0;
    visiblePoints = 5000;
    addComponentsToPane(this, myDBL,mySTR);
}
public void addComponentsToPane(Container pane, double[] myDBL, String[] mySTR) {
    pane.removeAll();
    myToolBar=new ToolBar(myDBL,mySTR);
    pane.add(myToolBar);
    myToolBar.hRescaleButton.addActionListener(this);
    System.out.println("pane reloaded successfully");
}
public void actionPerformed(ActionEvent ae) {
    if(ae.getSource()==myToolBar.hRescaleButton){
        String str = JOptionPane.showInputDialog(null, "Number of milliseconds shown in window : ", "Horizontal Rescale", 1);
        if(str != null) {
            int numPoints = Integer.parseInt(str);
            JOptionPane.showMessageDialog(null, "You entered: "+numPoints+"ms = "+(numPoints/1000)+"sec.", "Horizontal Rescale", 1);
            this.removeAll();
            visiblePoints = numPoints;
            frameWidth = this.getWidth();
            frameHeight = this.getHeight();
            setSize(frameWidth,frameHeight);
            addComponentsToPane(this,myDBL,mySTR);//THIS IS WHERE THE ERROR IS
            setSize(frameWidth,frameHeight);
        }
        else{JOptionPane.showMessageDialog(null, "You pressed cancel button.","Horizontal Rescale", 1);}
    }
}
}

ToolBar.java

import javax.swing.JToolBar;
import javax.swing.JButton;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Dimension;

public class ToolBar extends JPanel {
private static final long serialVersionUID = -2749251105543480474L;
static final private String RESET_HSCALE = "HorizontalRescale";
JButton hRescaleButton;

public ToolBar(double[] myDBL, String[] mySTR) {
    //Create the toolbar.
    JToolBar toolBar = new JToolBar();
    addButtons(toolBar);
    toolBar.setFloatable(false);
    toolBar.setRollover(true);
    //Lay out the main panel.
    setPreferredSize(new Dimension(this.getWidth(), 40));
    add(toolBar, BorderLayout.PAGE_START);
}
protected void addButtons(JToolBar toolBar) {
    hRescaleButton = new JButton("Reset Horizontal Scale");
    hRescaleButton.setActionCommand(RESET_HSCALE);
    hRescaleButton.setToolTipText("Reset horizontal scale.");
    toolBar.add(hRescaleButton);
}
}

Ответы [ 3 ]

1 голос
/ 23 ноября 2011

Трудно понять, что вы пытаетесь достичь с помощью этого кода. Как указывалось до ошибки компиляции, вы получаете, потому что вы используете переменную, которая не находится в области видимости.

Поскольку вы предоставляете слушателю действия видимость переменных с тем, как у вас все устроено, ваша единственная возможность - сделать их переменными экземпляра в JPanel.

Однако я бы не подумал, чтобы JPanel реализовывал actionListener. Вместо этого создайте слушатель для hRescaleButton как анонимный внутренний класс. Это лучше инкапсулирует ваш код, и вам не нужно будет проверять источник события в обработчике.

См. Код ниже.

Объявляя параметры в методе addComponentsToPane final, ваш анонимный слушатель действия внутреннего класса сможет получить к ним доступ.

import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class PanelGUI extends JPanel {
  private static final long serialVersionUID = 1L;
  public int visiblePoints;
  public int newStartingPoint;
  ToolBar myToolBar;
  int frameWidth = 600;
  int frameHeight = 300;

public PanelGUI(double[] myDBL, String[] mySTR){
    newStartingPoint = 0;
    visiblePoints = 5000;
    addComponentsToPane(this, myDBL,mySTR);
}

public void addComponentsToPane(Container pane, final double[] myDBL, final String[] mySTR) {
    pane.removeAll();
    myToolBar=new ToolBar(myDBL,mySTR);
    pane.add(myToolBar);
    myToolBar.hRescaleButton.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent ae) {

            String str = JOptionPane.showInputDialog(null, "Number of milliseconds shown in window : ", "Horizontal Rescale", 1);
            if(str != null) {
                int numPoints = Integer.parseInt(str);
                JOptionPane.showMessageDialog(null, "You entered: "+numPoints+"ms = "+(numPoints/1000)+"sec.", "Horizontal Rescale", 1);
                this.removeAll();
                visiblePoints = numPoints;
                frameWidth = this.getWidth();
                frameHeight = this.getHeight();
                setSize(frameWidth,frameHeight);
                addComponentsToPane(this,myDBL,mySTR);//THIS IS WHERE THE ERROR IS
                setSize(frameWidth,frameHeight);
              }
              else{
                  JOptionPane.showMessageDialog(null, "You pressed cancel button.","Horizontal Rescale", 1);
              }
      }});
      System.out.println("pane reloaded successfully");
}
}

С учетом сказанного: почему вы предполагаете, что передача массивов в качестве переменных вместо хранения их в качестве переменных экземпляра будет способствовать улучшению безопасности потоков? Не будет Если вы хотите обеспечить безопасность потоков, вы должны гарантировать, что массивы не могут быть доступны и изменены одновременно. Когда вы передаете в качестве аргумента, вы только копируете объектные ссылки, реальный массив не копируется, поэтому код больше не является поточно-ориентированным.

Если массивы необходимо модифицировать после их передачи, вам необходимо синхронизировать доступ к массиву, используя общую блокировку везде, где осуществляется доступ к массиву. Однако я хотел бы скопировать массив, чтобы у вас была собственная копия, которая, как вы знаете, не изменена. Тогда вам не потребуется синхронизация.

0 голосов
/ 23 ноября 2011

Похоже, вам не хватает revalidate, из-за которого добавленные компоненты не отображаются.Плохой дизайн API, но это правда.См. Документацию по API для Container.add .

Также вы должны добавить стандартный шаблон для запуска внешнего интерфейса Swing с основного:

public static void main(final String[] args) {
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            runEDT();
        }
    });
}
0 голосов
/ 23 ноября 2011

Первый анализ показывает следующие проблемы:

Ваша ошибка

$> javac Parent.java
.\PanelGUI.java:38: cannot find symbol
symbol  : variable myDBL
location: class PanelGUI
            addComponentsToPane(this,myDBL,mySTR);//THIS IS WHERE THE ERROR IS
                                     ^
.\PanelGUI.java:38: cannot find symbol
symbol  : variable mySTR
location: class PanelGUI
            addComponentsToPane(this,myDBL,mySTR);//THIS IS WHERE THE ERROR IS
                                           ^
2 errors

И эти переменные, myDBL и mySTR, похоже, не являются частью вашего объекта.

Я заметил, что вы передаете их в качестве параметров конструктора на панель инструментов, но вы фактически сохраняете их в своем классе панели инструментов, поэтому вы никогда не сможете вернуть их обратно.

Я думаю, вам нужно сделать шаг назад, определить свои цели и пойти дальше.

...