JMenuBar with paint method - java

I'm having trouble getting my JMenuBar to appear alongside my paint() method.
package Main;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
public class Main extends JFrame{
int x, y; // axis position for oval
//JMenuBar Variables
JMenuBar menuBar;
JMenu file;
JMenuItem newGame;
JMenuItem checkScore;
JMenuItem exitGame;
// DOUBLE BUFFERING
private Image dbImage;
private Graphics dbGraphics;
Font font = new Font("Arial", Font.ITALIC, 30);
// KeyListener Class
public class KeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT){
if(x <=0){ // FRAME COLLISION DETECTION
x=0;
}else
x += -5; //decrement position to the left
}
if(keyCode == e.VK_RIGHT){
if(x >= 380){
x = 380;
}else
x += +5; //incrementing position to the right
}
if(keyCode == e.VK_UP){
if (y <= 25){
y = 25;
}else
y += -5; //decrementing position up
}
if(keyCode == e.VK_DOWN){
if(y >= 380){
y = 380;
}else
y += +5; //incrementing position down
}
}
}
// CONSTRUCTOR
public Main(){
// Window Properties
addKeyListener(new KeyListener()); // creates instance of KeyListener class
setTitle("Tower Defence");
setSize(400, 400);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//setBackground(Color.CYAN);
// JMenuBar
menuBar = new JMenuBar();
file = new JMenu("File");
newGame = new JMenuItem("New Game");
checkScore = new JMenuItem("Check High Scores");
exitGame = new JMenuItem("Close Game");
menuBar.add(file);
file.add(newGame);
file.add(checkScore);
file.addSeparator();
file.add(exitGame);
setJMenuBar(menuBar);
// Display frame after all components added
setVisible(true);
// default position for oval
x = 150;
y = 150;
}
public void paint(Graphics g){
dbImage = createImage(getWidth(), getHeight()); // creates image of screen
dbGraphics = dbImage.getGraphics(); // gets graphics to be drawn in off screen image
paintComponent(dbGraphics); // paints graphics
g.drawImage(dbImage, 0, 0, this); // draw image to the visible screen
}
// PAINT GRAPHICS TO SCREEN
public void paintComponent(Graphics g){
g.setFont(font);
g.drawString("Hello World", 100, 200);
g.setColor(Color.red);
g.drawOval(x, y, 15, 15);
g.fillOval(x, y, 15, 15);
repaint();
}
// MAIN METHOD
public static void main(String[] args) {
new Main();
}
}
I saw a different question where the solution was to override the paint method and add super.paint(g);
when i tried this the JMenuBar appears but the frame keeps flickering constantly.

Heck, I'll throw my code in the ring. Recs as per my comments. Also, don't use KeyListeners but rather Key Bindings.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.RenderingHints;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class Main2 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int OVAL_W = 15;
private int x = 150;
private int y = 150;
private JMenuBar menuBar;
private JMenu file;
private JMenuItem newGame;
private JMenuItem checkScore;
private JMenuItem exitGame;
private Font font = new Font("Arial", Font.ITALIC, 30);
public Main2() {
menuBar = new JMenuBar();
file = new JMenu("File");
newGame = new JMenuItem("New Game");
checkScore = new JMenuItem("Check High Scores");
exitGame = new JMenuItem("Close Game");
menuBar.add(file);
file.add(newGame);
file.add(checkScore);
file.addSeparator();
file.add(exitGame);
addKeyBinding();
}
public JMenuBar getMenuBar() {
return menuBar;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setFont(font);
g.drawString("Hello World", 100, 200);
g.setColor(Color.red);
g.drawOval(x, y, OVAL_W, OVAL_W);
g.fillOval(x, y, OVAL_W, OVAL_W);
}
private void addKeyBinding() {
int condition = WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
for (final MyDirection dir : MyDirection.values()) {
KeyStroke keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0);
inputMap.put(keyStroke, dir.toString());
actionMap.put(dir.toString(), new AbstractAction() {
#Override
public void actionPerformed(ActionEvent evt) {
int newX = x + dir.getxTrans();
int newY = y + dir.getyTrans();
newX = Math.min(newX, PREF_W - 2 * OVAL_W);
newX = Math.max(newX, OVAL_W);
newY = Math.min(newY, PREF_H - 2 * OVAL_W);
newY = Math.max(newY, OVAL_W);
x = newX;
y = newY;
repaint();
}
});
}
}
enum MyDirection {
UP(KeyEvent.VK_UP, 0, -5), DOWN(KeyEvent.VK_DOWN, 0, 5),
LEFT(KeyEvent.VK_LEFT, -5, 0), RIGHT(KeyEvent.VK_RIGHT, 5, 0);
private int keyCode;
private int xTrans;
private int yTrans;
private MyDirection(int keyCode, int xTrans, int yTrans) {
this.keyCode = keyCode;
this.xTrans = xTrans;
this.yTrans = yTrans;
}
public int getKeyCode() {
return keyCode;
}
public int getxTrans() {
return xTrans;
}
public int getyTrans() {
return yTrans;
}
}
private static void createAndShowGui() {
Main2 main = new Main2();
JFrame frame = new JFrame("Main2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(main);
frame.setJMenuBar(main.getMenuBar());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Dont extend JFrame unnecessarily
Dont overide any paint method of JFrame unnecessarily rathe add Jpanel and override paintComponent
Dont call repaint(...) in paintComponent(...) as this will cause a loop i.e repaint will re-call paintComponent and the cycle will carry on
Create and manipulate Swing components on Event Dispatch Thread
Dont call setSize(..) on JFrame rather override getPreferredSize and return an appropriate size which fits all drawings and than call JFrame#pack() before setting JFrame visible
Dont use KeyListener/KeyAdapter for Swing components rather use KeyBindings
Here is your code fixed:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class Main extends JPanel {
int x, y; // axis position for oval
//JMenuBar Variables
JMenuBar menuBar;
JMenu file;
JMenuItem newGame;
JMenuItem checkScore;
JMenuItem exitGame;
Font font = new Font("Arial", Font.ITALIC, 30);
// KeyBindings Class
public class KeyBindings {
public KeyBindings(final JComponent jc) {
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "Right");
jc.getActionMap().put("Right", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
if (x >= 380) {
x = 380;
} else {
x += +5; //incrementing position to the right
}
jc.repaint();
}
});
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "Left");
jc.getActionMap().put("Left", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
if (x <= 0) { // FRAME COLLISION DETECTION
x = 0;
} else {
x += -5; //decrement position to the left
}
jc.repaint();
}
});
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "Up");
jc.getActionMap().put("Up", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
if (y <= 25) {
y = 25;
} else {
y += -5; //decrementing position up
}
jc.repaint();
}
});
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "Down");
jc.getActionMap().put("Down", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
if (y >= 380) {
y = 380;
} else {
y += +5; //incrementing position down
}
jc.repaint();
}
});
}
}
// CONSTRUCTOR
public Main() {
// Window Properties
JFrame frame = new JFrame();
frame.setTitle("Tower Defence");
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//setBackground(Color.CYAN);
// JMenuBar
menuBar = new JMenuBar();
file = new JMenu("File");
newGame = new JMenuItem("New Game");
checkScore = new JMenuItem("Check High Scores");
exitGame = new JMenuItem("Close Game");
menuBar.add(file);
file.add(newGame);
file.add(checkScore);
file.addSeparator();
file.add(exitGame);
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setFont(font);
g.drawString("Hello World", 100, 200);
g.setColor(Color.red);
g.drawOval(x, y, 15, 15);
g.fillOval(x, y, 15, 15);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
};
//add keybindings
new KeyBindings(panel);
frame.add(panel);
frame.setJMenuBar(menuBar);
frame.pack();
// Display frame after all components added
frame.setVisible(true);
// default position for oval
x = 150;
y = 150;
}
// MAIN METHOD
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Main();
}
});
}
}

Related

Repaint method not working on JComponent java swing

I want to have a text field to input an integer, then select 1) Grow or 2) Shrink, and then click the button so that the circle gets redrawn on the screen based on the selected options.
I don't know why it isn't repaining. (Don't worry about the layout, just want to get it to work first)
My Frame:
public class Main {
public static void main(String[] args) {
var frame = new JFrame();
frame.setSize(400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
var circleComp = new circleComponent();
var panel1 = new JPanel();
var multiplierLabel = new JLabel("Grow Multiplier");
var multiplierField = new JTextField(20);
var radio1 = new JRadioButton("Grow Circle");
var radio2 = new JRadioButton("Shrink Circle");
var bg = new ButtonGroup();
bg.add(radio1);
bg.add(radio2);
JButton button = new JButton("Rivizato");
button.addActionListener(
new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(radio1.isSelected()){
rrComp.repaint(0,0,Integer.parseInt(multiplierField.getText())*rrComp.getWidth(), Integer.parseInt(multiplierField.getText())*rrComp.getHeight());
}
else if(radio2.isSelected()){
rrComp.repaint(0,0,Integer.parseInt(multiplierField.getText())/rrComp.getWidth(), Integer.parseInt(multiplierField.getText())/rrComp.getHeight());
}
}
}
);
panel1.add(multiplierLabel);
panel1.add(multiplierField);
panel1.add(button);
panel1.add(radio1);
panel1.add(radio2);
frame.add(panel1);
frame.add(circleComp);
}
}
My CircleComponent class:
public class CircleComponent extends JComponent {
public void paintComponent(Graphics g){
super.paintComponent(g);
var g2 = (Graphics2D) g;
var circle = new Ellipse2D.Double(0,0,100,100);
g2.draw(circle);
}
}
var circle = new Ellipse2D.Double(0,0,100,100); means that your circle will never change size.
You should also be careful with repaint(x, y, width, height) as it could leave regions of your component "dirty". Better to just use repaint.
As a conceptual example...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
private CirclePane circlePane;
public MainPane() {
setLayout(new BorderLayout());
JPanel actionsPane = new JPanel(new GridBagLayout());
JButton growButton = new JButton("Grow");
growButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
circlePane.grow();
}
});
JButton shrinkButton = new JButton("Shrink");
shrinkButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
circlePane.shrink();
}
});
actionsPane.add(growButton);
actionsPane.add(shrinkButton);
circlePane = new CirclePane();
add(circlePane);
add(actionsPane, BorderLayout.SOUTH);
}
}
public class CirclePane extends JPanel {
private Ellipse2D circle;
public CirclePane() {
circle = new Ellipse2D.Double(0, 0, 100, 100);
}
public void grow() {
double width = circle.getWidth() + 10;
double height = circle.getHeight() + 10;
circle.setFrame(0, 0, width, height);
repaint();
}
public void shrink() {
double width = Math.max(0, circle.getWidth() - 10);
double height = Math.max(0, circle.getHeight() - 10);
circle.setFrame(0, 0, width, height);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double x = (getWidth() - circle.getWidth()) / 2d;
double y = (getHeight() - circle.getHeight()) / 2d;
g2d.translate(x, y);
g2d.draw(circle);
g2d.dispose();
}
}
}
nb: I know I've not used JTextField to specify the size of the circle, that's on purpose. You will need to adapt your requirements to work in a similar way - can you see where you might pass parameters to the CirclePane?

Why does the star rotation slows down automatically after some time

I have a program where I have to use internal Timer event to rotate a star in circular motion. There is a button in the frame that changes the direction of the star and a slider which changes the speed of the star rotation.
This is my Main Class
import javax.swing.JFrame;
public class Main {
public static void main(String args[]) {
// Making an instance of the class that makes the frame
MainFrame frame = new MainFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
}
}
MainFrame Class that makes the frame.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
#SuppressWarnings("serial")
public class MainFrame extends JFrame{
private StarGraphics frameStar;
private JButton starToggle;
public JSlider starSpeed;
public MainFrame() {
// Setting some properties of the frame
setTitle("Star Moving with Internal Events");
setLayout(new BorderLayout());
// Initializing the panel which has rotating star
frameStar = new StarPainter(this);
// Adding the bottom toggle button and slider
addToggler();
}
// Getter for the slider value
public int sliderSpeed() {
return starSpeed.getValue();
}
// Adds Button to change the direction of the star
private void addToggler() {
// Adding another jpanel which has layout set to null so i can add button of my size
JPanel panel = new JPanel();
panel.setLayout(null);
panel.setPreferredSize(new Dimension(20,80));
panel.setBackground(Color.WHITE);
// Initializing button and its action listener to change star direction
starToggle = new JButton("Toggle");
starToggle.setBounds(190, 0, 80, 20);
starToggle.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == starToggle) {
frameStar.ChangeDirections();
}
}
});
// Adding button to panel
panel.add(starToggle);
// Adding slider to the panel
addSlider(panel);
// Adding panel to the main Panel at the bottom
add(panel, BorderLayout.SOUTH);
}
private void addSlider(JPanel panel) {
// Adding Slider and it's properties
starSpeed = new JSlider(JSlider.HORIZONTAL, 0, 20, 5);
starSpeed.setMajorTickSpacing(10);
starSpeed.setMinorTickSpacing(1);
starSpeed.setPaintTicks(true);
starSpeed.setPaintLabels(true);
starSpeed.setBounds(70,30,400, 45);
// Adding Slider-ChangeListener to change the rotation speed of the star
starSpeed.addChangeListener(new ChangeListener() { // anonymous inner class
// handle change in slider value
#Override
public void stateChanged(ChangeEvent e) {
frameStar.ChangeSpeed(starSpeed.getValue());
}
}
);
// Adding label besides the slider
JLabel label = new JLabel("Speed : ");
label.setBounds(10 , 10, 80, 80);
panel.add(label);
panel.add(starSpeed);
}
}
Class to create the panel that has star rotation
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class StarGraphics extends JPanel{
private boolean toggleDir = false;
private int speed = 10;
private Timer timer;
protected double angleOfStarRotation = 0;
public StarGraphics(JFrame frame) {
setPreferredSize(new Dimension(500, 470));
setBackground(Color.BLACK);
setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
startTimer();
}
public void startTimer() {
timer = new Timer(speed, new ActionListener() {
public void actionPerformed(ActionEvent e){
// System.out.println(angleOfStarRotation);
if(!toggleDir) //rotates clockwise
angleOfStarRotation = angleOfStarRotation + 1;
else //rotates counterclockwise
angleOfStarRotation = angleOfStarRotation - 1;
// if (angleOfStarRotation == 360 || angleOfStarRotation == -360) // If there is a full circle, it will reset the angle to zero
// angleOfStarRotation = 0;
repaint();
}});
timer.start();
}
public void ChangeSpeed(int newSpeed) {
this.speed = newSpeed;
timer.setDelay(speed);
}
public void ChangeDirections() {toggleDir = !toggleDir; }
}
And a class that paints the star into the panel
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import java.security.SecureRandom;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class StarPainter extends StarGraphics{
private int[] starXPoints = {55, 67, 109, 73, 83, 55, 27, 37, 1, 43};
private int[] starYPoints = {0, 36, 36, 54, 96, 72, 96, 54, 36, 36};
GeneralPath starDesign = new GeneralPath();
public StarPainter(JFrame frame) {
super(frame);
}
public void drawStar(GeneralPath path) {
path.moveTo(starXPoints[0], starYPoints[0]);
for(int i=0; i<10; i++)
path.lineTo(starXPoints[i], starYPoints[i]);
path.closePath();
}
public void starActions(Graphics2D g) {
int startAngle = 360;
// For Random Color
SecureRandom random = new SecureRandom();
// rotate around origin and draw stars in random colors
for (int count = 1; count <= 1; count++)
{
double angle = startAngle - 90;
// rotate coordinate system
g.rotate(angleOfStarRotation * Math.PI / angle); //rotates as per the rotated angle //
// set random drawing color
g.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
// draw filled star
g.fill(starDesign);
// dispose the star
g.dispose();
}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
drawStar(starDesign);
g2d.translate(250,150);
starActions(g2d);
}
}
After running the code, the output will show a frame with coloring star rotating around the panel in circular motion, but after 2 full rotation, the star rotation slow down automatically. Does anyone know why that happens?
Your "core" problem is right here...
public void drawStar(GeneralPath path) {
path.moveTo(starXPoints[0], starYPoints[0]);
for(int i=0; i<10; i++)
path.lineTo(starXPoints[i], starYPoints[i]);
path.closePath();
}
This gets called each time you re-draw the component, which means, you're adding new points to the shape, making it infinitely more complex on each paint pass.
Instead, just create the shape in the constructor...
public StarPainter() {
starDesign.moveTo(starXPoints[0], starYPoints[0]);
for (int i = 0; i < 10; i++) {
starDesign.lineTo(starXPoints[i], starYPoints[i]);
}
starDesign.closePath();
}
As has already been pointed out, you're disposing of a Graphics context which you did not create.
If your going to change the transformation of the context, you should always create a copy of your own, for example...
public void starActions(Graphics2D g) {
int startAngle = 360;
// For Random Color
SecureRandom random = new SecureRandom();
g = (Graphics2D) g.create();
// rotate around origin and draw stars in random colors
//for (int count = 1; count <= 1; count++) {
double angle = startAngle - 90;
// rotate coordinate system
g.rotate(angleOfStarRotation * Math.PI / angle); //rotates as per the rotated angle //
// set random drawing color
g.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
// draw filled star
g.fill(starDesign);
// dispose the star
g.dispose();
//}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.translate(250, 150);
starActions(g2d);
g2d.dispose();
}
Also, passing a reference of the JFrame to the component...
public StarGraphics(JFrame frame) {
setPreferredSize(new Dimension(500, 470));
setBackground(Color.BLACK);
setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
startTimer();
}
is a bad idea. The component has no need for, nor is it its responsibility too, interact with the frame. You're just exposing implementation detail unnecessarily.
Runnable example
import java.awt.BorderLayout;
import java.awt.Color;
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 java.awt.geom.GeneralPath;
import java.security.SecureRandom;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MainFrame frame = new MainFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
}
});
}
public class MainFrame extends JFrame {
private StarGraphics frameStar;
private JButton starToggle;
public JSlider starSpeed;
public MainFrame() {
// Setting some properties of the frame
setTitle("Star Moving with Internal Events");
setLayout(new BorderLayout());
// Initializing the panel which has rotating star
frameStar = new StarPainter();
add(frameStar);
// Adding the bottom toggle button and slider
addToggler();
}
// Getter for the slider value
public int sliderSpeed() {
return starSpeed.getValue();
}
// Adds Button to change the direction of the star
private void addToggler() {
// Adding another jpanel which has layout set to null so i can add button of my size
JPanel panel = new JPanel();
panel.setLayout(null);
panel.setPreferredSize(new Dimension(20, 80));
panel.setBackground(Color.WHITE);
// Initializing button and its action listener to change star direction
starToggle = new JButton("Toggle");
starToggle.setBounds(190, 0, 80, 20);
starToggle.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == starToggle) {
frameStar.ChangeDirections();
}
}
});
// Adding button to panel
panel.add(starToggle);
// Adding slider to the panel
addSlider(panel);
// Adding panel to the main Panel at the bottom
add(panel, BorderLayout.SOUTH);
}
private void addSlider(JPanel panel) {
// Adding Slider and it's properties
starSpeed = new JSlider(JSlider.HORIZONTAL, 0, 20, 5);
starSpeed.setMajorTickSpacing(10);
starSpeed.setMinorTickSpacing(1);
starSpeed.setPaintTicks(true);
starSpeed.setPaintLabels(true);
starSpeed.setBounds(70, 30, 400, 45);
// Adding Slider-ChangeListener to change the rotation speed of the star
starSpeed.addChangeListener(new ChangeListener() { // anonymous inner class
// handle change in slider value
#Override
public void stateChanged(ChangeEvent e) {
frameStar.ChangeSpeed(starSpeed.getValue());
}
}
);
// Adding label besides the slider
JLabel label = new JLabel("Speed : ");
label.setBounds(10, 10, 80, 80);
panel.add(label);
panel.add(starSpeed);
}
}
public class StarGraphics extends JPanel {
private boolean toggleDir = false;
private int speed = 10;
private Timer timer;
protected double angleOfStarRotation = 0;
public StarGraphics() {
setPreferredSize(new Dimension(500, 470));
setBackground(Color.BLACK);
setLayout(new BorderLayout());
startTimer();
}
public void startTimer() {
timer = new Timer(speed, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// System.out.println(angleOfStarRotation);
if (!toggleDir) //rotates clockwise
{
angleOfStarRotation = angleOfStarRotation + 1;
} else //rotates counterclockwise
{
angleOfStarRotation = angleOfStarRotation - 1;
}
System.out.println("tick");
// if (angleOfStarRotation == 360 || angleOfStarRotation == -360) // If there is a full circle, it will reset the angle to zero
// angleOfStarRotation = 0;
repaint();
}
});
timer.start();
}
public void ChangeSpeed(int newSpeed) {
this.speed = newSpeed;
timer.setDelay(speed);
}
public void ChangeDirections() {
toggleDir = !toggleDir;
}
}
public class StarPainter extends StarGraphics {
private int[] starXPoints = {55, 67, 109, 73, 83, 55, 27, 37, 1, 43};
private int[] starYPoints = {0, 36, 36, 54, 96, 72, 96, 54, 36, 36};
GeneralPath starDesign = new GeneralPath();
public StarPainter() {
starDesign.moveTo(starXPoints[0], starYPoints[0]);
for (int i = 0; i < 10; i++) {
starDesign.lineTo(starXPoints[i], starYPoints[i]);
}
starDesign.closePath();
}
public void starActions(Graphics2D g) {
int startAngle = 360;
// For Random Color
SecureRandom random = new SecureRandom();
g = (Graphics2D) g.create();
// rotate around origin and draw stars in random colors
//for (int count = 1; count <= 1; count++) {
double angle = startAngle - 90;
// rotate coordinate system
g.rotate(angleOfStarRotation * Math.PI / angle); //rotates as per the rotated angle //
// set random drawing color
g.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
// draw filled star
g.fill(starDesign);
// dispose the star
g.dispose();
//}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.translate(250, 150);
starActions(g2d);
g2d.dispose();
}
}
}

Why after using method removeAll or remove(panel), I have to click outside the window and then back in for the rect to move

Hi am new to programming and am trying to make a game with a start menu and then if you click "start" the screen clears and shows a rect in a black background that you can move around the screen with VK up/down/left/right.
But every time i click start i have to click outside of the window and then back the window for the rect to move around
I have tried to use getContentPane to add panel to the window but still every time i click start have to click outside and then back in the window to move the rect.
Help, what do i need to fix/add to not click outside of the frame and the back again to move the rect around
Heres my code the menu screen :
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class Menuscreen {
private int WIDTH = 800;
private int HEIGHT = 600;
public void menuscreen () {
//Window
final JFrame window = new JFrame();
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(WIDTH, HEIGHT);
window.setResizable(false);
window.setLocationRelativeTo(null);
//Panel
final JPanel panel = new JPanel();
panel.setBackground(Color.BLACK);
panel.setVisible(true);
panel.setLayout(null);
window.add(panel);
//Title
JLabel label = new JLabel("SNAKE");
panel.add(label);
label.setBounds(290, 5, 204, 73);
label.setFont(new Font("Tahoma", Font.BOLD, 60));
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setForeground(Color.RED);
label.setBackground(Color.red);
//Buttons
//start button
JButton bstart = new JButton ("Start");
panel.add(bstart);
bstart.setBounds(424, 200, 70, 60);
bstart.setVisible(true);
//start button - run snake on click
bstart.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
window.getContentPane().remove(panel);
snake snake = new snake();
window.add(snake);
window.revalidate();
window.repaint();
}
});
//exit button
JButton bexit = new JButton ("Exit");
panel.add(bexit);
bexit.setBounds(290, 200, 70, 60);
bexit.setVisible(true);
//exit button - close on click
bexit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
}
}
and the snake class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
import javax.swing.Timer;
public class snake extends JPanel implements ActionListener, KeyListener {
public void thicks () {}
public snake () {
setBackground(Color.BLACK);
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
//thread = new Thread(this);
// thread.start();
}
private static final long serialVersionUID = 1L;
Timer fps = new Timer( 5, this);
double x =0 , y = 0, speedx = 0, speedy = 0;
public void paintComponent(Graphics g) {
fps.start();
super.paintComponent(g);
g.setColor(Color.blue);
Graphics2D graphics = (Graphics2D) g;
Rectangle2D rect = new Rectangle2D.Double(x, y, 40, 40);
graphics.fill(rect);
}
public void actionPerformed(ActionEvent e) {
if(x < 0 || x > 740 ) {
speedx= -speedx;
}
if(y < 0 || y > 520) {
speedy = -speedy;
}
x += speedx;
y += speedy;
repaint();
}
public void down() {
speedy = 2;
speedx = 0;
}
public void up() {
speedy = -2;
speedx = 0;
}
public void right() {
speedy = 0;
speedx = 2;
}
public void left() {
speedy = 0;
speedx = -2;
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_DOWN) {
down();
}
if(keyCode == KeyEvent.VK_UP) {
up();
}
if(keyCode == KeyEvent.VK_RIGHT) {
right();
}
if(keyCode == KeyEvent.VK_LEFT) {
left();
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public void run() {
}
}
lastly the main
public class Main {
public static void main(String [] args) {
Menuscreen Menuscreen = new Menuscreen();
Menuscreen.menuscreen();
}
}

Swing Components Doubling

So I am trying to create a simple paint program and I have been having a problem. The program has a window, on the left of the window is a bar with pen size control, and the rest of the window is the drawing pane. However, whenever I draw on the pane, the side bar is basically copied onto the pane, but it can be drawn over.
Here is my CHPaint class (main):
package paint;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CHPaint{
JFrame frame;
JLabel penSizeLabel;
PaintPanel panel;
JButton upButton;
JButton downButton;
JPanel left;
JPanel main;
int penSize = 1;
public static void main(String[] args){
CHPaint gui = new CHPaint();
System.out.println("gui built");
gui.go();
}
public void go() {
frame = new JFrame("Caleb's Paint");
panel = new PaintPanel();
upButton = new JButton("Up");
downButton = new JButton("Down");
penSizeLabel = new JLabel("Size: " + penSize);
left = new JPanel();
main = new JPanel();
panel.addMouseListener(new Painting());
panel.addMouseMotionListener(new Painting());
upButton.addActionListener(new UpButton());
downButton.addActionListener(new DownButton());
left.setLayout(new BoxLayout(left, BoxLayout.Y_AXIS));
main.setLayout(new BorderLayout());
left.add(upButton);
left.add(penSizeLabel);
left.add(downButton);
left.setBackground(Color.gray);
penSizeLabel.setBackground(Color.gray);
frame.getContentPane().add(BorderLayout.CENTER, main);
main.add(BorderLayout.WEST, left);
main.add(BorderLayout.CENTER, panel);
frame.setSize(600, 600);
frame.setVisible(true);
}
class UpButton implements ActionListener{
public void actionPerformed(ActionEvent e){
panel.changePenSize(1);
penSize++;
penSizeLabel.setText("Size: " + penSize);
}
}
class DownButton implements ActionListener{
public void actionPerformed(ActionEvent e){
panel.changePenSize(-1);
if (penSize > 1){
penSize--;
}
penSizeLabel.setText("Size: " + penSize);
}
}
class Painting implements MouseListener, MouseMotionListener{
public void mousePressed(MouseEvent e) {
panel.draw(e.getX(), e.getY());
}
public void mouseDragged(MouseEvent e) {
panel.draw(e.getX(), e.getY());
}
public void mouseReleased(MouseEvent e) {
panel.mouseUp();
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
}
}
Here is the class for the drawing panel:
package paint;
import java.awt.*;
import javax.swing.*;
public class PaintPanel extends JPanel {
int drawX = -10;
int drawY = -10;
int oldX = -10;
int oldY = -10;
int penSize = 1;
public void draw(int x, int y){
oldX = drawX;
oldY = drawY;
drawX = x;
drawY = y;
this.repaint();
}
public void mouseUp(){
oldX = -10;
oldY = -10;
drawX= -10;
drawY= -10;
}
public void changePenSize(int p){
if (penSize > 0){
penSize = penSize+p;
}
}
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
if (oldX != -10 && (oldY) != -10){ // If you didn't just start or lift the pen
g2.setStroke(new BasicStroke(penSize, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g.setColor(Color.red);
g.drawLine(oldX, oldY, drawX, drawY);
} else {
g.setColor(Color.red);
g.fillOval(drawX-(penSize/2), drawY-(penSize/2), penSize, penSize);
}
}
}
EDIT:
Sorry, I didn't know the rules here for posting, please forgive me D:. Also, I didn't know what part of the code messed it up so I didn't know what I should cut out. Thanks for your help.
This won't solve your problem but the following is not used anymore:
main.add(BorderLayout.CENTER, panel); // read the API for more info
You should be using:
main.add(panel, BorderLayout.CENTER);
You need to call super.paintComponent() in your paintComponent() method. Among other things, this will clear the JPanel for you.

when press on the button and then start drawing the button also copy in on the panel

I have two JPanels. The first one contains JButtons and in the second simply we can draw on with the Mouse. The problem is when I click on the JButton and start drawing the JButton also draw in on the JPanel. Please do provide me, with some direction, as to where I am not looking at ?
main class
public class LabelDemo extends JFrame {
JPanel p1 = new JPanel();
painter p2 = new painter();
JButton red = new JButton("red");
JButton blue = new JButton(" blue ");
JLabel lbl = new JLabel("Label");
ImageIcon icon = new ImageIcon("image/YouTube.png");
public LabelDemo() {
setLayout(new BorderLayout());
p1.setBorder(new LineBorder(Color.gray));
//jbt1.setIcon(icon);
p1.add(red);
p1.add(blue);
lbl.setOpaque(true);
lbl.setBackground(Color.yellow);
p1.add(lbl);
p1.setBounds(20, 30, 40, 78);
add(p1,BorderLayout.EAST);
add(p2,BorderLayout.CENTER);
}
public static void main(String[] args){
LabelDemo frame = new LabelDemo();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700, 400);
frame.setLocationRelativeTo(null);
}
}
innr class
class painter extends JPanel {
int x , y;
boolean isPresed = false;
public void setPainter(int x , int y) {
this.x = x;
this.y = y;
}
public painter() {
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
isPresed = true;
setPainter(e.getX(),e.getY());
repaint();
}
});
}
protected void paintComponent(Graphics g){
Color randomColor = Color.getHSBColor( (float)Math.random(), 1.0F, 1.0F );
if(isPresed){
g.setColor(randomColor);
g.fillOval(x-5, y-5, 10, 10);
}
}
}//end of painter
Ok, as I understood you want to get rid of panel on east (p1 panel) when clicking red or blue button:
package stack;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class LabelDemo extends JFrame {
JPanel p1 = new JPanel();
Painter p2 = new Painter();
JButton red = new JButton("red");
JButton blue = new JButton(" blue ");
JLabel lbl = new JLabel("Label");
ImageIcon icon = new ImageIcon("image/YouTube.png");
public LabelDemo() {
setLayout(new BorderLayout());
p1.setBorder(new LineBorder(Color.gray));
// jbt1.setIcon(icon);
p2.setPreferredSize(new Dimension(600,400));
p1.add(red);
p1.add(blue);
lbl.setOpaque(true);
lbl.setBackground(Color.yellow);
p1.add(lbl);
p1.setBounds(20, 30, 40, 78);
add(p1,BorderLayout.EAST);
add(p2,BorderLayout.CENTER);
red.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
remove(p1);
repaint();
revalidate();
}
});
blue.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
remove(p1);
repaint();
revalidate();
}
});
}
public static void main(String[] args){
LabelDemo frame = new LabelDemo();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
class Painter extends JPanel {
int x , y;
boolean isPresed = false;
public void setPainter(int x , int y) {
this.x = x;
this.y = y;
}
public Painter() {
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
isPresed = true;
setPainter(e.getX(),e.getY());
repaint();
}
});
}
protected void paintComponent(Graphics g){
Color randomColor = Color.getHSBColor( (float)Math.random(), 1.0F, 1.0F );
if(isPresed){
g.setColor(randomColor);
g.fillOval(x-5, y-5, 10, 10);
}
}
}//end of painter
Also don't call setSize() method call pack() and setPreferredSize(), I was personaly criticized a few times because of that. Just an annotation.
In your painter pane's paintComponent method, you really should call super.paintComponent first.
Swing reuses the Graphics, so its possible to get old content still in its buffer. If you call super.paintComponent, this will clean it up for
protected void paintComponent(Graphics g){
// Must call super.paintComponent() so the Graphics is updated correctly...
super.paintComponent();
Color randomColor = Color.getHSBColor( (float)Math.random(), 1.0F, 1.0F );
if(isPresed){
g.setColor(randomColor);
g.fillOval(x-5, y-5, 10, 10);
}
}

Categories

Resources