While working on a program, I made some of my fields static i.e. a JTextField for a E-Number. But now this field behaves not as expected, on some of my pages it appears, on some others it disappears.
Since I am not very experienced working with a lot of statics, there might be a concept I am not understanding.
I have created a very simplified but working example of my program (MCVE) if you want to test it.
It shows my overview page at first - the E-Number JTextField is missing.
If you click on the search button, it shows the tracking page - with the E-Number JTextField present.
Both pages contain the same workNumberPanel and I cant find a difference, that would explain the behaviour.
So why is the E-Number JTextField present on the overview page and missing on the tracking page? Any help / explanation is appreciated!
MainProgram.java
import java.awt.CardLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import net.miginfocom.swing.MigLayout;
public class MainProgram extends JFrame {
private static final long serialVersionUID = 1L;
public static JPanel centerPanel = new JPanel();
public static CardLayout contentCardsLayout = new CardLayout();
OverviewPage overviewPage = new OverviewPage();
TrackingPage trackingPage = new TrackingPage();
public void initialize() {
createCenterPanel();
}
private void createCenterPanel() {
centerPanel.setLayout(contentCardsLayout);
overviewPage.setName("overviewPage");
trackingPage.setName("trackingPage");
centerPanel.add(overviewPage, "overviewPage");
centerPanel.add(trackingPage, "trackingPage");
add(centerPanel, "growx, wrap");
}
public MainProgram() {
setBounds(300, 50, 1200, 900);
setLayout(new MigLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
MainProgram window = new MainProgram();
window.setVisible(true);
window.initialize();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
OverviewPage.java
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class OverviewPage extends JPanel {
WorkNumberPanel workNumberPanel = new WorkNumberPanel();
private static final long serialVersionUID = 1L;
public OverviewPage() {
setLayout(new MigLayout());
add(workNumberPanel, "wrap, growx");
}
}
TrackingPage.java
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class TrackingPage extends JPanel {
private static final long serialVersionUID = 1L;
WorkNumberPanel equipmentNumberPanel = new WorkNumberPanel();
public TrackingPage(){
setLayout(new MigLayout("", "grow, fill"));
add(equipmentNumberPanel, "wrap, growx");
}
}
WorkNumberPanel.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import net.miginfocom.swing.MigLayout;
public class WorkNumberPanel extends JPanel {
private static final long serialVersionUID = 1L;
private static final Integer TEXTFIELD_LENGTH = 20;
JPanel mainWorkNumberPanel = new JPanel();
JLabel lblWorkNumber = new JLabel("E-Nr: ");
JLabel lblN_Number = new JLabel("N-Nr.: ");
JLabel lblSNumber = new JLabel("W-Nr.: ");
public static JTextField txtWorkNumber = new JTextField(TEXTFIELD_LENGTH);
JTextField txtNNumber = new JTextField(TEXTFIELD_LENGTH);
JTextField txtSNumber = new JTextField(TEXTFIELD_LENGTH);
JButton btnSearchEntry = new JButton("Search");
public WorkNumberPanel() {
createEquipmentNumberPanel();
btnSearchEntry.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
MainProgram.contentCardsLayout.show(MainProgram.centerPanel, "trackingPage");
}
});
}
private void createEquipmentNumberPanel() {
setLayout(new MigLayout());
mainWorkNumberPanel.setLayout(new MigLayout("", "[][grow, fill][][grow, fill][][grow, fill][]"));
mainWorkNumberPanel.add(lblWorkNumber);
mainWorkNumberPanel.add(txtWorkNumber);
mainWorkNumberPanel.add(lblN_Number);
mainWorkNumberPanel.add(txtNNumber);
mainWorkNumberPanel.add(lblSNumber);
mainWorkNumberPanel.add(txtSNumber);
mainWorkNumberPanel.add(btnSearchEntry);
add(mainWorkNumberPanel, "push, span, growx");
}
}
Probably because when you create your "pages" with this code
OverviewPage overviewPage = new OverviewPage();
TrackingPage trackingPage = new TrackingPage();
the TrackingPage will be the last one to execute the following line
mainWorkNumberPanel.add(txtWorkNumber);
in private void createEquipmentNumberPanel(), and hence that Panel will "own" the JTextField. It only makes sense that a UI component can only be at one place at any given time, otherwise things would get very strange :)
Your statement
Both pages contain the same workNumberPanel and I cant find a difference, that would explain the behaviour.
is simply not true. You are creating a new instance of WorkNumberPanel in both OverViewPage and TrackingPage when you execute the following line
WorkNumberPanel equipmentNumberPanel = new WorkNumberPanel();
So my recommendation is that you find another way of implementing what you want without using a static JTextField (or any other UI component for that matter).
Here you instantiate a OverviewPage, then a TrackingPage .
OverviewPage overviewPage = new OverviewPage();
TrackingPage trackingPage = new TrackingPage();
Both of these classes instantiate a WorkNumberPanel .
WorkNumberPanel add the static JTextField (txtWorkNumber) to their display panel (mainWorkNumberPanel).
A single Component can't be added to several Container objects.
This is what happens to your textfield, since it is static and not an instance variable.
The last addition will win, so the textfield will appear in TrackingPage only, and not in OverviewPage anymore .
Just don't make it static.
First off you need to understand what a static field is. A static field is not related to a particular instance of an object. The field is related to the class itself.
There's quite a good explanation here and here.
Now with regards to your case. A JComponent can only be added to one panel at a time. Adding it to another will remove it from the first.
In your code you are creating multiple instances of 'WorkingNumberPanel'. When you do this you add the text fields to the panel, including the static text field txtWorkNumber. Since the field txtWorkNumber is static you are adding the same object to multiple components, which as I mentioned above will remove it from anywhere it was previously added.
One possible way of solving this would be to store the value from txtWorkNumber in a static variable and create a new instance (non-static) text field to add to the panel.
Related
The following example creates a JFrame with JButton, JTextField and JLabel.
When the button is pressed it increments the value in the text field and label.
This example also creates a 2nd JFrame that is a copy of the first.
The button, text field and label is copied as well.
The issue at hand is the button on the copied frame still updates the text field and label on the original. The 'why' is fairly obvious and is because the code makes specific reference to the text field and label.
Although this isn't written in the best manner but it is a great example of the scenario in which I am addressing.
The objective is, without a major rewrite, what would be the least invasive way to have the copied button action update the copied test field and label instead of the original?
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.JTextField;
class ButtonTextFieldLabel extends JFrame
{
JButton bnt1 = new JButton("B1");
JTextField tf1 = new JTextField("1");
JLabel lbl1 = new JLabel("100");
public ButtonTextFieldLabel()
{
super("Main Frame");
setLayout(null);
bnt1.setBounds(50,100,120,40);
tf1.setBounds(300,100, 80,40);
lbl1.setBounds(200,100,80,40);
bnt1.addActionListener(new ListenerHolder(this));
add(bnt1);
add(tf1);
add(lbl1);
setSize(500,500);
makeCopy(this);
setVisible(true);
}
private void makeCopy(ButtonTextFieldLabel originalObj)
{
JFrame copyFrame = new JFrame();
copyFrame.setTitle("Copy of " + originalObj.getTitle());
copyFrame.setSize(originalObj.getSize());
copyFrame.setLocation(originalObj.getX()+100, originalObj.getY()+100);
copyFrame.setLayout(null);
JButton copyBnt1 = new JButton();
copyBnt1.setBounds(originalObj.bnt1.getBounds());
copyBnt1.setLabel(originalObj.bnt1.getLabel());
copyFrame.add(copyBnt1);
for (ActionListener al : originalObj.bnt1.getActionListeners())
{
copyBnt1.addActionListener(al);
}
JTextField copyTf1 = new JTextField();
copyTf1.setBounds(originalObj.tf1.getBounds());
copyTf1.setText(originalObj.tf1.getText());
JLabel copyLbl1 = new JLabel();
copyLbl1.setBounds(originalObj.lbl1.getBounds());
copyLbl1.setText(originalObj.lbl1.getText());
copyFrame.add(copyBnt1);
copyFrame.add(copyTf1);
copyFrame.add(copyLbl1);
copyFrame.setVisible(true);
}
public void runThis()
{
tf1.setText( Integer.toString(Integer.parseInt(tf1.getText())+1) );
lbl1.setText( Integer.toString(Integer.parseInt(lbl1.getText())+1) );
}
}
class ListenerHolder implements ActionListener
{
ButtonTextFieldLabel ph;
public ListenerHolder(ButtonTextFieldLabel ph)
{
this.ph = ph;
}
#Override
public void actionPerformed(ActionEvent arg0)
{
ph.runThis();
}
}
public class TestBTL
{
public static void main(String[] args){
new ButtonTextFieldLabel();
}
}
You already know the reason for the problem -- you're copying the original ActionListener, complete with its reference to the original GUI components. The overall solution is not to copy the action listener but rather to create your GUI's to hold and maintain their own unique state. One solution is rather than try to copy components via kludge, to create a self-contained GUI object that holds and updates its own state. You can create multiple GUI's using a factory method if desired.
For example:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class TestBtl2 {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndDisplayFrame("Frame 1").setVisible(true);
createAndDisplayFrame("Frame 2").setVisible(true);
});
}
// Factory method
private static JFrame createAndDisplayFrame(String text) {
BtlPanel btlPanel = new BtlPanel();
JFrame frame = new JFrame(text);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(btlPanel);
frame.pack();
frame.setLocationByPlatform(true);
return frame;
}
}
class BtlPanel extends JPanel {
private int value = 0;
private JButton button1 = new JButton(new ButtonAction("Button 1"));
private JLabel label1 = new JLabel("00");
private JTextField textField1 = new JTextField("00");
public BtlPanel() {
textField1.setFocusable(false);
add(button1);
add(Box.createHorizontalStrut(20));
add(label1);
add(Box.createHorizontalStrut(20));
add(textField1);
setPreferredSize(new Dimension(300, 100));
}
public void incrementValue() {
value++;
String text = String.format("%02d", value);
label1.setText(text);
textField1.setText(text);
}
private class ButtonAction extends AbstractAction {
public ButtonAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
incrementValue();
}
}
}
Side Recommendations:
While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
Check out: The Use of Multiple JFrames, Good/Bad Practice?
I am a Beginner in Java. I have looked all over the place for an answer to my question, but could not find any, or they were to complex for me at this stage of my Java knowledge.
What Planning to do is to create a program on the way of my learning, it will be quite a bit of code and would like to keep things organized.
I have a class where I want to store the mainPanel, where then I would like to add other JPanels which are stored in other classes (on button click (not with a cardLayout)).
My code is probably full of errors, I hope you can help me.
Here is my main class:
import javax.swing.JFrame;
public class TestTool {
public static void main(String[] args){
Test1 frame = new Test1();
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Then I have another class where I want to store the mainPanel and load other panels from different classes:
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test1 extends JFrame {
public Test1(){
testPanel();
}
public void testPanel(){
setTitle("Test Tool");
TestPanel1 te = new TestPanel1();
JPanel mainPanel = new JPanel();
mainPanel.add(te.pan());
}
}
On the next class I have a different panel which I am then trying to load into the mainPanel:
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TestPanel1 {
private JPanel panel1;
public TestPanel1(){
JPanel panel1 = new JPanel();
JLabel label1 = new JLabel("panel 1");
panel1.add(label1);
JButton button1 = new JButton("button 1");
panel1.add(button1);
}
public JPanel pan(){
return panel1;
}
}
Is there anyway I can do it like this? or am I doing it completely wrong?
Thank you
I would suggest making the TestPanel class extend the JPanel class and in your constructor call the superconstructor and then do what you need.
As of late I've been developing a (very) small GUI application in Java. I'm extremely new to Swing and Java in general, but up until now I have been able to get everything to work the way I want it to. However, after cleaning up my code, when I run the program nothing but the border of the window appears. What am I doing wrong and how can I fix my code? Thanks ahead of time!
For the sake of saving space I've made Pastebin links to all of my classes (besides Main).
Main Class
package me.n3rdfall.ezserver.main;
public class Main {
public static GUI g = new GUI();
public static void main(String[] args) {
g.showWindow(800, 500);
}
}
GUI Class
http://pastebin.com/gDMipdp1
ButtonListener Class
http://pastebin.com/4XXm70AD
EDIT: It appears that calling removeAll() directly on 'frame' actually removed essential things other than what I had added. By calling removeAll() on getContentPane(), the issue was resolved.
Quick hack: Remove the removeAll() functions.
public void homePage() {
// frame.removeAll();
// mainpanel.removeAll();
// topbar.removeAll();
I'm not sure what you're trying to achieve, but that will at least show some items. If I were you I would rebuild this GUI by extending JFrame. It will make your code a little easier to read.
I also think what you are trying to achieve with the buttons is to switch layouts, you can do this in an easier way by using CardLayout
Example (has nothing to do with your code, but to demonstrate):
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example extends JFrame implements ActionListener {
private JButton leftButton;
private JButton rightButton;
private CardLayout cardLayout = new CardLayout();
JPanel cards = new JPanel(cardLayout);
final static String LEFTPANEL = "LEFTPANEL";
final static String RIGHTPANEL = "RIGHTPANEL";
JPanel card1;
JPanel card2;
public Example() {
JPanel topPanel = new JPanel();
addButtons(topPanel);
add(topPanel, BorderLayout.NORTH);
add(cards, BorderLayout.CENTER);
//Initiates the card panels
initCards();
setTitle("My Window");
setSize(300, 300);
setLocationRelativeTo(null);
setVisible(true);
}
private void initCards() {
card1 = new JPanel();
card2 = new JPanel();
card1.setBackground(Color.black);
card2.setBackground(Color.red);
cards.add(card1, LEFTPANEL);
cards.add(card2, RIGHTPANEL);
}
private void addButtons(Container con) {
leftButton = new JButton("Left Button");
leftButton.addActionListener(this);
rightButton = new JButton("Right Button");
rightButton.addActionListener(this);
con.add(leftButton, BorderLayout.WEST);
con.add(rightButton, BorderLayout.EAST);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(leftButton)) {
//Change cardlayout
cardLayout.show(cards, LEFTPANEL);
} else if(e.getSource().equals(rightButton)) {
//Change cardlayout
cardLayout.show(cards, RIGHTPANEL);
}
}
public static void main(String[] args) {
new Example();
}
}
In trying to run my basic GUI application from Main I have somehow managed to first make the GUI show up (but it was smaller than what I set the size to within the code and not showing any components) then magically (after adding pack() and setlocationrelativeto(null)) it does not pop up at all. I am using Netbeans (if that helps), in Main it gives me a tooltip that my GUI is "never used" so it runs and outputs "Finished building" rather than continuing to run and showing the GUI. I have provided 2 sets of code (1) main method and (2) GUI class. Please let me know if I'm being confusing as of course it makes sense in my head but may be communicated badly. I have not included the complete code but if it is necessary please let me know and I will do so.
package logTime;
public class LogInTime {
public static void main(String[] args) {
try{
LogAppFrame app = new LogAppFrame(); //IDE gives tooltip that app is unused
}
catch(Exception e){
System.err.println("\n\nError Occurred: "); //am going to print message later
}
}
}
The actual GUI code - does not include imports or actionlisteners:
public void LogAppFrame(){
frame = new JFrame("Time Log Application");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cl = new CardLayout();
frame.getContentPane().setLayout(cl);
//frame.setLayout(cl);
frame.setSize(new Dimension(375,385));
logNewFrame = new JPanel();
logNewFrame.setLayout(new GridLayout(5,1));
logNewFrame.setBorder(new EmptyBorder(20,20,20,20));
frame.getContentPane().add(logNewFrame, "logNewFrame");
historyFrame = new JPanel();
historyFrame.setLayout(new GridLayout(2,1)); //given 0 for rows to add numerous rows
historyFrame.setBorder(new EmptyBorder(20,20,20,20));
frame.getContentPane().add(historyFrame, "historyFrame");
.
.
.
//added lots of components but will not include code as there is no error within this portion of code - i used to have both Main and LogAppFrame class all together and my GUI worked and showed components but I felt it may be best practice not to do it this way and cardlayout wasnt working
.
.
.
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Adding SSCE below:
package logTime;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.*;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class LogAppFrame{
private static JFrame frame;
private static CardLayout cl;
//menu option components
/**
* Help option: How To Use/Read Me - explains how to use it 8 Hour Day -
* shows the arrival and leave time based on lunch type
*/
/**
* Log New Date option: shows screen to input new values into date
*/
/**
* View Past Dates option: shows all past dates since forever - may add
* month tabs later
*/
/**
* Edit Past Date option: doesnt exist yet but will be added to View Past
* menu option as side button to edit any old date
*/
private static JMenuBar menuBar = new JMenuBar();
private static JMenu help;
private static JMenuItem logNewDate;
private static JMenuItem viewPastDates;
private static JMenuItem workDay;
private static JMenuItem about;
//Log New Date components
/**
* 4 labels, 1 button, 1 calendar, 2 dropdowns, 2 textfields, 5x2 gridlayout
*/
private static JLabel dateToday;
private static JLabel timeInToday;
private static JLabel timeOutToday;
private static JLabel lunchTypeToday;
private static JLabel timeColon1;
private static JLabel timeColon2;
private static JButton saveButton;
private static JComboBox month;
private static JComboBox day;
private static JComboBox year;
private static JComboBox amPm1;
private static JComboBox amPm2;
private static JComboBox hrTimeIn;
private static JComboBox hrTimeOut;
private static JComboBox minTimeIn;
private static JComboBox minTimeOut;
private static JPanel dateTodayPanel;
private static JPanel timeInPanel;
private static JPanel timeOutPanel;
private static JPanel lunchTypePanel;
private static JPanel saveButtonPanel;
private static JComboBox lunchType;
//View Past Dates components
/**
* 4x*infinitiy* gridlayout or have a flowlayout, 4 labels
*/
private static JLabel pastDates;
private static JLabel pastTimeIns;
private static JLabel pastTimeOuts;
private static JLabel pastLunchTypes;
private static JPanel headers; //holds header labels
private static JPanel oldLogs; //will hold all past log panels
//Frames to hold the logNew and viewOld views
private static JPanel logNewFrame;
private static JPanel historyFrame;
public void LogAppFrame(){
frame = new JFrame("Time Log Application");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cl = new CardLayout();
frame.getContentPane().setLayout(cl);
//frame.setLayout(cl);
frame.setSize(new Dimension(375,385));
logNewFrame = new JPanel();
logNewFrame.setLayout(new GridLayout(5,1));
logNewFrame.setBorder(new EmptyBorder(20,20,20,20));
frame.getContentPane().add(logNewFrame, "logNewFrame");
historyFrame = new JPanel();
historyFrame.setLayout(new GridLayout(2,1)); //given 0 for rows to add numerous rows
historyFrame.setBorder(new EmptyBorder(20,20,20,20));
frame.getContentPane().add(historyFrame, "historyFrame");
//Menu components
menuBar = new JMenuBar();
help = new JMenu("Help");
logNewDate = new JMenuItem("Log New Date");
viewPastDates = new JMenuItem("View Past Dates");
workDay = new JMenuItem("8 Hour Day");
about = new JMenuItem("How To ...");
help.add(workDay);
help.add(about);
menuBar.add(logNewDate);
menuBar.add(viewPastDates);
menuBar.add(help);
frame.setJMenuBar(menuBar);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
You have written void before the thing that ought to be a constructor. So it is mistaken as a method by the compiler which never gets called. Unfortunately the compiler generates a no-op constructor for you in such a case. Just remove the void keyword.
And by the way, remove all the nasty static keywords from the fields. That hurts.
If you want to write simple gui applications you should check WindowBuilder. It's drag and drop gui for java that actually works.
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.
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");
}
}
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.
First analysis shows the following problems:
Your error is
$> 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
And those variables, myDBL and mySTR don't seem to be part of your object.
I notice that you pass them in as constructor parameters to Toolbar, but you ever actually save them in your Toolbar class, so you can't ever get them back out.
I think you need to take a step back, identify what your objectives are, and go from there.
Looks like you are missing a revalidate, that will cause the added components to not appear. Bad API design, but true. See the API docs for Container.add.
Also you should add the standard boilerplate for starting a Swing front end from main:
public static void main(final String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
runEDT();
}
});
}