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();
Related
I am trying to simplify the Javax swing graphics classes in order to make it easier for other people to get into Java graphics, but I am facing a problem with testing it.
Keep in mind, that I am writing the main method as a user of the code and not the developer. I need answers that will change the code of the class methods and not the main method.
What my main method code is supposed to do is print 'hovering' when the user hovers over the button. However, when I add a SOP statement before the if statement, it works...
The method for the mouse hovering is in the Button class.
Here is my main method code -
public static void main(String[] args) {
GraphWin win = new GraphWin(1000, 1000, "Graphics Window - Test");
win.show();
Button button = new Button(new Point(380, 300), new Point(620, 400));
button.draw(win);
enter code herewhile(true) {
//System.out.println(button.hovering);
if(button.hovering) {
System.out.println("hovering");
}
}
}
And here is my code for the Button class -
public class Button implements MouseListener{
public JButton button;
public boolean clicked = false, hovering = false, pressed = false;
public Button(Point p, Point p2) { //This is the default constructor of the button with only 2 points specified
this.button = new JButton();
this.setBounds(p, p2);
this.button.addMouseListener(this);
this.setBorderVisible(false);}
public Button(Point p, Point p2, String text) { //This constructor requires text to be displayed`enter code here`
this.button = new JButton(text);
this.setBounds(p, p2);
this.button.addMouseListener(this);
this.setBorderVisible(false);}
public Button(String icon, Point p, Point p2) { //This constructor sets an Icon for the button
this.button = new JButton();
this.setIcon(icon);
this.setBounds(p, p2);
this.button.addMouseListener(this);
this.setBorderVisible(false);}
public Button(Point p, Point p2, String text, String icon) { //Here, both the text and Icon is specified
this.button = new JButton(text);
this.setIcon(icon);
this.setBounds(p, p2);
this.button.addMouseListener(this);
this.setBorderVisible(false);}
public void draw(GraphWin win) {
win.window.add(this.button);}
public void setBounds(Point p, Point p2) {
this.button.setBounds(p.x, p.y, p2.x - p.x, p2.y - p.y);
}
public void setEnabled(boolean enable) {
this.button.setEnabled(enable);}
public void disable() {
this.button.setEnabled(false);}
public void enable() {
this.button.setEnabled(true);
}
public void setColor(Color color) {
this.button.setBackground(color);}
public void setColor(String color) {
this.button.setBackground(Color.decode(color));}
public void setText(String text) {
this.button.setText(text);}
public void setIcon(String icon) {
File imageCheck = new File(icon);
if(!imageCheck.exists())
System.out.println("Image file not found!");
else
this.button.setIcon(new ImageIcon(icon));
}
public void resizeIcon(String icon, int width, int height) {
Image img = new ImageIcon(icon).getImage();
img = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
this.button.setIcon(new ImageIcon(img));
}
public void setCustomMargins(int top, int bottom, int left, int right) {
this.button.setMargin(new Insets(top, left, bottom, right));}
public void setMargins(int m) {
this.button.setMargin(new Insets(m, m, m, m));}
public void setLabel(String label) {
this.button.setToolTipText(label);
}
public void setBorderVisible(boolean border) {
this.button.setBorderPainted(border);}
public void setOpaque(boolean opaque) {
this.button.setContentAreaFilled(opaque);}
#Override
public void mouseEntered(MouseEvent arg0) {
this.hovering = true;
System.out.println(1);
}
#Override
public void mouseExited(MouseEvent arg0) {
this.hovering = false;
}
#Override
public void mousePressed(MouseEvent arg0) {
this.pressed = true;
}
#Override
public void mouseReleased(MouseEvent arg0) {
this.pressed = false;
}
#Override
public void mouseClicked(MouseEvent e) {
this.clicked = true;
System.out.println(1);
}
}
This sort of thing is usually to do with threading.
Events in Swing are dispatched on the AWT Event Dispatch Thread (EDT). In order to be thread-safe, practically everything dealing with Swing/AWT should be done on the EDT.
In your case, there is no kind of locking between the variable being set and read. Adding a println causes a pause (with all sorts of memory barriers or whatnot) that happens to allow the program to run in the desired sequence.
You've probably seen main methods written to pass execution straight over to the AWT.
class MyGUI {
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(MyGUI::go);
}
private static void go() {
...
It might be better to supply the main class yourself, implemented such that it takes the application class as an argument and passes execution on once everything is setup. Whilst traditionally command lines use a main static method/function, everywhere else subtypes: Applets, Servlets, etc.
best approach would be to use a isHovering() method but educated guess on the behavior inside a while(true) with or without a Sysout might be related to a compiler optimisation. Might be fixed by putting the hovering variable as transient
I realize this is a repeat question, but my circumstances are a little bit different. I need to have a MouseListener in another class that can altar the background color of the object that calls it. Please help me.
public class LeftListPanel extends JPanel {
public LeftListPanel() {
setBackground(Settings.BACKGROUND_COLOR);
setLayout(null);
addPersonalStatsTab();
}
private void addPersonalStatsTab() {
JPanel personalStatsPanel = new JPanel();
personalStatsPanel.addMouseListener(new CustomMouseListener());
JLabel personalStatsText = new JLabel("Text");
personalStatsPanel.add(personalStatsText);
add(personalStatsPanel);
}
Then I have an inner-nested class for the MouseListener because this is the only place this MouseListener will be called.
class CustomMouseListener implements MouseListener {
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
setBackground(Settings.BACKGROUND_COLOR.brighter());
}
#Override
public void mouseExited(MouseEvent e) {
setBackground(Settings.BACKGROUND_COLOR);
}
}
The setBackground(COLOR) lines are those who don't work... this.setBack and super.setBack ARE NOT working in this case.. I'M DESPERATE FOR HELP!
The reason you don't see the background changes is that when you call setBackground, you are de-referring (implicitly) the this object, i.e. the instance of LeftListPanel. So, you are actually changing its background, but you don't see it because inside the LeftListPanel instance there is another JPanel (instantiated at the addPersonalStatsTab method) which occupies the whole visible space (or even it is not visible at all, because of that weird null layout; I don't know exactly).
Fist of all, I recommend to you not to set null as a layout. Chose a proper layout, or let it be defaulted - do not call setLayout(null).
Then, set personalStatsPanel as a private member of LeftListPanel. And when calling to setBackground, use it as the scope reference:
LeftListPanel.this.personalStatsPanel.setBackground(...);
This works, I instead just created a private method where I pass in the panel I want to apply it too.
private void CustomMouseListener(JPanel panel) {
panel.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
panel.setBackground(Settings.BACKGROUND_COLOR.brighter());
}
#Override
public void mouseExited(MouseEvent e) {
panel.setBackground(Settings.BACKGROUND_COLOR);
}
});
}
Thank you all for your time and suggestions :)
You could...
Pass a reference of the component you want changed to the CustomMouseListener
class CustomMouseListener implements MouseListener {
private JPanel panel;
public CustomMouseListener(JPanel panel) {
this.panel = panel;
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
panel.setBackground(Settings.BACKGROUND_COLOR.brighter());
}
#Override
public void mouseExited(MouseEvent e) {
panel.setBackground(Settings.BACKGROUND_COLOR);
}
}
This is okay if you want to use the listener on a limited number of components, but if you want to use the same listener on a number of components...
You could...
Use the source property of the MouseEvent to get which component triggered the event
#Override
public void mouseEntered(MouseEvent e) {
if (!(e.getSource() instanceof JPanel)) {
return;
}
JPanel panel = (JPanel)e.getSource();
panel.setBackground(Settings.BACKGROUND_COLOR.brighter());
}
or, a better solution would be to do something more like...
#Override
public void mouseEntered(MouseEvent e) {
e.getComponent().setBackground(Settings.BACKGROUND_COLOR.brighter());
}
since the information is already provided to you (just not, this returns an instance of Component, so if you need to access the Swing specific properties, you'd still need to cast it).
Why is this approach better?
CustomMouseListener listener = new CustomMouseListener();
panel1.addMouseListener(listener);
panel2.addMouseListener(listener);
panel3.addMouseListener(listener);
panel4.addMouseListener(listener);
panel5.addMouseListener(listener);
panel6.addMouseListener(listener);
panel7.addMouseListener(listener);
because it's agnostic, meaning you can create a single instance of the listener and re-use on multiple components
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.
I have two classes in same package. i have declared a static variable in one class and want to access that variable in another class.
Here is my code in which i have declared the static variable
public class wampusGUI extends javax.swing.JFrame {
static String userCommand;
public wampusGUI() {
initComponents();
}
public void setTextArea(String text) {
displayTextArea.append(text);
}
private void enterButtonActionPerformed(java.awt.event.ActionEvent evt) {
userCommand = commandText.getText();
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
wampusGUI w = new wampusGUI();
w.setVisible(true);
Game g = new Game(w);
g.play();
}
});
}
}
Here is the code in which i want to access variable
public class Game {
private wampusGUI gui;
public Game(wampusGUI w) {
world = new World();
world.start();
gui = w;
}
public void play() {
gui.setTextArea(welcome());
gui.setTextArea(describe());
for (;;) {
String s = userCommand; // here value should come should
System.out.println(userCommand);
Command c = Command.create(s);
String r = c.perform(world);
// is game over?
if (r == null) {
break;
}
System.out.println(r);
}
System.out.println("Game over");
}
}
However, i can pass the variable from first class as a argument. but the problem is that, when i will run program the value is going null first time, which i dont want. i want when i enter value in textfield then it should go to another class.
Thank you.
Looking at your code, it seems you want to show dialogs to your user with a certain text
gui.setTextArea(welcome());
gui.setTextArea(describe());
and sometimes, that dialog should capture user input which is handled afterwards.
Those setTextArea calls are not what you want to use. The user will never see the welcome message as it will immediately be replaced by the describe message.
Make sure you do not block the Event Dispatch Thread (EDT) or nothing will be shown at all. I do not know what your Command class will do, but I see an infinite loop on the Event Dispatch Thread which is never a good thing. Take a look at the Concurrency in Swing tutorial for more information
Thanks to that for loop, the user will simply not be capable to input any command as the EDT is busy handling your loop. What you need is a blocking call allowing the user to provide input (not blocking the EDT, but just blocking the execution of your code). The static methods in the JOptionPane class are perfectly suited for this (e.g. the JOptionPane#showInputDialog). These methods also have a mechanism to pass the user input back to the calling code without any static variables, which solves your problem.
I suggest that you use a listener of one sort or another to allow the Game object to listen for and respond to changes in the state of the GUI object. There are several ways to do this, but one of the most elegant and useful I've found is to use Swing's own innate PropertyChangeSupport to allow you to use PropertyChangeListeners. All Swing components will allow you to add a PropertyChangeListener to it. And so I suggest that you do this, that you have Game add one to your WampusGUI class (which should be capitalized) object like so:
public Game(WampusGUI w) {
gui = w;
gui.addPropertyChangeListener(new PropertyChangeListener() {
// ....
}
This will allow Game to listen for changes in the gui's state.
You'll then want to make the gui's userCommand String a "bound property" which means giving it a setter method that will fire the property change support notifying all listeners of change. I would do this like so:
public class WampusGUI extends JFrame {
public static final String USER_COMMAND = "user command";
// ....
private void setUserCommand(String userCommand) {
String oldValue = this.userCommand;
String newValue = userCommand;
this.userCommand = userCommand;
firePropertyChange(USER_COMMAND, oldValue, newValue);
}
Then you would only change this String's value via this setter method:
private void enterButtonActionPerformed(java.awt.event.ActionEvent evt) {
setUserCommand(commandText.getText());
}
The Game's property change listener would then respond like so:
gui.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
// is the property being changed the one we're interested in?
if (WampusGUI.USER_COMMAND.equals(pcEvt.getPropertyName())) {
// get user command:
String userCommand = pcEvt.getNewValue().toString();
// then we can do with it what we want
play(userCommand);
}
}
});
One of the beauties of this technique is that the observed class, the GUI, doesn't have to have any knowledge about the observer class (the Game). A small runnable example of this is like so:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
public class WampusGUI extends JFrame {
public static final String USER_COMMAND = "user command";
private String userCommand;
private JTextArea displayTextArea = new JTextArea(10, 30);
private JTextField commandText = new JTextField(10);
public WampusGUI() {
initComponents();
}
private void setUserCommand(String userCommand) {
String oldValue = this.userCommand;
String newValue = userCommand;
this.userCommand = userCommand;
firePropertyChange(USER_COMMAND, oldValue, newValue);
}
private void initComponents() {
displayTextArea.setEditable(false);
displayTextArea.setFocusable(false);
JButton enterButton = new JButton("Enter Command");
enterButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
enterButtonActionPerformed(evt);
}
});
JPanel commandPanel = new JPanel();
commandPanel.add(commandText);
commandPanel.add(Box.createHorizontalStrut(15));
commandPanel.add(enterButton);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainPanel.add(new JScrollPane(displayTextArea));
mainPanel.add(commandPanel, BorderLayout.SOUTH);
add(mainPanel);
}
public void setTextArea(String text) {
displayTextArea.append(text);
}
private void enterButtonActionPerformed(java.awt.event.ActionEvent evt) {
setUserCommand(commandText.getText());
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
WampusGUI w = new WampusGUI();
w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
w.pack();
w.setLocationRelativeTo(null);
w.setVisible(true);
Game g = new Game(w);
g.play();
}
});
}
}
class Game {
private WampusGUI gui;
public Game(WampusGUI w) {
gui = w;
gui.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
// is the property being changed the one we're interested in?
if (WampusGUI.USER_COMMAND.equals(pcEvt.getPropertyName())) {
// get user command:
String userCommand = pcEvt.getNewValue().toString();
// then we can do with it what we want
play(userCommand);
}
}
});
}
public void play() {
gui.setTextArea("Welcome!\n");
gui.setTextArea("Please enjoy the game!\n");
}
public void play(String userCommand) {
// here we can do what we want with the String. For instance we can display it in the gui:
gui.setTextArea("User entered: " + userCommand + "\n");
}
}
I agree with Jon Skeet that this is not a good solution...
But in case u want an dirty solution to ur problem then u can try this:
public class wampusGUI extends javax.swing.JFrame
{
private static wampusGUI myInstance;
public wampusGUI( )
{
myInstance = this;
initComponents();
}
public static void getUserCommand()
{
if(myInstance!=null)
{
return myInstance.commandText.getText();
}
else
{
return null;
}
}
......
......
}
in the other class use:
public void play()
{
.....
//String s = userCommand; // here value should come should
String s = wampusGUI.getUserCommand();
.....
}
This kind of code is there in some of our legacy projects... and I hate this.
So, what I have is a program that plots Phase trajectories. At the moment the starting points are all random, but what I am trying to add is a way for the program to start a trajectory from the point I click on. I've been fiddling with it for hours, trying everything I know, well here's the code:
public static void click(final double r, final double t) {
MouseListener mus = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
double r = e.getX();
double t = e.getY();
}
};
}
public Vector<Graph> getGraphs() {
// ... bunch of code that draws the graph...
g.add(new Graph.Line());
g.lastElement().add(r, t);
g.lastElement().setColor(Color.blue);
And what it tells me is that r and t can't be found. I realize that it might be hard to help without the whole code, but it is loads of code, I can email it to someone if you are really willing to help. But in any other case, anyone got an idea what I can do?
1) r and t are not in scope for your getGraphs() method.
2) You don't seem to have registered your mouse adapter as a MouseListener anywhere
3) It is not clear how the click() method gets called
You need to capture the mouse clicks from a window component, let's say it is a JPanel that you are using.
Then your code would look something like this:
public class MyApplication {
private JFrame myWindow = new JFrame("My Application");
private JPanel myPanelYouCanClick = new JPanel();
public MyApplication() {
myWindow.setContantPane(myPanelYouCanClick);
myPanelYouCanClick.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
double r = e.getX();
double t = e.getY();
// Code to create your new trajectory called from here, pass
// in the values of r and t if required. Remember you are
// running on the event dispatcher thread!
}
});
myWindow.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MyApplication app = new MyApplication();
}
});
}
}