java - 将数组作为线程安全参数传递时出现 ActionListener 错误

标签 java arrays swing thread-safety actionlistener

我正在重写一些代码以提高线程安全性。我试图将数组作为参数传递,而不是将它们存储在类变量中。但是,当我的 gui 中的按钮需要更新/重新加载我的 gui 中的面板内容时,会引发错误。

看起来我需要以某种方式将这些数组传递到按钮或 ActionListener 中,但我不知道该怎么做。由于问题隐藏在数千行不相关的代码中,因此我在下面的代码示例中重新创建了相关方面。下面的代码唯一的另一个问题是,由于某种原因,它没有使按钮可见。但除此之外,下面的代码准确地重新创建了我的应用程序中抛出的错误。请注意,当 Pane 重新加载两个数组中的数据时,代码会打印一条消息。

谁能告诉我如何更改下面的代码,以便在单击按钮刷新面板内容时能够将数组作为参数传递?

代码位于三个文件中,如下所示:

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 (此文件包含在 ECLIPSE 中抛出错误消息的行。)

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);}
    }
}
}

工具栏.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);
}
}

最佳答案

很难理解你想用这段代码实现什么目的。正如之前指出的,您收到的编译错误是因为您使用的变量不在范围内。

只要按照您布置事物的方式为您提供操作监听器对变量的可见性,您唯一的选择就是将它们设置为 JPanel 中的实例变量。

但是,我会考虑不让 JPanel 实现 actionListener。相反,为 hRescaleButton 创建监听器作为匿名内部类。这可以更好地封装您的代码,并且您无需在处理程序中检查事件源。

请参阅下面的代码。

通过在 addComponentsToPane 方法上声明最终参数,您的匿名内部类操作监听器将能够访问它们。

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");
}
}

话虽如此,为什么您认为将数组作为变量传递而不是将它们存储为实例变量将有助于提高线程安全性?不会的。如果要确保线程安全,则需要确保不能同时访问和修改数组。当您作为参数传递时,您只是复制对象引用,而不会复制实际的数组,因此代码不再是线程安全的。

如果数组在传入后需要修改,那么您需要在访问数组的各处使用公共(public)锁来同步对数组的访问。但是,我会考虑复制该数组,以便您拥有自己的副本,并且您知道该副本不会被修改。那么您就不需要任何同步。

关于java - 将数组作为线程安全参数传递时出现 ActionListener 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8236021/

相关文章:

java - 字符串无法转换为字符,如何解决?

python - 从 Python 列表中的每个元素中删除最后一个字符

c - 为什么当 N 越界时 &a[N] 不调用 UB?

java - 使用 Maven 分发可以单独跟踪每个依赖项的 swing 应用程序

java - 在java中将字符串解析为日期

java - 字符串比较逻辑未按预期工作

javascript - 判断数组中的某个元素是否为字符串

java - 装饰 JOptionPane.showMessageDialog,如无边框

java - 与 JLayeredPane 后面的 JPanel 交互

java - 将 UTC 时间戳转换为任何时区