问题
This post is continue of this post. Basically in my software is based on CardLayout
panels. And now I want to change panels from outside of cardLayout
. in the provided link, I got helped to do this and it worked. Now I added a controller to my software, that is between an inner panel (CardLayout
) and an outside panel. In the outside panel(leftBar
) I have a button that if its actionListener
is located inside that class it works correctly and open the chose inner panel of CardLayout
. But if I take the ActionListener
into the controller, it just doesnt work. No error comes up.
Here is my sample code: BASE:
public class Base {
JFrame frame = new JFrame("Panel");
BorderLayout bl = new BorderLayout();
public Base(){
MainPanel mainPanel = new MainPanel();
LeftBar leftBar = new LeftBar(mainPanel);
frame.setLayout(bl);
frame.setSize(800, 600);
frame.add(leftBar, BorderLayout.WEST);
frame.add(mainPanel, BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) throws IOException {
new Base();
}
}
MainPanel (CardLAyout base)
public class MainPanel extends JPanel {
private CardLayout cl = new CardLayout();
private JPanel panelHolder = new JPanel(cl);
public MainPanel(){
FirstPage firstPage = new FirstPage(this);
SecondPage secondPage = new SecondPage(this);
LeftBar leftBar = new LeftBar(this);
Controller controller = new Controller(secondPage, leftBar, this);
setLayout(new GridLayout(0,1));
panelHolder.add(firstPage, "firstPage");
panelHolder.add(secondPage, "secondPage");
cl.show(panelHolder, "firstPage");
add(panelHolder);
}
public void showPanel(String panelIdentifier){
cl.show(panelHolder, panelIdentifier);
}
}
LeftBar
public class LeftBar extends JPanel{
private JButton button;
private MainPanel mainPanel;
public LeftBar(MainPanel mainPanel){
this.mainPanel = mainPanel;
setPreferredSize(new Dimension(200, 40));
setLayout(new BorderLayout());
setBackground(Color.black);
button = new JButton("Show Second Page");
add(button, BorderLayout.NORTH);
}
public void addPageListener(ActionListener listenForButton){
button.addActionListener(listenForButton);
}
}
Second Page:
public class SecondPage extends JPanel{
MainPanel mainPanel;
JButton button;
public SecondPage(MainPanel mainPanel){
this.mainPanel = mainPanel;
setBackground(Color.white);
add(new JLabel("This is second page"));
}
}
First Page:
public class FirstPage extends JPanel {
MainPanel mainPanel;
JButton button;
public FirstPage(MainPanel mainPanel) {
this.mainPanel = mainPanel;
setBackground(Color.GRAY);
button = new JButton("Show page");
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent ae) {
mainPanel.showPanel("secondPage");
}
});
add(button);
}
}
And controller:
public class Controller {
private SecondPage secondPage;
private LeftBar leftBar;
private MainPanel mainPanel;
public Controller(SecondPage secondPage, LeftBar leftBar, MainPanel mainPanel){
this.secondPage=secondPage;
this.leftBar=leftBar;
this.mainPanel=mainPanel;
this.leftBar.addPageListener(new ButtonListener());
}
class ButtonListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Works");
mainPanel.showPanel("secondPage");
}
}
}
As you can see in LeftBar
I have a method for the button that works as an actionListener
. and I call that method in controller and give it a class. But it doesnt work. However the ACtionListener
works if it is located in LeftBar class (inline).
Any idea how to fix it?
回答1:
You're creating two instances of LeftBar
, one in the Base
constructor, which gets added to the screen...
public Base() {
MainPanel mainPanel = new MainPanel();
LeftBar leftBar = new LeftBar(mainPanel);
frame.setLayout(bl);
frame.setSize(800, 600);
frame.add(leftBar, BorderLayout.WEST);
frame.add(mainPanel, BorderLayout.CENTER);
And one in the MainPanel
constructor which gets passed to the controller...
public class MainPanel extends JPanel {
private CardLayout cl = new CardLayout();
private JPanel panelHolder = new JPanel(cl);
public MainPanel() {
FirstPage firstPage = new FirstPage(this);
SecondPage secondPage = new SecondPage(this);
LeftBar leftBar = new LeftBar(this);
This means the controller is attach a ActionListener
to a button which is never visible on the screen
The first thing I would do is start decoupling your code, rather then passing instances of your class, you need to establish a series of contracts to which you controller and views can agree to, for example, your MainPanel
should provide a way to switch views, your LeftBar
should provide notification when the user wants to switch views
For example...
public interface Pageable {
public void showView(String name);
}
public interface Navigatable {
public void addActionListener(ActionListener listener);
}
Then your main view would implement the Pageable
interface
public class MainPanel extends JPanel implements Pageable {
//...
@Override
public void showView(String name) {
cl.show(panelHolder, name);
}
And your LeftBar
would implement the Navigatable
interface
public class LeftBar extends JPanel implements Navigatable {
//...
@Override
public void addActionListener(ActionListener listener) {
button.addActionListener(listener);
}
This simply defines the contractual capabilities of any implementation, your controller should not care about anything else (nor should you allow it to do things it wasn't meant to, like remove all the components from your views, naughty controller)
Your controller then just becomes responsible for managing the contracts between the interfaces...
public class Controller {
private final Navigatable navigatable;
private final Pageable pageable;
public Controller(Navigatable navigatable, Pageable pageable) {
this.navigatable = navigatable;
this.pageable = pageable;
navigatable.addActionListener(new ButtonListener());
}
class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent ae) {
pageable.showView("secondPage");
}
}
}
For example...
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Base {
JFrame frame = new JFrame("Panel");
BorderLayout bl = new BorderLayout();
public Base() {
MainPanel mainPanel = new MainPanel();
LeftBar leftBar = new LeftBar(mainPanel);
frame.setLayout(bl);
frame.setSize(800, 600);
frame.add(leftBar, BorderLayout.WEST);
frame.add(mainPanel, BorderLayout.CENTER);
Controller controller = new Controller(leftBar, mainPanel);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) throws IOException {
new Base();
}
public interface Pageable {
public void showView(String name);
}
public interface Navigatable {
public void addActionListener(ActionListener listener);
}
public class MainPanel extends JPanel implements Pageable {
private CardLayout cl = new CardLayout();
private JPanel panelHolder = new JPanel(cl);
public MainPanel() {
FirstPage firstPage = new FirstPage(this);
SecondPage secondPage = new SecondPage(this);
setLayout(new GridLayout(0, 1));
panelHolder.add(firstPage, "firstPage");
panelHolder.add(secondPage, "secondPage");
cl.show(panelHolder, "firstPage");
add(panelHolder);
}
public void showPanel(String panelIdentifier) {
cl.show(panelHolder, panelIdentifier);
}
@Override
public void showView(String name) {
cl.show(panelHolder, name);
}
}
public class LeftBar extends JPanel implements Navigatable {
private JButton button;
private MainPanel mainPanel;
public LeftBar(MainPanel mainPanel) {
this.mainPanel = mainPanel;
setPreferredSize(new Dimension(200, 40));
setLayout(new BorderLayout());
setBackground(Color.black);
button = new JButton("Show Second Page");
add(button, BorderLayout.NORTH);
}
@Override
public void addActionListener(ActionListener listener) {
button.addActionListener(listener);
}
}
public class SecondPage extends JPanel {
MainPanel mainPanel;
JButton button;
public SecondPage(MainPanel mainPanel) {
this.mainPanel = mainPanel;
setBackground(Color.white);
add(new JLabel("This is second page"));
}
}
public class FirstPage extends JPanel {
MainPanel mainPanel;
JButton button;
public FirstPage(MainPanel mainPanel) {
this.mainPanel = mainPanel;
setBackground(Color.GRAY);
button = new JButton("Show page");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
mainPanel.showPanel("secondPage");
}
});
add(button);
}
}
public class Controller {
private final Navigatable navigatable;
private final Pageable pageable;
public Controller(Navigatable navigatable, Pageable pageable) {
this.navigatable = navigatable;
this.pageable = pageable;
navigatable.addActionListener(new ButtonListener());
}
class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent ae) {
pageable.showView("secondPage");
}
}
}
}
Now personally, this is just a bit of hacking around your code, personally, I would prefer to have a controller which interacted with a single view/contract, it makes it SO much simpler...
来源:https://stackoverflow.com/questions/29597973/why-doesnt-actionlistener-work-in-the-controller