I am re-writing some code to improve thread safety. I am trying to pass arrays as arguments rather than storing them in class variables. But an error is being thrown where a button in my gui needs to update/reload the contents of a panel in my gui.
It looks like I need to somehow pass these arrays into the button or into ActionListener, but I do not know how to do that. Since the problem is buried in many thousands of lines of irrelevant code, I have re-created the relevant aspects in the code sample below. The only other problem with the code below is that for some reason it it not making the button visible. But otherwise, the code below accurately recreates the error that is being thrown in my application. Note that the code prints a message when the pane is reloaded with data in the two arrays.
Can anyone show me how to change the code below so that it is able to pass the arrays as arguments when the button is clicked to refresh the panel’s contents?
The code is in three files as follows:
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 (THIS FILE CONTAINS THE LINE THAT THROWS THE ERROR MESSAGE IN 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);}
}
}
}
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);
}
}
Its difficult to understand what your trying to achieve with this code. As pointed out before the compile error you are getting is because you are using a variable that isn’t in scope.
As far as giving you action listener visibility to the variables with the way you have things laid out your only option is to make them instance variables in the JPanel.
However, I would consider not having JPanel implement actionListener. Instead create the listener for hRescaleButton as an anonymous inner class. This would better encapsulate your code and you wouldn’t need to check the source of the event in the handler.
See the code below.
By declaring the parameters on the addComponentsToPane method final then your anonymous inner class action listener will be able to access them.
With that said, Why do you assume passing the arrays as variables instead of storing them as instance variables will do anything to improve Thread Safety? It won’t. If you want to ensure Thread Safety you need to ensure the arrays can’t be accessed and modified concurrently. When you pass as an argument you are only copying object references the actual array isn’t copied so the code isn’t anymore thread safe.
If the arrays need to be modified after they are passed in then you need to synchronize access to the array using a common lock everywhere the array is accessed. However, I’d consider copying the array so you have your own copy that you know isn’t modified. Then you wouldn’t need any synchronization.