When i run the code below, the fireEvent() method is called inside the Slider class instead of the ColorPanel class. How can i make it call the fireEvent() method in the ColorPanel class? (They both extend EventComponent which has the method)
public class ColorPanel extends EventComponent<ColorChangeListener> {
public ColorPanel() {
...
add(new ValueSlider());
}
.................more Code
#Override
protected void fireEvent() {
for (ColorChangeListener l : listeners)
l.colorChanged(color);
}
private class ValueSlider extends Slider {
public ValueSlider() {
super(0, 200, 200, 200);
this.x = 10;
this.y = 220;
addListener(new ValueChangeListener() {
#Override
public void valueChanged(int value) {
colorCircle.setValue(value / 200f);
color = colorCircle.getSelectedColor();
fireEvent();
}
});
}
}
Point the compiler to the right method by changing fireEvent(); to ColorPanel.this.fireEvent();
You should specify the class like this:
ColorPanel.this.fireEvent();
Related
Suppose you have class A and class B. Class A is the main class which builds a frame with a GUI. It contains all the GUI variables (such as buttons, labels, strings) along with whatever methods that you'll be using. Class A also creates a class B object:
ClassB name = new ClassB();
Inside class B you will find a for loop. Now, once the for loop is finished looping, I want to call a method located in class A. Whenever I try calling a method located in class A, Eclipse suggests making that method static. I'm trying to avoid making static methods. Is there a way of calling class A's methods from class B without making anything static?
Class A:
public class Game extends JFrame implements ActionListener {
// init variables
private JPanel contentPane;
private JPanel panel_actions;
private JButton btn_strike;
private JProgressBar progBar_loading;
private Load load;
// create the frame
public dsgsd() {
load = new Load();
// frame initializing
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setBounds(100, 100, 890, 480);
setTitle("BeyondInfinity - Group Project for CS1100");
getContentPane().setLayout(null);
setVisible(true);
// create a root panel
contentPane = new JPanel();
contentPane.setLayout(null);
contentPane.setBounds(0, 0, 884, 451);
contentPane.setVisible(true);
getContentPane().add(contentPane);
// create actions panel for displaying attack buttons
panel_actions = new JPanel();
panel_actions.setBorder(new EmptyBorder(10, 10, 10, 10));
panel_actions.setBounds(10, 306, 854, 68);
panel_actions.setBackground(new Color(100, 149, 237));
panel_actions.setLayout(new GridLayout(0, 6, 10, 0));
panel_actions.setVisible(true);
contentPane.add(panel_actions);
// create attack button #1
btn_strike = new JButton("Strike");
btn_strike.setFocusable(false);
btn_strike.setVisible(true);
btn_strike.addActionListener(this);
panel_actions.add(btn_strike);
}
// create action listener
public void actionPerformed(ActionEvent evt) {
if (evt.getSource().equals(btn_strike)) {
load.start();
}
}
public void executeTasks() {
//TODO do something
}
// set value for the loading bar
public void setProgBar_loading(int val) {
progBar_loading.setValue(val);
progBar_loading.repaint();
}
}
Class B:
public class Load {
private Timer timer;
private int i;
public void start() {
// reset loading bar
Game.setProgBar_loading(0);
i = 0;
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (i > 100) {
timer.stop();
Game..executeTasks();
} else
Game.setProgBar_loading(i++);
}
};
// timer which triggers the actionlistener every 15ms
timer = new Timer(15, listener);
timer.start();
}
}
You're going to need a reference to an instance of ClassA inside of ClassB to avoid static methods.
First, ClassB will need a field and constructor similar to the following:
private ClassA parent = null;
public ClassB(ClassA parent) {
this.parent = parent;
}
Then, when you instantiate ClassB, you'll pass a reference to the current instance like so: ClassB name = new ClassB(this)
Finally, when you want to use your method inside ClassB (let's assume that method is called doSomething(), you can call it with parent.doSomething()
The "proper" OOP approach to do this would be with an interface.
public interface Loadable {
void reset();
void setProgress(int progress);
void onLoaded();
}
You implement this in your Game class
public class Game extends JFrame implements ActionListener, Loadable {
private JButton load_button;
private JProgressBar progressBar;
public Game() {
// initialize
}
public void executeTasks() {
//TODO do something
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(load_button)) {
new Loader().load(this);
}
}
#Override
public void onLoaded() {
executeTasks();
}
#Override
public void reset() {
progressBar.setValue(0);
}
#Override
public void setProgress(int progress) {
progressBar.setValue(progress);
}
}
And pass it into the Loader. This way, the Loader doesn't care the you are giving it a Game object. You could have any implementation of Loadable that this Loader can load.
public class Loader {
private Timer timer;
private int i;
public void load(final Loadable l) {
// reset loading bar
l.reset();
i = 0;
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
l.setProgress(++i);
if (i >= 100) {
timer.stop();
l.onLoaded();
}
}
};
// timer which triggers the actionlistener every 15ms
timer = new Timer(15, listener);
timer.start();
}
}
You can call non-static methods of an object, but you can only call static methods on a class. See this for more information on the difference between the two. To be able to call a method on an object of type ClassA, you'd have to do something like this:
public class ClassA {
public method myNonStaticMethod() { ... }
}
public class ClassB {
private ClassA a;
public ClassB(ClassA a) {
this.a = a; //This makes sure this *object* has a *reference* to an object of *type* ClassA.
}
public void looping() {
//some looping code
this.a.myNonStaticMethod(); //Actually call the nonstatic method
}
}
Note that any class that imports another class will have reference to that class and can call static methods on that class, or instantiate a new object of that class type. If you want a particular object to call a non-static method of another object, it either needs to instantiate the object itself, or it needs a reference to that other object.
In the example above, the constructor of ClassB gets a reference to a specific object of type ClassA, whose reference name is a. This is saved to a private member field, which can be called by any non-static method in an object of type ClassB.
To call any non-static method of A, you need a class instance of A. Do you have one inside class B? If you don't then you can't call a non-static method. A static method can be called without the instance (as long as it is accessible) like this A.method1();
I'm trying to create two windows with Processing. Before you mark this as a duplicate, as there are other questions similar to this, I have a specific error and I can't find a solution. When I try to add(s) I get the error The method add(Component) in the type Container is not applicable for the arguments (evolution_simulator.SecondApplet)
I'm not sure how to fix this, and any help would be appreciated. Here is the code:
import javax.swing.*;
PFrame f;
void setup() {
size(320, 240);
f = new PFrame();
}
void draw() {
}
public class PFrame extends JFrame {
SecondApplet s;
public PFrame() {
setBounds(100,100,400,300);
s = new SecondApplet();
add(s); // error occurs here
s.init();
show();
}
}
public class SecondApplet extends PApplet {
public void setup() {
size(400, 300);
noLoop();
}
public void draw() {
}
}
The reason for the error message is because the add() function is expecting a Component, and PApplet is not a Component. This is because PApplet no longer extends Applet as of Processing 3, so old code that uses it as a Component will no longer work.
Instead, you can create a class that extends PApplet for your second window, and then call PApplet.runSketch() using that second PApplet as a parameter:
void setup() {
size(100, 100);
String[] args = {"TwoFrameTest"};
SecondApplet sa = new SecondApplet();
PApplet.runSketch(args, sa);
}
void draw() {
background(0);
ellipse(50, 50, 10, 10);
}
public class SecondApplet extends PApplet {
public void settings() {
size(200, 100);
}
public void draw() {
background(255);
fill(0);
ellipse(100, 50, 10, 10);
}
}
I have got a problem and I'm totally new at programming I have the object the Hero and I want to use all of his methods in my game class this is what I Programmed so far:
MainGame class:
class MainGame extends JComponent implements ActionListener, KeyListener{
Image Background;
MainGame() throws IOException {
Background = ImageIO.read(getClass().getResource("Background.png"));
}
public static void main (String[] args) throws IOException {
JFrame window = new JFrame("Adventure Times");
MainGame game = new MainGame();
window.add(game);
window.pack();
window.setLocationRelativeTo(null);
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.setVisible(true);
window.addKeyListener(game);
}
public void paintComponent(Graphics g) {
g.drawImage(Background, 0, 0, null);
}
public Dimension getPreferredSize() { return new Dimension(800, 600);
}
public void actionPerformed(ActionEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT);
Hero.moveRight();
}
public void keyReleased(KeyEvent e) {
}
}
Hero class:
public class Hero {
public int HeroX = 0;
public int HeroY = 0;
public int HeroSpeed = 0;
private BufferedImage Hero;
public Hero() {
try {
Hero = ImageIO.read(getClass().getResource("Hero.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void Draw(Graphics g) {
g.drawImage(Hero, HeroX, HeroY, null);
}
public void moveRight() {
HeroX += HeroSpeed;
}
public void moveLeft() {
HeroX -= HeroSpeed;
}
}
To use Hero's methods in your MainGame class, you either need an instance of Hero that can call them, or the method definitions have to include the static keyword. In this application, static doesn't work, and would in fact completely break your Hero class if applied to the methods you have now, so you need to instantiate a Hero. To do this, you need to, within MainGame have the line
Hero achilles = new Hero();
With the code you currently have, however, this will throw an exception in the Hero constructor that your try statement doesn't catch, as it won't be an IOException. The exception will be a result of trying to assign a value to a data type in
Hero = ImageIO.read(getClass().getResource("Hero.png"));
In fact, the code as it is won't even compile because of the attempted definition of Hero as a member of type BufferedImage. This is illegal, as you cannot use a class name as an identifier. This is similar to doing int = 4, which makes no sense. Rename the BufferedImage wherever it's referred to and the code should compile. For instance:
private BufferedImage sprite;
Alternatively, you could name it hero with a lowercase 'h' to avoid the name collision. This is also in line with naming conventions and general best practice for Java, as well as most languages. Class names are usually capitalized, while member names are usually lowercase. For more info on naming conventions, see here.
So I have a class that extends a JPanel and within the constructor I add my JButtons and whatever else I need to add. I also have a MainFrame class that is the container (JFrame) and this class will take an argument from a class called FrameSwitcher (Controller) which will assess what buttons were clicked, and pass the information to the MainFrame
I'm having troubles doing this, I can't find a proper way to do this. I do also wish to maintain the JButtons private and non static.
JPanel example:
public class MainMenu() {
private JButton btnSinglePlayer, btnMultiPlayer;
public MainMenu() {
setLayout(null);
btnSinglePlayer = new JButton("singlePlayer");
btnSinglePlayer.setBounds(320, 25, 275, 130);
add(btnSinglePlayer);
btnMultiPlayer = new JButton("MultiPlayer");
btnMultiPlayer.setBounds(320, 170 , 275, 130);
add(btnMultiPlayer);
}
}
FrameSwitcher:
public class FrameSwitcher implements panelListener { // panelListener is an interface defined else where.
public FrameSwitcher(MainFrame frame) {
// This is irrelevant to the question.
}
#Override
public void gamePanel() {
System.out.println("GamePanel Event: Recieved");
}
#Override
public void mainMenu() {
System.out.println("mainMenu Event: Recieved");
}
#Override
public void scoreBoardPanel() {
System.out.println("scoreBoardPanel Event: Recieved");
}
}
Then my MainFrame:
public class MainFrame extends JFrame implements ActionListener {
private PanelListener panelListener;
private JFrame mainContainer = new JFrame("Game");
private JPanel mainMenu = new MainMenu();
public void start() {
mainContainer(mainMenu);
}
public MainFrame(JPanel frame) {
mainContainer.getContentPane().add(frame);
mainContainer.pack();
// Other methods to initialize the frame
return mainContainer;
}
public void switchFrames(PanelListener panelListener) {
this.panelListener = panelListener; // PanelListener is an interface.
}
public void actionPerformed(ActionEvent e) {
JButton source = (JButton)e.getsource();
if(source == MainMenu.btnSinglePlayer) {
if(panelListener != null) {
System.out.println("Recieved the event approriately.");
}
}
}
}
In this example, it does compile, but doesn't do what it is supposed to. Another thing is I currently have the JButtons as public and static, I don't want that.
In your MainMenu class, you need to add some kind of listener that interested parties can register with, so when some event occurs, they can be notified.
The simplest solution would be to provide a addActionListener method which delegated to each of the buttons. This, however, has may expose portions of the application you don't exposed (a listener now has direct access to the JButton and can do all kinds of nasty things to it).
A better solution would be to create something like a MainMenuListener which had methods like startSinglePlayer and startMultiPlayer
You would then provide a add/removeMainMenuListener method within in your MainMenu class.
Each button would then register there own actionListener and fire the appropriate menu listener event
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class MainMenu extends JPanel {
private JButton btnSinglePlayer, btnMultiPlayer;
public MainMenu() {
setLayout(null);
btnSinglePlayer = new JButton("singlePlayer");
btnSinglePlayer.setBounds(320, 25, 275, 130);
add(btnSinglePlayer);
btnSinglePlayer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fireStartSinglePlayer();
}
});
btnMultiPlayer = new JButton("MultiPlayer");
btnMultiPlayer.setBounds(320, 170, 275, 130);
add(btnMultiPlayer);
btnMultiPlayer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fireStartMultiPlayer();
}
});
}
public void addMainMenuListener(MainMenuListener listener) {
listenerList.add(MainMenuListener.class, listener);
}
public void removeMainMenuListener(MainMenuListener listener) {
listenerList.remove(MainMenuListener.class, listener);
}
public void fireStartSinglePlayer() {
MainMenuListener[] listeners = listenerList.getListeners(MainMenuListener.class);
if (listeners != null && listeners.length > 0) {
for (MainMenuListener listener : listeners) {
listener.startSinglePlayer();
}
}
}
public void fireStartMultiPlayer() {
MainMenuListener[] listeners = listenerList.getListeners(MainMenuListener.class);
if (listeners != null && listeners.length > 0) {
for (MainMenuListener listener : listeners) {
listener.startMultiPlayer();
}
}
}
public interface MainMenuListener extends EventListener {
public void startSinglePlayer();
public void startMultiPlayer();
}
}
First you have to create an ActionListener like this
class MyActionListener implements ActionListener{
public void actionPerformed(ActionEvent ae){
//do your stuff
}
}
Then call,
yourButton.addActionListener(new MyActionListener());
I'm learning Java, and now that I'm over the packages hump, things are going smoothly. I can draw similarities between most things I'm learning with things I already know at least the concept of. But what on earth is going on with the following bit of code? Is it some form of constructor, or anonymous object?
Something obj = new Something()
{
private static final int num = 3;
public void meth()
{
// w/e
}
};
You got it - this creates an anonymous inner class of Something.
See also: Nested Classes (The Java Tutorial) and Anonymous Classes.
/**
* Notice there's only one thing in this that isn't defined:
* It still needs public abstract void triggerEvent();
*/
public abstract static class TopButton extends JPanel implements MouseListener {
protected ButtonPanel parent;
private String text;
public TopButton(ButtonPanel bp, String text) { parent = bp; this.text = text; addMouseListener(this); }
public void mouseClicked(MouseEvent e) { triggerEvent(); }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public abstract void triggerEvent();
public void paintComponent(Graphics g) {
super.paintComponent(g);
Color oldColor = g.getColor();
Font oldFont = g.getFont();
Font newFont = new Font(oldFont.getName(),oldFont.getStyle(),oldFont.getSize());
g.setFont(newFont);
g.setColor(Color.black);
g.drawString(text, 20, 20);
g.setFont(oldFont);
g.setColor(oldColor);
}
}
Now, when I actually define my buttons, I do this. By providing the one line it needs, the only thing that makes it different from others. Now I could make a new file for each one, and define a new class for each one. This is much simpler.
private static void loadButtonPanelButtons() {
/* This button should tell the parent to bring up the save screen */
TopButton save = new TopButton(buttonPanel,"Save") {
public void triggerEvent() { parent.triggerSave(); }
};
save.setBorder(LineBorder.createBlackLineBorder());
buttonPanel.add(save);
/* This button should tell the parent to bring up the load screen */
TopButton load = new TopButton(buttonPanel,"Load") {
public void triggerEvent() { parent.triggerLoad(); }
};
load.setBorder(LineBorder.createBlackLineBorder());
buttonPanel.add(load);
TopButton addTile = new TopButton(buttonPanel,"Add Tile") {
public void triggerEvent() { parent.triggerAddTile(); }
};
addTile.setBorder(LineBorder.createBlackLineBorder());
buttonPanel.add(addTile);
TopButton saveTiles = new TopButton(buttonPanel,"Save Tiles") {
public void triggerEvent() { parent.triggerStyleSave(); }
};
saveTiles.setBorder(LineBorder.createBlackLineBorder());
buttonPanel.add(saveTiles);
}
Now, when I handle the buttons being pressed, remember back in the definition of TopButton... there was
public void mouseClicked(MouseEvent e) { triggerEvent(); }
We know triggerEvent() eventually gets defined. We can define it on a per-button basis, and when the panel gets clicked, no matter what we defined triggerEvent() to be, it gets called.
Such construct creates an anonymous inner class of a class where this construct is executed, and derived from Something (not an inner class of Something).
The idea is to quickly provide implementations for abstract classes, interfaces, or override some functionality of a class.
(new Thread(){ public void run() { System.out.println("executed on another thread"); }}).start();