Jbutton that draws on a new Jpanel - java

i'd like this button to (on click) draw an Oval. Problem is that eclipse says something about missing semicolons (in the action listener definition) and i dont understand why. Whats the proper way of passing methods (bulid in or custom) to the action listeners?
public class figury implements ActionListener {
public figury() {
frame();
}
public void frame() {
JFrame f = new JFrame();
f.setVisible(true);
f.setSize(480, 480);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel();
JButton kolo = new JButton("Rysuj kolo");
JButton kolo = new JButton("Rysuj kwadrat");
kwadrat.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
public void paintComponent(Graphics g){
g.fillOval(50,50,100,100);
g.setColor(Color.RED);
}
}
});
p.add(kolo);
f.add(p);
}
public static void main(String[] args) {
new figury();
}
}

You are trying to define a method inside another method there. In your case, the problem is in the line containing
public void paintComponent(Graphics g) {
...
This cannot be defined inside another method in java. There are good ideas for painting in java in these official documentation links and stackoverflow questions:
How to make canvas with Swing?
http://www.oracle.com/technetwork/java/painting-140037.html

If your figury class implements ActionListener, it should implement public void actionPerformed(ActionEvent e) method.
Also you are trying to declare a method paintComponent() inside another actionPerformed() method.
I think your code should look something like this:
public class figury implements ActionListener {
public figury() {
frame();
}
public void frame() {
JFrame f = new JFrame();
f.setVisible(true);
f.setSize(480, 480);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel();
JButton kolo = new JButton("Rysuj kolo");
JButton kwadrat = new JButton("Rysuj kwadrat");
kwadrat.addActionListener(this);
p.add(kolo);
p.add(kwadrat);
f.add(p);
}
#Override
public void actionPerformed(ActionEvent e) {
paintComponent(/*pass here a Graphics object*/);
}
public void paintComponent(Graphics g) {
g.fillOval(50,50,100,100);
g.setColor(Color.RED);
}
public static void main(String[] args) {
new figury();
}
}

Related

Gui graphic does not appear in Panel

I am trying to make a drawOval moving by using the two buttons that I set to be North and East so the ball will move between the JButtons, at the center.
Why does not appear at the panel?
Also I am thinking using a function that make this x=x+; and y=y+1 when I pressed left or right.
I do not figure out what can I do.
So this is the code I made:
public class Main extends JFrame implements ActionListener {
JButton left;
JButton right;
JPanel p;
Main(){
JButton left = new JButton("left");
left.addActionListener(this);
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
//The first way I think is better to make it move.
}
});
JButton right = new JButton("right");
right.addActionListener(this);
Panel p = new Panel();
p.setLayout(new BorderLayout());
p.add("West",left);// to the left
p.add("East",right);//to the right
Container c = getContentPane();
c.add(p);
}
public static void main(String[] args) {
Main f=new Main();
f.setTitle("Heracles");
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true); //this is the window
}
public void paintComponent (Graphics g) {
super.paintComponents(g);
Graphics2D g1=(Graphics2D) g;
g.drawOval(3, 5, 45, 46); // The ball
g.fillOval(20, 30, 40, 40);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
To understand why it's not working, you need to understand how the paint system actually works
Just by looking at this snippet it should be obvious something is wrong.
public class Main extends JFrame implements ActionListener {
//...
public void paintComponent (Graphics g) {
super.paintComponents(g);
//...
}
}
You've declare a method called paintComponent but are calling the super method paintComponents (note the s at the end).
Further, when ever you "think" you're overriding a method, you should make use of the #Override attribute, this will cause a compiler error when you've done something wrong
public class Main extends JFrame implements ActionListener {
//...
#Overrride
public void paintComponent (Graphics g) {
super.paintComponents(g);
//...
}
}
The above code will now fail to compile, as JFrame doesn't declare a paintComponent method.
As a general rule, you should avoid extending directly from JFrame (or other top level containers), they are compound components and have a complex hierarchy and functionality.
A better place to start might be with a JPanel
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
JButton left;
JButton right;
JPanel paintPane;
public TestPane() {
JButton left = new JButton("left");
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
}
});
JButton right = new JButton("right");
right.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
paintPane = new PaintPane();
setLayout(new BorderLayout());
add(left, BorderLayout.WEST);
add(right, BorderLayout.EAST);
add(paintPane);
}
}
public class PaintPane extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g1 = (Graphics2D) g;
g1.drawOval(3, 5, 45, 46); // The ball
g1.fillOval(20, 30, 40, 40);
}
}
}
You should take the time to have a look at Painting in Swing and Performing Custom Painting for more details.
Some other concepts you might like to take the time to learn:
Single Responsibility Principle - a class should do one thing and do it well
Observer Pattern - This typically represent in Swing as the listener API
Model-View-Controller - this encompasses the above and defines different layers of responsibility for different parts of the program, it will helper you understand the basic structure of Swing as well
Also I am thinking using a function that make this x=x+; and y=y+1 when I pressed left or right.
Ok, so this is where the "model" part of the MVC will play it's part.
So lets start by defining the basic properties we expect the model to support...
public interface ShapeModel {
public Point getPoint();
public void addChangeListener(ChangeListener listener);
public void removeChangeListener(ChangeListener listener);
}
Here is supports a Point to act as the location and a ChangeListener to act as the observer pattern, which will notify interested parties that the state of the model has changed.
Why start with a interface? As a general concept, you should always prefer to code to interface instead of implementation. In this case, one aspect of the interface which hasn't been defined is, how does the Point get updated? That's of little interest to most parties who want to work with the model, they just want to know when it changes, the mutation of the model can be expressed either directly via the implementation or a "mutable" interface which extends from the this interface
Next, we define a default implementation...
public class DefaultShapeModel implements ShapeModel {
private Point point = new Point(40, 40);
private List<ChangeListener> listeners = new ArrayList<>(25);
#Override
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
fireStateChanged();
}
protected void fireStateChanged() {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : listeners) {
listener.stateChanged(evt);
}
}
#Override
public void addChangeListener(ChangeListener listener) {
listeners.add(listener);
}
#Override
public void removeChangeListener(ChangeListener listener) {
listeners.remove(listener);
}
}
This does define how the paint is to be updated.
Finally, we update the TestPane and PaintPane to support the model...
public class TestPane extends JPanel {
JButton left;
JButton right;
JPanel paintPane;
private DefaultShapeModel model;
public TestPane() {
model = new DefaultShapeModel();
JButton left = new JButton("left");
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
Point p = model.getPoint();
p.x--;
if (p.x > 0) {
p.x = 0;
}
model.setPoint(p);
}
});
JButton right = new JButton("right");
right.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Point p = model.getPoint();
p.x++;
if (p.x + 40 > paintPane.getWidth()) {
p.x = paintPane.getWidth() - 40;
}
model.setPoint(p);
}
});
paintPane = new PaintPane(model);
setLayout(new BorderLayout());
add(left, BorderLayout.WEST);
add(right, BorderLayout.EAST);
add(paintPane);
}
}
public class PaintPane extends JPanel {
private ShapeModel model;
public PaintPane(ShapeModel model) {
this.model = model;
this.model.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
repaint();
}
});
}
public ShapeModel getModel() {
return model;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g1 = (Graphics2D) g;
Point p = getModel().getPoint();
g1.fillOval(p.x, p.y, 40, 40);
g1.setColor(Color.WHITE);
g1.drawOval(p.x, p.y, 40, 40);
}
}
Why does not appear at the panel?
To display graphic you created, use follow these steps,
Remove paintComponent method and replace it with below code..
public JComponent createOvel() {
return new JComponent() {
#Override
protected void paintComponent(Graphics g) {
Graphics2D g1 = (Graphics2D) g;
g.drawOval(3, 5, 45, 46); // The ball
g.fillOval(20, 30, 40, 40);
}
};
}
Then call it in Main() constructor,
p.add("Center", createOvel());
This will display the graphic you created.

Want to create a frame taking mouse input and implements drawLines()

I am trying to create a frame that is taking input from mouse and also make x/o grid on frame using drawLines(). But I am able to do only one of the two.
Here is my code:
public class Test extends JPanel {
public static void main(String[] args) {
Test t = new Test();
t.dispFrame();
}
public static void dispFrame()
{
JFrame frame = new JFrame("My New Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(300, 300));
frame.setResizable(false);
JPanel panel=new JPanel();
panel.addMouseListener(new MouseListener()
{
#Override
public void mouseClicked(MouseEvent e) {
System.out.println(":MOUSE_CLICK_EVENT:");
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("\n:MOUSE_PRESSED_EVENT:");
}
#Override
public void mouseReleased(MouseEvent e) {
System.out.println(":MOUSE_RELEASED_EVENT:");
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println(":MOUSE_ENTER_EVENT:");
}
#Override
public void mouseExited(MouseEvent e) {
System.out.println(":MOUSE_EXITED_EVENT:");
}
});
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(30,100,270,100);
g.drawLine(30,200,270,200);
g.drawLine(100,35,100,250);
g.drawLine(200,35,200,250);
}
}
If you want to override the paintComponent() method on your panel, you should do something like this,
JPanel panel = new JPanel() {
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(30,100,270,100);
g.drawLine(30,200,270,200);
g.drawLine(100,35,100,250);
g.drawLine(200,35,200,250);
}
};
In your code, your are overriding the paintComponent() in your Test class, which will throw a compile time error if your Test class itself is not a subclass Component.

What is the proper way to swap out an existing JPanel in a JFrame with another?

I'm building a program that requires swapping out the current, visible JPanel with another. Unfortunately there seems to be multiple to go about this and all of my attempts have ended in failure. I can successfully get the first JPanel to appear in my JFrame, but swapping JPanels results in a blank JFrame.
My Main JFrame:
public class ShellFrame {
static CardLayout cl = new CardLayout(); //handles panel switching
static JFrame frame; //init swing on EDT
static MainMenu mm;
static Panel2 p2;
static Panel3 p3;
public static void main(String[] args) {
initFrame();
}
public static void initFrame() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame = new JFrame();
frame.setDefaultCloseOperation(3);
frame.setLayout(cl);
mm = new MainMenu();
pp = new PlacementPanel();
//first panel added to frame will always show first
frame.add(mm, "MainMenu");
frame.pack(); //sizes frame to fit the panel being shown
frame.setVisible(true);
}
});
}
public static void switchPanel(String name) {
cl.show(frame.getContentPane(), name);
frame.pack();
}
public static void updatePanel2(/* args */) {
frame.removeAll();
p2 = new Panel2(/* args */);
frame.add(pp, "PlacementPanel");
frame.pack();
frame.validate();
frame.repaint();
}
I'm trying to use updatePanel2 to swap out the existing panel with a new Panel2 but It doesn't seem to be working. Panel2 works fine on it's own but trying to use it in conjunction with my program simply yields a blank window. Any help would be greatly appreciated!
that requires swapping out the current, visible JPanel with another
Have a look at CardLayout for a complete example of how to do it properly.
I have a Swing app which 'swaps' Panels when the user press the 'SPACE' key, showing a live plot of a running simulation. What i did goes like this:
public class MainPanel extends JPanel implements Runnable {
// Called when the JPanel is added to the JFrame
public void addNotify() {
super.addNotify();
animator = new ScheduledThreadPoolExecutor(1);
animator.scheduleAtFixedRate(this, 0, 1000L/60L, TimeUnit.MILLISECONDS);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (spacePressed)
plot.render(g);
else
simulation.render(g);
}
public void run() {
simulation.update();
repaint();
}
}
public class PlotView {
public void render(Graphics g) {
//draw the plot here
}
}
public class SimulationView {
public void render(Graphics g) {
//draw simulation here
}
}
This works very well for my 'show live plot' problem. And there's also the CardLayout approach, which you may turn into a new separate question if you having trouble. Good luck!
You should do .setVisible(false); to the panel which you want to be replaced.
Here is a working example, it switches the panels when you press "ENTER";
If you copy this in an IDE, automatically get the imports (shift+o in Eclipse);
public class MyFrame extends JFrame implements KeyListener {
private JButton button = new JButton("Change Panels");
private JPanel panelOnFrame = new JPanel();
private JPanel panel1 = new JPanel();
public MyFrame() {
// adding labels to panels, to distinguish them
panelOnFrame.add(new JLabel("panel on frame"));
panel1.add(new JLabel("panel 1"));
setSize(new Dimension(250,250));
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(button);
add(panelOnFrame);
setVisible(true);
addKeyListener(this);
addKeyListener(this);
setFocusable(true);
}
public static void main(String[] args) {
MyFrame frame = new MyFrame();
}
#Override
public void keyPressed(KeyEvent k) {
if(k.getKeyCode() == KeyEvent.VK_ENTER){
//+-------------here is the replacement:
panelOnFrame.setVisible(false);
this.add(panel1);
}
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}

Running a class as a JApplet or a JFrame?

If I want to make a class that can be run as both an JApplet and JFrame I thought that all the class had to do was extend the JApplet. I had asked this question in a post earlier but I am not sure how to extends this question to that question. I have the life cycle of an applet included in this code and along with the main method.
import java.awt.*;
import java.applet.Applet;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LifeCycle extends Applet
{
private static final long serialVersionUID = 1L;
String output = "test";
String event;
public void init()
{
gui(); //I am not certain if this needs to be there.
event = "\nInitializing...";
printOutput();
}
public void start()
{
event = "\nStarting...";
printOutput();
}
public void stop()
{
event = "\nStopping...";
printOutput();
}
public void destroy()
{
event = "\nDestroying...";
printOutput();
}
private void printOutput()
{
System.out.println(event);
output += event;
repaint();
}
private void gui() {
JFrame f = new JFrame("Not resizable");
JPanel d = new JPanel();
d.setBackground(Color.BLACK);
f.add(d);
f.setSize(745,440);
f.setResizable(false);
f.setLocationRelativeTo(null);
f.setTitle("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g)
{
System.out.println("Graphics Paint Method!");
g.drawString(output, 100, 100);
}
public static void main(String[] args) {
LifeCycle l = new LifeCycle();
l.gui();
}
}
If you need something that can be run in a JFrame or a JApplet, put all the logic and things into a JPanel and depending on which you want make either a JFrame or a JApplet and add the JPanel to either.
Edit for all those lifecycle things, you can have either the applet or frame call them as necessary on your panel.
Edit: example
public class MyPanel extends JPanel {
public MyPanel()
{
setBackground(Color.BLACK);
setForeground(Color.WHITE);
}
String output = "test";
String event;
public void init()
{
event = "\nInitializing...";
printOutput();
}
// Put all the other methods in here too
private void printOutput()
{
System.out.println(event);
output += event;
repaint();
}
#Override
public void paintComponent(Graphics g)
{
System.out.println("Graphics Paint Method!");
g.setColor(this.getBackground());
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(this.getForeground());
g.drawString(output, 100, 100);
}
}
public class MyFrame extends JFrame {
MyPanel myPanel;
public MyFrame()
{
super("Test frame");
setSize(745,440);
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myPanel=new MyPanel();
add(myPanel,BorderLayout.CENTER);
}
public static void main(String[] args)
{
MyFrame f = new MyFrame();
f.setVisible(true);
}
}
public class MyApplet extends JApplet {
private static final long serialVersionUID = 1L;
MyPanel myPanel;
#Override
public void init()
{
myPanel = new MyPanel();
getContentPane().add(myPanel,BorderLayout.CENTER);
}
}
Then add methods to JFrame and JApplet to call the relevant methods on myPanel
For JFrame I recommend WindowListener and whatnot. For JApplet you can just have the init, start, destroy and stop methods to call those methods on the panel.
For WindowListener or perhaps more conveniently WindowAdapter, this link seems to be a good reference: http://way2java.com/awt-components/java-frame-closing-windowadapter/
Simply add() the applet to a JFrame and then call the applet's life cycle methods on the appropriate events (init() after you construct it, destroy() when the frame is closing etc)
Edit: yes the call to gui() should be there and not in main

how to simply implement a KeyListener?

public class MyPanel extends JPanel implements KeyListener {
private char c = 'e';
public MyPanel() {
this.setPreferredSize(new Dimension(500,500));
addKeyListener(this);
}
public void paintComponent(Graphics g) {
super.repaint();
g.drawString("the key that pressed is" + c, 250,250);
}
public void keyPressed(KeyEvent e) {
c=e.getKeyChar();
repaint();
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
c=e.getKeyChar();
repaint();
}
public static void main(String[] s) {
JFrame f=new JFrame();
f.getContentPane().add(new MyPanel());
f.pack();
f.setVisible(true);
}
}
I tried reading this yet didnt mange to understand how to simply implement a KeyListener. so what do i need to change for this to work?
Here are the reasons why it doesn't work:
The JPanel does not have the keyboard focus. (The frame has it.) You probably want to requestFocus when the panel is added to the screen.
You need to call repaint when the graphic should change.
You mustn't call repaint in the paintComponent method.
You need to clear the drawing area before drawing the string again (otherwise all characters will end up on top of each other).
Here's a complete working example:
class MyPanel extends JPanel implements KeyListener {
private char c = 'e';
public MyPanel() {
this.setPreferredSize(new Dimension(500, 500));
addKeyListener(this);
}
public void addNotify() {
super.addNotify();
requestFocus();
}
public void paintComponent(Graphics g) {
g.clearRect(0, 0, getWidth(), getHeight());
g.drawString("the key that pressed is " + c, 250, 250);
}
public void keyPressed(KeyEvent e) { }
public void keyReleased(KeyEvent e) { }
public void keyTyped(KeyEvent e) {
c = e.getKeyChar();
repaint();
}
public static void main(String[] s) {
JFrame f = new JFrame();
f.getContentPane().add(new MyPanel());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
Oh, and you may want to add f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) to make the application terminate when you close the window. :-)

Categories