How can I get my JAVA Method-Chaining to work? - java

I am trying to do some simple method chaining but always have the error "cannot find symbol" part way through.
e.g.:
public JButton[] getSignOnButtons() {
return InitialFrame.getInitialPanel().getSignOnButtons();
}
I am implementing the MVC model, in the View Package I have 4 classes: View, InitialFrame, InitialPanel, NorthPanel. For my Controller to communicate with the View package, I always go through the View Class.
My Controller Class needs to access attributes of View's classes, what's the best way?
I "cheated" it previously by making all the View classes' attributes public so I could just create a 'get' method from view
e.g.
return InitialFrame.InitialPanel.Buttons;
Thanks for any help.
The error just says "cannot not find symbol" is each case.
**EDITED from this point down......
This is the whole View Package:
public class View {
InitialFrame initialFrame;
public View(){
initialFrame = new InitialFrame();
}
public JFrame getInitialFrame() {
return initialFrame;
}
public InitialPanel getInitialPanel() {
return InitialFrame.getInitialPanel();
}
public JButton[] getSignOnButtons() {
return initialFrame.getInitialPanel().getSignOnButtons();
}
}
This is the InitialFrame Class:
public final class InitialFrame extends JFrame {
private final InitialPanel initialPanel;
public InitialFrame() {
super("Welcome to the Sign-on Screen");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(700, 700);
this.setLayout(new GridLayout(1, 1));
initialPanel = new InitialPanel();
this.add(initialPanel);
//this.pack();
this.setLocationRelativeTo(null);
this.validate();
this.repaint();
this.setVisible(true);
JButton[] test = initialPanel.getSignOnButtons();
String newStr = initialPanel.getNorthPanel().getTest(); //Call to getTest
}
public InitialPanel getInitialPanel() {
return initialPanel;
}
}
//InitialPanel ___________
class InitialPanel extends JPanel{
private BorderLayout InitialPanelLayout;
private JButton[] signOnButtons;
private NorthPanel northPanel;
private JPanel southPanel;
private JPanel leftPanel;
private JPanel rightPanel;
private JPanel centerPanel;
private JLabel userNameLabel;
private JTextField userNameTextField;
public InitialPanel() {
this.setSize(600, 600);
InitialPanelLayout = new BorderLayout();
this.setLayout(InitialPanelLayout);
this.createPanels();
this.formatCenterPanel();
setVisible(true);
this.validate();
this.repaint();
}
/**
* Method is to create panels for all the Border Layout of initial Panel
* #param none
*/
private void createPanels() {
//Graphics comp2D = new Graphics();
//comp2D.drawString("Free the bound periodicals", 22, 100);
northPanel = new NorthPanel();
northPanel.setSize(600, 200);
this.add(northPanel, "North");
southPanel = new JPanel();
this.add(southPanel, "South");
leftPanel = new JPanel();
this.add(leftPanel, BEFORE_LINE_BEGINS);
rightPanel = new JPanel();
this.add(rightPanel, AFTER_LINE_ENDS);
centerPanel = new JPanel();
this.add(centerPanel, "Center");
}
/**
* Method is to format the center panel on the opening window.
* It uses 4 row grid layout, top row is a container with Label and TextField.
* #param none
*/
private void formatCenterPanel() {
centerPanel.setLayout(new GridLayout(5, 1));
Container userName = new Container();
userName.setLayout(new GridLayout(1, 2));
userNameLabel = new JLabel("UserName: ");
userName.add(userNameLabel);
userNameTextField = new JTextField(30);
userName.add(userNameTextField);
centerPanel.add(userName);
signOnButtons = new JButton[3];
signOnButtons[0] = new JButton("Sign-On");
signOnButtons[1] = new JButton("Register");
signOnButtons[2] = new JButton("Exit");
for (JButton butt: signOnButtons) {
centerPanel.add(butt);
}
centerPanel.validate();
centerPanel.repaint();
}
public JButton[] getSignOnButtons() {
return signOnButtons;
}
public JTextField getUserNameTextField() {
return userNameTextField;
}
public NorthPanel getNorthPanel() {
return northPanel;
}
}
ALL updated now...
Only one error remains: "non-static method getInitialPanel() cannot be referenced from a static context"
in View Class
public InitialPanel getInitialPanel() {
return InitialFrame.getInitialPanel();
}
Final Edit:
The main solution was to use the 'this' keyword.
After that, I could use Controller to chain 3 or more methods to retrieve attributes buried in the View Package.
for example, in the View Class:
public JButton[] getSignOnButtons() {
return this.initialFrame.getInitialPanel().getSignOnButtons();
}
**EDIT 12/25/2018
the this.keyword does not solve this every time. It is still a tricky operation.
Sometimes I just allowed NetBeans to create the method itself because it says method not found even though it is named exactly the same.

Method chaining works from left to right in way that value returned by left method must have right method implemented in the class;
for example;
" Hello ".substring(1).trim()
Notice that here substring(1) is returning String value, which has also trim() method implemented in its (String) class.
In your case;
return InitialFrame.getInitialPanel().getSignOnButtons();
you are returning Initialframe from getInitialPlane() method, but there is not implementation of getSignOnButtons() in InitialFrame class. That's why JVM is complaining.

There is no method getSignOnButtons() in JPanel. Perhaps it's in InitialPanel? if that is the case, the return type of InitialFrame.getInitialPanel() should be InitialPanel instead of JPanel.

This is happening because you are trying to execute a method which is not present in JFrame class. When you are declaring this JFrame InitialFrame;, at compile time Java will check whether the method exists or not in JFrame class. Since it is not there in JFrame, you looks to be getting "cannot not find symbol" error.
Also, try to follow code standards - field names should be in lower camel case i.e. intialFrame.
Try below code (I have not compiled it though) -
public class View {
private InitialFrame initialFrame;
public View(){
initialFrame = new InitialFrame();
}
public JFrame getInitialFrame() {
return this.initialFrame;
}
public JPanel getInitialPanel() {
return this.initialFrame.getInitialPanel();
}
public JButton[] getSignOnButtons() {
return this.initialFrame.getInitialPanel().getSignOnButtons();
}
}
public final class InitialFrame extends JFrame {
private InitialPanel initialPanel;
public InitialFrame() {
super("Welcome to the Sign-on Screen");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(700, 700);
this.setLayout(new GridLayout(1, 1));
initialPanel = new InitialPanel();
this.add(initialPanel);
//this.pack();
this.setLocationRelativeTo(null);
this.validate();
this.repaint();
this.setVisible(true);
JButton[] test = initialPanel.getSignOnButtons();
String new = initialPanel.getNorthPanel().getTest();
}
public JPanel getInitialPanel() {
return this.initialPanel;
}
}
I assume you have another InitialPanel class which is extending JPanel and having getSignOnButtons() method defined in it.

Related

Dynamically add jcheckbox in jpanel

I have to add dynamically jcheckboxes in a panel when the user write something into a form. That's my code
Main
public class EmptyFrame extends JFrame{
private static final long serialVersionUID = 1L;
/*top panels*/
//to add technicians
private JButton newTechnician;
private NewTechForm ntForm;
private JPanel panelForm;
private JPanel panelChekBoxes;
TechCheckBoxGroup techniciansGroup;
private List<String> technicians;
//main container
private Container pane = getContentPane();
//components
GroupLayout gl = new GroupLayout(pane);
EmptyFrame(){
preinit();
init();
}
private void preinit(){
panelChekBoxes=new JPanel();
panelForm=new JPanel();
techniciansGroup=new TechCheckBoxGroup(panelChekBoxes);
}
private void init(){
/*top options*/
ntForm=new NewTechForm(panelForm);
newTechnician=new JButton("Add technician");
newTechnician.addActionListener(
new AddTechnicianAction(techniciansGroup,ntForm)
);
ntForm.getPanel().add(newTechnician);
/*end top options*/
for(String technic : technicians){
techniciansGroup.addCheckBoxes(
new JCheckBox(technic));
}
createWindowLayout(
new JLabel("Technicians"),
techniciansGroup.getCheckBoxes(),
ntForm.getPanel());
}
public void createWindowLayout(JComponent... arg) {
pane = getContentPane();
gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createParallelGroup()
.addGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addComponent(arg[1])
.addComponent(arg[2])
)
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addGroup(gl.createParallelGroup()
.addComponent(arg[0])
.addComponent(arg[1])
.addComponent(arg[2]))
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
EmptyFrame ex = new EmptyFrame();
ex.setVisible(true);
});
}
}
in the main are presents a form and a checkbox group the first is the ntForm and the second one is the techniciansGroup. When i insert a name inside the form i would like to add a checkbox inside the checkbox group, here are the button, the checkbox group and the form classes:
AddTechnicianAction
this would be the class where everything would happened
public class AddTechnicianAction implements ActionListener{
TechCheckBoxGroup technicians;
NewTechForm form;
JTable table;
public AddTechnicianAction(TechCheckBoxGroup arg0, NewTechForm arg1){
technicians=arg0;
form=arg1;
}
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("Add new tech: "+this.form.getSurnameText().getText()+" "+this.form.getNameText().getText());
technicians.addCheckBoxes(new JCheckBox(this.form.getSurnameText()+" "+this.form.getNameText()));
System.out.println(technicians);
}
}
NewTechForm
this is the form
public class NewTechForm {
private JLabel nameLabel;
private JLabel surnameLabel;
private JTextField nameText;
private JTextField surnameText;
private JPanel panel;
public NewTechForm(JPanel panel){
nameLabel= new JLabel("Nome: ", JLabel.RIGHT);
surnameLabel = new JLabel("Cognome: ", JLabel.CENTER);
nameText = new JTextField(6);
surnameText = new JTextField(6);
this.panel=panel;
panel.add(nameLabel);
panel.add(nameText);
panel.add(surnameLabel);
panel.add(surnameText);
}
public JLabel getNameLabel() {
return nameLabel;
}
public JTextField getNameText() {
return nameText;
}
public JTextField getSurnameText() {
return surnameText;
}
public JLabel getSurnameLabel() {
return surnameLabel;
}
public JPanel getPanel() {
return panel;
}
}
The problem is that inside TechCheckBoxGroup something happens, but not the things that i'm expecting to. The panel have a new checkbox after the action is performed but it seems that that panel (the obne inside TachCheckBoxGroup) is not the one inside the main class, and infact nothing were rendered in the window. There is clearly something that i didn't understand about the scoping in swing, what's the better practice to do what i'm trying to? Or this is the good way and i miss something?
I think that it is important to have answers on stack overflow, so for that reason I post my answer to my problem even if it's not really easy to see that was the right solution, now I explain better. While I'm trying to solve the problem of the wrong behaviour I've asked my self if I was doing the wrong considerations, and so it was, because i was trying to let comunicate all the components without a real
mediator
in fact it was impossible to catch the event in the main window with the code that i had written above. Seaching and searching i finally find this great answer here. So i basically change the NewTechForm classes making it a jpanel with a form inside, same thing for the CheckGroupBox, i'll made it a panel with the check box inside, and i send all the event to a listener in the main window.

BorderLayout - JPanel in JPanel

I want to create two JPanel containers nested in another panel, but why does it show nothing as the code below? It seems that my two panels are not on the ABC panel?
public class ABC extends JPanel
{
Frame frame;
public ABC(Frame frame)
{
super();
this.frame = frame;
setLayout(new BorderLayout());
JPanel one = new JPanel();
JPanel two = new JPanel();
add(one,BorderLayout.NORTH);
add(two,BorderLayout.CENTER);
one.setVisible( true );
two.setVisible( true );
}
public class one extends JPanel {
public one() {
setLayout(new FlowLayout(FlowLayout.LEFT));
createA();
setVisible(true);
}
}
public class two extends JPanel {
public two() {
setLayout(new FlowLayout(FlowLayout.LEFT));
createB();
setVisible(true);
}
}
private void createA(){
add(ButtonA);
add(ButtonAA);
add(ButtonAAA);
}
private void createB(){
add(ButtonB);
}
}
Ur using it in the wrong way, u must use youre own clases (one, two) not the JPANEL:
JPanel one = new one();
JPanel two = new two();
add(one,BorderLayout.NORTH);
add(two,BorderLayout.CENTER);
Btw, try to change the name of your clases can be confusing, to One, Two
try to change the prefererSize of the panel one because when you put a panel in NORTH OR anywhere else but the CENTRE it should have a size
use border to see the edge of the panel
one.setBorder(BorderFactory.createLineBorder(Color.black));
two.setBorder(BorderFactory.createLineBorder(Color.blue));
one.setpreferredsize(new new dimension(width,height));
add(one,BorderLayout.NORTH);

Assigning current JPanel to new instance of JPanel but does not refresh

I have sub-classed JPanel to provide a generic JPanel container that contains options for a filter selected from a JComboBox.
When the JComboBox is changed from one filter to another, I have a switch statement that checks which filter is now selected and reassigns the "options" JPanel to a new instance of the options class associated with that filter:
public void setFilterOptions(String choice){
switch(choice){
case "Gaussian": options = new GaussianFilterOptions();break;
case "Sobel": options = new SobelFilterOptions();System.out.println("?");break;
}
}
The problem is that the JPanel "options" does not get refreshed in the GUI after setFilterOptions is called. Whichever filter is set to show by default appears upon startup and remains even if I switch the JComboBox selection. I have tried repainting, revalidating, and validating "options" as well as the JPanel containing "options" and the JFrame enclosing the entire application.
I added print statements in each case to verify that they were working when the combo box is switched and not falling through, so I'm sure that is not the problem.
You're confusing variable with object. You have likely originally placed a JPanel object that options referred to into your GUI, but understand, you didn't place the options variable into the GUI, but rather (and again) the JPanel object that it referred to into the GUI.
If later you change the JPanel that the options variable refers to, this will have no effect on the GUI, since it still holds the same original JPanel object that it held before. If you want to change the JPanel displayed, you have to do that directly by swapping out JPanels in the GUI. This is best accomplished by using a CardLayout.
e.g.,
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class SwapPanels extends JPanel {
private static final String GAUSSIAN = "Gaussian";
private static final String SOBEL = "Sobel";
private static final String[] FILTER_OPTIONS = {GAUSSIAN, SOBEL};
private CardLayout cardLayout = new CardLayout();
private JPanel cardHolderPanel = new JPanel(cardLayout);
private JPanel gaussianPanel = new JPanel();
private JPanel sobelPanel = new JPanel();
private JComboBox<String> filterCombo = new JComboBox<>(FILTER_OPTIONS);
public SwapPanels() {
JPanel comboPanel = new JPanel();
comboPanel.add(filterCombo);
filterCombo.addActionListener(new ComboListener());
gaussianPanel.add(new JLabel("Gaussian Filtering Done Here"));
sobelPanel.add(new JLabel("Sobel Filtering Done Here"));
cardHolderPanel.add(gaussianPanel, GAUSSIAN);
cardHolderPanel.add(sobelPanel, SOBEL);
int gap = 50;
cardHolderPanel.setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setLayout(new BorderLayout());
add(cardHolderPanel, BorderLayout.CENTER);
add(comboPanel, BorderLayout.PAGE_END);
}
private class ComboListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
String key = (String) filterCombo.getSelectedItem();
cardLayout.show(cardHolderPanel, key);
}
}
private static void createAndShowGui() {
SwapPanels mainPanel = new SwapPanels();
JFrame frame = new JFrame("SwapPanels");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Also you could do it like this instead of the switch
public void setFilterOptions(String choice){
options = (choice.equals("Gaussian"))? new GaussianFilterOptions():
new SobelFilterOptions();
}
}

int and boolean not changing after action performed

I copied all of the relevant code below, and my problem is that after running the action performed (which is connected to a button) the values I tried to change in the action performed didn't actually change.
I put a sout(ques) at the end of the action performed and I can see the change in value but when I move outside of it, it reverts back to the 0;
public class GameRunner extends JPanel implements ActionListener{
private int x=50,y=600;
private Ball b = new Ball(x,y);
private Timer timer;
private boolean correct , incorrect;
private JButton button;
private JTextField f;
private int ques = 0;
private String[][] math = {{"2X^2","4x"},{"q2","a2"},{"q3","a3"},{"q4","a4"},{"q5","a5"},
{"q6","a6"},{"q7","a7"},{"q8","a8"}};
public void actionPerformed(ActionEvent actionEvent) {
if (f.getText().equals(math[ques][1])) {
correct = true;
} else {
incorrect = true;
}
f.setText("");
if(ques<7)
ques++;
else
ques = 0;
System.out.println(ques);
//I can see the change here
}
public void paint(Graphics g){//called whenever refreshed...
System.out.println(ques);
// But now outside of the action performed the ques and the correct incorrect do not change
if(correct)
b.move();
if(incorrect)
b.move2();
}
public static void main(String[] args) {
GameRunner gui = new GameRunner ();
gui.go();
}
public void go(){
button = new JButton("Guess");
f = new JTextField(15);
button.addActionListener(this);
JFrame frame = new JFrame("Derivative Game");
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(700, 700));
JPanel pan = new JPanel(new BorderLayout());
JPanel pan2 = new GameRunner();
JPanel pan3 = new JPanel();
pan3.add( f);
pan3.add(button);
pan3.setBackground(new Color(80, 218, 213));
pan.add( pan3,BorderLayout.CENTER);
pan.setBackground(new Color(80, 218, 213));
frame.add(pan2);
frame.getContentPane().add(BorderLayout.SOUTH, pan);
frame.setSize(700, 760);
frame.setVisible(true);
frame.setResizable(false);
}
}
The basic problem is that you've actually got two instances of GameRunner here: the one you create in main(), and another one that you add to the JFrame. Since you only call go() on the one not in the JFrame, that instance's paint() method will never be called.
You need to refactor your code to eliminate that second stray GameRunner instance. While you're at it, you should also use paintComponent() instead of paint(), and you should take any "business logic" (like those calls to move()) out of your painting code.
In other words, get rid of this line:
JPanel pan2 = new GameRunner();
Since you're already "in" an instance of GameRunner, you shouldn't be creating another one. Then to use the "current" instance of GameRunner, you can use the this keyword:
frame.add(this);
Edit- You also aren't telling your GameRunner JPanel to repaint itself after the button is clicked. You might want to add a call to repaint() in your actionPerformed() method.

Listener doesn't work

I'm writing a Java programm, according to MVC model.
So the problem is that the Frame doesn't react to button click.
(The text, that I write isn't added to the TextArea after click)
At first I call constructors for View and Controller
MessageFrame mf = new MessageFrame(con);
MessageFrameListener mfl = new MessageFrameListener(mf);
Here is the part of MessageFrameListener class (controller)
public class MessageFrameListener{
private MessageFrame mf;
public MessageFrameListener(MessageFrame m_f){
mf = m_f;
m_f.addButtonListener(new SButtonListener());
}
//#Override
public class SButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
String insert = mf.getInput();
mf.addLine(insert);
mf.refreshInput();
}
}
}
Here is the part from MessageFrame class (View)
public class MessageFrame{
public JTextField messField;
public JTextArea dialogArea;
public JButton sendButton;
public JFrame frame;
public Contact con;
public MessageFrame (Contact con_get) {
con = con_get;
frame = new JFrame();
frame.setSize(538, 299);
JPanel panel_1 = new JPanel();
frame.getContentPane().add(panel_1, BorderLayout.NORTH);
JPanel panel_2 = new JPanel();
frame.getContentPane().add(panel_2, BorderLayout.SOUTH);
panel_2.setLayout(new BoxLayout(panel_2, BoxLayout.X_AXIS));
messField = new JTextField();
panel_2.add(messField);
messField.setColumns(10);
JButton sendButton = new JButton("Send");
panel_2.add(sendButton);
JPanel panel_3 = new JPanel();
frame.getContentPane().add(panel_3, BorderLayout.EAST);
JPanel panel_4 = new JPanel();
frame.getContentPane().add(panel_4, BorderLayout.CENTER);
panel_4.setLayout(new BorderLayout(0, 0));
JTextArea dialogArea = new JTextArea();
panel_4.add(dialogArea);
frame.setVisible(true);
}
public String getInput(){
return messField.getText();
}
public void refreshInput(){
messField.setText("");
}
public void addLine(String line){
dialogArea.append(line);
}
public void addButtonListener(ActionListener bal){
sendButton.addActionListener(bal);
}
}
You will definately find the answer if you check the output of your program or debug it.
Exception in thread "main" java.lang.NullPointerException
at test3.MessageFrame.addButtonListener(Main.java:93)
at test3.MessageFrameListener.<init>(Main.java:28)
at test3.Main.main(Main.java:18)
Your are hiding the reference to the JButton sendButton by declaring it again in the constructor so the field is never initialised.
JButton sendButton = new JButton("Send");
panel_2.add(sendButton);
Since you've posted code scraps and have not posted a functioning SSCCE that we can test, all we can do is guess -- so you'll get what you paid for, and here goes my guess:
You're listening on the wrong MessageFrame. Your program has 2 or more MessageFrame objects, one of which is displayed, and the other which is being listened to, and so your displayed MessageFrame will of never trip the listener.
If this doesn't help, and you need better help, then please provide us with a better question, and an sscce.
You are adding an empty string:
String insert = mf.getInput(); //all it does is: messField.getText();
mf.addLine(insert); //adding the empty string
mf.refreshInput(); //all it does is: messField.setText("");

Categories