When I use repaint() in the swing timer method startTimer, it just simply doesnt call paintcomponent(). Everything works inside of the timer method except repaint(). Im pretty new at java so if anyone could help me with this problem or point out any other errors I would greatly appreciate it. thank you
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Board extends JPanel {
Timer timer;
int count;
int clockNumber;
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillRect(30, 30, 640, 640);//makes a black square
for(int i=30;i<=510; i+=160)//adds white columns
{
for(int j=30; j<=510; j+=160)
{
g.clearRect(i, j, 80, 80);
}
}
for(int i=110; i<=590; i+=160)//adds black columns
{
for(int j=110; j<=590; j+=160)
{
g.clearRect(i, j, 80, 80);
}
}
g.setFont(new Font("Monospace", Font.BOLD, 30));
g.setColor(Color.WHITE);
g.drawString("a", 85, 660);
g.drawString("c", 245, 660);
g.drawString("e", 405, 660);
g.drawString("g", 565, 660);
g.drawString("7", 35, 140);
g.drawString("5", 35, 300);
g.drawString("3", 35, 460);
g.drawString("1", 35, 620);
g.setColor(Color.BLACK);
g.drawString("b", 165, 660);
g.drawString("d", 325, 660);
g.drawString("f", 485, 660);
g.drawString("h", 645, 660);
g.drawString("8", 35, 60);
g.drawString("6", 35, 220);
g.drawString("4", 35, 380);
g.drawString("2", 35, 540);
System.out.println(clockNumber);
g.drawString(String.valueOf(clockNumber), 300, 300);
}
public void showX(Graphics g)
{
g.setFont(new Font("wrongFont", Font.BOLD, 200));
g.setColor(Color.RED);
g.drawString("X", 35, 540);
}
public void boardImage()
{
JFrame frame=new JFrame();
frame.setSize(600, 600);
frame.getContentPane().add(new Board());
frame.setLocationRelativeTo(null);
frame.setBackground(Color.LIGHT_GRAY);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
CoordinateGame game=new CoordinateGame();
frame.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
int x=e.getX();
int y=e.getY();
}
});
}
public int clockNumber()
{
return clockNumber;
}
public void startTimer(int seconds)
{
ActionListener action=new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
clockNumber=count;
if(count==0)
{
timer.stop();
}
else
{
System.out.println(count);
clockNumber--;
count--;
repaint();
}
}
};
timer=new Timer(1000, action);
timer.setInitialDelay(0);
timer.start();
count=seconds;
}
}
Since you didn't provide a runnable example I should suppose that you're doing something like
Board board=new Board();
board.boardImage();
board.startTimer();
The problem is in boardImage() that creates a new instance of Board and adds that instance to the JFrame, not the original board, on which you start the timer.
So replace
frame.getContentPane().add(new Board());
with
frame.getContentPane().add(this);
Consider also removing the explicit setSize on the frame and add override getPreferredSize on your custom component, then use frame.pack() to automatically adjust the frame size to the board.
Related
package easteregg;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
class MyCanvas extends JComponent {
public void paint(Graphics g) {
g.drawOval (100, 20, 110, 160);
}
}
public class EasterEgg {
public static void main(String[] a) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setBounds(30, 30, 300, 300);
window.getContentPane().add(new MyCanvas());
window.setVisible(true);
}
}
my problem is i dont know how to put lines inside the oval
i want to make a easterEgg please help me
i have modified the paint method to draw one pattern please check the below code
public void paint(Graphics g) {
g.drawOval (100, 20, 110, 160);
g.drawLine(120, 40, 140, 60);
g.drawLine(140, 60, 150, 40);
g.drawLine(150, 40, 170, 60);
g.drawLine(170, 60, 190,40);
}
and the output is
this is just a hint to draw lines but better to create one method which will draw that pattern form one end to other end of the oval
Okay, so I'm trying to make a smiley face program, when it first starts up it's supposed to show the default smiley face(this part works and it's great I guess)
But then it should give you two buttons to pick from the smile and the frown buttons which should redraw the faces to show one smiling or frowning but it doesn't work for some reason.
I've been reading about graphics and I know you're not supposed to call them from outside the paint() method so I changed my code accordingly and I can tell the buttons are working because I make them print out something each time but the actual redrawing isn't working. I've tried using repaint() and revalidate() as well. For some reason if you use repaint() it repaints more and more each time which is odd, but maybe it's supposed to behave that way?
Can someone please take a look at the code and let me know what you think is the problem or where I should be looking for a solution I've used java for a while but I never use graphics :/ I've read your supposed to use setVisible/setSize(or pack()) at the end and that actually helped with some issues I had earlier but I don't get what to do when you want to draw multiple things most examples only show drawing one thing.
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class JSmileFacePanel2 extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
JButton smile = new JButton("SMILE");
JButton frown = new JButton("FROWN");
public JSmileFacePanel2() {
setLayout(new FlowLayout());
setTitle("JSmileFace-V2: Jose M. Tobar");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(frown);
add(smile);
setSize(800, 800);
setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
//by default should show smiling
g.setColor(Color.YELLOW);
g.fillOval(200, 200, 500, 500);
g.setColor(Color.BLUE);
g.fillOval(300, 360, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(600, 360, 50, 50);
g.drawArc(400, 400, 100, 40, 180, 185);
smile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("SMILE BUTTON CLICKED");
drawSmile(g);
}
});
frown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("FROWN BUTTON CLICKED");
drawFrown(g);
}
});
}
public void drawSmile(Graphics g) {
g.setColor(Color.YELLOW);
g.fillOval(200, 200, 500, 500);
g.setColor(Color.BLUE);
g.fillOval(300, 360, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(600, 360, 50, 50);
g.drawArc(400, 400, 100, 40, 180, 185);
repaint();
}
public void drawFrown(Graphics g) {
g.setColor(Color.WHITE);
g.fillOval(200, 200, 500, 500);
g.setColor(Color.BLUE);
g.fillOval(300, 360, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(600, 360, 50, 50);
g.drawArc(400, 400, 100, 40, 180, 185);
repaint();
}
public static void main(String[] args) {
JSmileFacePanel2 js = new JSmileFacePanel2();
}
}
You are still calling painting methods outside the paint method, because the actionPerformed methods different methods than the paint method. It doesn't matter that they are textually inside it, it's still a different method.
Also, you are repeatedly adding the action listeners every time that there is a repaint event, which will slow your application down to a halt and it will not repaint correctly either.
So, check whether you should smile or frown inside the paint method and add the action listeners inside the constructor.
The code then becomes:
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class JSmileFacePanel2 extends JFrame {
private static final long serialVersionUID = 1L;
// by default should show smiling
private boolean doSmile = true;
JButton smile = new JButton("SMILE");
JButton frown = new JButton("FROWN");
public JSmileFacePanel2() {
setLayout(new FlowLayout());
setTitle("JSmileFace-V2: Jose M. Tobar");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(frown);
add(smile);
smile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("SMILE BUTTON CLICKED");
doSmile = true;
repaint();
}
});
frown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("FROWN BUTTON CLICKED");
doSmile = false;
repaint();
}
});
setSize(800, 800);
setVisible(true);
}
public void paint(final Graphics g) {
super.paint(g);
if (doSmile) {
drawSmile(g);
} else {
drawFrown(g);
}
}
public void drawSmile(Graphics g) {
g.setColor(Color.YELLOW);
g.fillOval(200, 200, 500, 500);
g.setColor(Color.BLUE);
g.fillOval(300, 360, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(600, 360, 50, 50);
g.drawArc(400, 400, 100, 40, 180, 185);
}
public void drawFrown(Graphics g) {
g.setColor(Color.WHITE);
g.fillOval(200, 200, 500, 500);
g.setColor(Color.BLUE);
g.fillOval(300, 360, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(600, 360, 50, 50);
g.drawArc(400, 400, 100, 40, 180, 185);
}
public static void main(String[] args) {
JSmileFacePanel2 js = new JSmileFacePanel2();
}
}
In a word, no. But, you're on the right track though.
Remember, you're running in an event driven environment, meaning that something happens and then you respond to it.
Painting should do nothing more then just paint the current state, in your example, every time paint is called, you're adding a new ActionListener to the buttons, so you could end up with 3+ ActionListeners attached to each of your buttons just when the screen is made visible, which will result in some seriously weird behavior.
You should also not modify the state of the component, directly or indirectly from within your paint methods, which may cause a repaint to be scheduled, this will result in your paint method been called repeatedly, which will eventually consume your CPU cycles, messy to say the least.
You should also avoid extending from top level containers and overriding paint (generally), preferring instead to use a JPanel and overriding it's paintComponent method instead.
Two main reasons for this, first, it locks you into a single use case, meaning you can't re-use your components and secondly painting directly to a top level container like JFrame could have you painting underneath the frame's decorations/borders and because of the way painting works, even having the frames content painting over it.
See Painting in AWT and Swing and Performing Custom Painting for more details
The general solution is to use a flag to change the way in which your painting process works and change this flag accordingly when you want to (from within the button's ActionListeners for example)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
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 JSmileFace {
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
new JSmileFace();
}
public JSmileFace() {
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 SmilyPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class SmilyPane extends JPanel {
JButton smile = new JButton("SMILE");
JButton frown = new JButton("FROWN");
private boolean frowning = false;
public SmilyPane() {
setLayout(new FlowLayout());
add(frown);
add(smile);
smile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frowning = false;
repaint();
}
});
frown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("FROWN BUTTON CLICKED");
frowning = true;
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.YELLOW);
g.fillOval(200, 200, 500, 500);
g.setColor(Color.BLUE);
g.fillOval(300, 360, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(600, 360, 50, 50);
g.drawArc(400, 400, 100, 40, 180, 185);
if (frowning) {
drawFrown(g);
} else {
drawSmile(g);
}
}
public void drawSmile(Graphics g) {
g.setColor(Color.YELLOW);
g.fillOval(200, 200, 500, 500);
g.setColor(Color.BLUE);
g.fillOval(300, 360, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(600, 360, 50, 50);
g.drawArc(400, 400, 100, 40, 180, 185);
}
public void drawFrown(Graphics g) {
g.setColor(Color.WHITE);
g.fillOval(200, 200, 500, 500);
g.setColor(Color.BLUE);
g.fillOval(300, 360, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(600, 360, 50, 50);
g.drawArc(400, 400, 100, 40, 180, 185);
}
}
}
major issue: you're adding a lot of actionlisters in your code...
...whenever repaint() is called, it calls internally the paint(Graphics g) method and inside your paint-method you're adding a actionListener (again and again and again, whenever you redraw)
try to add the actionListener within your constructor:
public JSmileFacePanel2() {
setLayout(new FlowLayout());
setTitle("JSmileFace-V2: Jose M. Tobar");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(frown);
add(smile);
setSize(800, 800);
setVisible(true);
//here:
smile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("SMILE BUTTON CLICKED");
drawSmile(g);
}
});
frown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("FROWN BUTTON CLICKED");
drawFrown(g);
}
});
}
a minor flaw:
don't call drawFrown(g) or drawSmile(g) inside your actionListener (you can't anymore, you don't know graphics anymore) instead call repaint().
But before you repaint() you tell your graphic what will be drawn (i'm using an int for this, better use Enums but it will work for right now
i'm just doing the smile-part, the frown part is the same
private int style = 0;
public JSmileFacePanel2() {
//other code as above
...
smile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("SMILE BUTTON CLICKED");
style = 1; //1=smile, 2=frown
repaint(); //this calls internally the paint(g) method
}
});
}
and adjust your paint method:
public void paint(Graphics g) {
super.paint(g);
//by default should show smiling
g.setColor(Color.YELLOW);
g.fillOval(200, 200, 500, 500);
g.setColor(Color.BLUE);
g.fillOval(300, 360, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(600, 360, 50, 50);
g.drawArc(400, 400, 100, 40, 180, 185);
if(style == 1){
drawSmile(g);
}
if(style == 2){
drawFrown(g);
}
}
I'm currently working with JFrame and I'm trying to draw a rectangle but I don't know how to execute the code paint(Graphics g), how do I get the Graphics object?
package com.raggaer.frame;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Frame {
private JFrame frame;
public Frame() {
this.frame = new JFrame("Java Snake");
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.frame.setSize(new Dimension(500, 500));
// DRAW??
this.frame.setVisible(true);
}
public void paint(Graphics g) {
g.drawRect(10, 10, 200, 200);
}
}
Just call frame.repaint() (which should be called once automatically) to make it repaint the graphics. No need to provide your own Graphics object.
Side note, you should be using a JPanel with paintComponent(Graphics) instead. This will make handling of events a lot easier, especially for a game like snake.
Here is a small code example on Stack Overflow: Java drawing on JPanel which on a JFrame
And one I made myself with usage of Java 8:
import javax.swing.*;
import java.awt.*;
/**
* #author Obicere
*/
public class PaintExample {
public PaintExample() {
final JFrame frame = new JFrame("Paint Example");
final MyPanel panel = new MyPanel();
frame.add(panel);
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(PaintExample::new);
}
public class MyPanel extends JPanel {
#Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
g.setColor(Color.YELLOW);
g.fillOval(0, 0, 50, 50);
g.setColor(Color.BLACK);
g.drawOval(0, 0, 50, 50);
g.drawLine(20, 10, 20, 20);
g.drawLine(30, 10, 30, 20);
g.drawArc(15, 15, 20, 20, 180, 180);
g.drawString("Drawing with swing!", 10, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
}
As request of your comment, I also modified the program to display objects upon request:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedList;
/**
* #author Obicere
*/
public class PaintExample {
public PaintExample() {
final JFrame frame = new JFrame("Paint Example");
final MyPanel panel = new MyPanel();
frame.add(panel);
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(PaintExample::new);
}
public class MyPanel extends JPanel {
private final LinkedList<SmileyFace> faces;
public MyPanel() {
faces = new LinkedList<>();
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
faces.add(new SmileyFace(e.getX(), e.getY()));
MyPanel.this.repaint(); // Refresh the display on the screen
}
});
}
#Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
faces.stream().forEach((e) -> e.render(g));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
public class SmileyFace {
private final int x;
private final int y;
public SmileyFace(final int x, final int y) {
this.x = x;
this.y = y;
}
public void render(final Graphics g) {
g.setColor(Color.YELLOW);
g.fillOval(x, y, 50, 50);
g.setColor(Color.BLACK);
g.drawOval(x, y, 50, 50);
g.drawLine(x + 20, y + 10, x + 20, y + 20);
g.drawLine(x + 30, y + 10, x + 30, y + 20);
g.drawArc(x + 15, y + 15, 20, 20, 180, 180);
}
}
}
I made my own BottomBar with a simple gradient extending JComponent and adjusting the paintComponent() method.
Then I add it to the SOUTH of my JFrame which uses BorderLayout.
Everything looks correct at the beginning.
When I resize the frame the BottomBar gets repainted and set to the new position correctly. The think is, it happens a few milliseconds to late, so that one can see the JFrame 's background for a second.
The funny thing is, that when I set the execution environment to Java-SE 1.6 it works... (instead of 1.7)
Also, Im running it on a mac, if that makes a difference.
Code - JButton Example
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Main {
public static void main(String args[]){
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Resize Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JButton(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
}
Code - BottomBar Example
Main:
public class Main {
public static void main(String args[]){
Frame window = new Frame();
window.setSize(500, 400);
window.setVisible(true);
}
}
Frame:
import java.awt.BorderLayout;
import javax.swing.JFrame;
public class Frame extends JFrame{
private static final long serialVersionUID = 1L;
public Frame() {
setLayout( new BorderLayout() );
getContentPane().add( BorderLayout.SOUTH, new BottomBar() );
}
}
BottomBar
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JComponent;
public class BottomBar extends JComponent {
private static final long serialVersionUID = 1L;
public BottomBar() {
setSize(200, 30);
setPreferredSize( new Dimension(200, 30) );
}
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint gradient = new GradientPaint(0, 0, new Color(185, 185, 185), 0, getHeight() , new Color(151, 151, 151) );
g2.setPaint(gradient);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor( new Color(64, 64, 64) );
g2.drawLine(0, 0, getWidth(), 0);
g2.setColor( new Color(215, 215, 215) );
g2.drawLine(0, 1, getWidth(), 1);
}
}
I am unable to reproduce the effect you describe on 1.6; you might try the sscce below on 1.7. Note, several suggestions for your example:
Avoid setXxxxSize(), as discussed here. If you just want a 30 pixel high bar in SOUTH, override getPreferredSize() as shown below. If you later decide to add components, you'll need to add a layout manager.
#Override
public Dimension getPreferredSize() {
return new Dimension(0, 30);
}
Use pack() to let the Window adopt the preferred sizes of the enclosed components. I've added an arbitrary size JPanel to the CENTER; resize the frame to see how the bar grows horizontally in SOUTH.
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see https://stackoverflow.com/a/13610367/230513 */
public class Main {
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("BottomBar");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
}, BorderLayout.CENTER);
frame.add(new BottomBar(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
private static class BottomBar extends JComponent {
#Override
public Dimension getPreferredSize() {
return new Dimension(0, 30);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint gradient = new GradientPaint(
0, 0, new Color(185, 185, 185),
0, getHeight(), new Color(151, 151, 151));
g2.setPaint(gradient);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor(new Color(64, 64, 64));
g2.drawLine(0, 0, getWidth(), 0);
g2.setColor(new Color(215, 215, 215));
g2.drawLine(0, 1, getWidth(), 1);
}
}
}
I want to draw a line in a JPanel.
This is my GUI and I want a line in the JPanel in white.
I find many examples but the problem is the how to use it.
In many exmples, always they draw in a JFrame that extends from a JPanel.
I want to add the Panel to the Frame and add some buttons to draw lines in many directions and use the X button in center to clean the JPanel.
This is the code of the interface:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import java.awt.Color;
import javax.swing.JScrollPane;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class circuit extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
circuit frame = new circuit();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public circuit() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 559, 332);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(10, 21, 359, 255);
contentPane.add(scrollPane);
JPanel panel = new JPanel();
scrollPane.setViewportView(panel);
panel.setBackground(Color.WHITE);
JLabel label = new JLabel("New label");
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
/////////////
}
});
label.setIcon(new ImageIcon("C:\\Users\\achermen\\Desktop\\up.png"));
label.setBounds(447, 66, 46, 48);
contentPane.add(label);
JLabel label_1 = new JLabel("New label");
label_1.setIcon(new ImageIcon("C:\\Users\\achermen\\Desktop\\down.png"));
label_1.setBounds(447, 159, 46, 48);
contentPane.add(label_1);
JLabel label_2 = new JLabel("New label");
label_2.setIcon(new ImageIcon("C:\\Users\\achermen\\Desktop\\right.png"));
label_2.setBounds(495, 112, 46, 48);
contentPane.add(label_2);
JLabel label_3 = new JLabel("New label");
label_3.setIcon(new ImageIcon("C:\\Users\\achermen\\Desktop\\left.png"));
label_3.setBounds(398, 112, 46, 48);
contentPane.add(label_3);
JLabel label_4 = new JLabel("New label");
label_4.setIcon(new ImageIcon("C:\\Users\\achermen\\Desktop\\1303860240_list-remove.png"));
label_4.setBounds(447, 112, 46, 48);
contentPane.add(label_4);
}
}
This is the code to draw a line
public void paint(Graphics graphics)
{
graphics.drawLine(10, 20, 300, 310);
}
So how to use this lines ....
Thanks in advance.
Best regards,
Ali
It may be easier to draw lines using the following approach:
click to mark the first endpoint
drag to show the line in progress
release to mark the second endpoint
This related example may offer some additional guidance.
Addendum
The example below implements the outline above.
I've update the example to show how to use a panel of buttons to affect the drawing.
See also this related example that uses the Action interface with key bindings.
I've updated this example to use Key Bindings.
LinePanel.java
import java.awt.BasicStroke;
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.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
/**
* #see https://stackoverflow.com/questions/6991648
* #see https://stackoverflow.com/questions/6887296
* #see https://stackoverflow.com/questions/5797965
*/
public class LinePanel extends JPanel {
private MouseHandler mouseHandler = new MouseHandler();
private Point p1 = new Point(100, 100);
private Point p2 = new Point(540, 380);
private boolean drawing;
public LinePanel() {
this.setPreferredSize(new Dimension(640, 480));
this.addMouseListener(mouseHandler);
this.addMouseMotionListener(mouseHandler);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(8,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
private class MouseHandler extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
drawing = true;
p1 = e.getPoint();
p2 = p1;
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
drawing = false;
p2 = e.getPoint();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
if (drawing) {
p2 = e.getPoint();
repaint();
}
}
}
private class ControlPanel extends JPanel {
private static final int DELTA = 10;
public ControlPanel() {
this.add(new MoveButton("\u2190", KeyEvent.VK_LEFT, -DELTA, 0));
this.add(new MoveButton("\u2191", KeyEvent.VK_UP, 0, -DELTA));
this.add(new MoveButton("\u2192", KeyEvent.VK_RIGHT, DELTA, 0));
this.add(new MoveButton("\u2193", KeyEvent.VK_DOWN, 0, DELTA));
}
private class MoveButton extends JButton {
KeyStroke k;
int dx, dy;
public MoveButton(String name, int code,
final int dx, final int dy) {
super(name);
this.k = KeyStroke.getKeyStroke(code, 0);
this.dx = dx;
this.dy = dy;
this.setAction(new AbstractAction(this.getText()) {
#Override
public void actionPerformed(ActionEvent e) {
LinePanel.this.p1.translate(dx, dy);
LinePanel.this.p2.translate(dx, dy);
LinePanel.this.repaint();
}
});
ControlPanel.this.getInputMap(WHEN_IN_FOCUSED_WINDOW)
.put(k, k.toString());
ControlPanel.this.getActionMap()
.put(k.toString(), new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
MoveButton.this.doClick();
}
});
}
}
}
private void display() {
JFrame f = new JFrame("LinePanel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.add(new ControlPanel(), BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new LinePanel().display();
}
});
}
}
Is this going to work like an etch-a-sketch? Then you need to track the current position of the point.
Point current = new Point(0, 0); //for example.
Then when the user clicks the buttons you can simply increment or decrement x and y accordingly.
On left arrow:
current.setX(current.getX() - INC);
where INC could be a variable that specifies the length of the distance to draw the line. Maybe 5? Always set a second point p1 to the previous location though.
It is always easier to create a class that extends Canvas or JPanel to draw on rather than draweing directly on the JFrame.
e.g.
public class Circuit extends JFrame {
Point p1, current;
JPanel drawPanel;
//your other declarations
public Circuit(){
super();
drawPanel = new DrawPanel();
p1 = new Point(0, 0);
current = new Point(0, 0);
add(drawPanel, BorderLayout.CENTER);
//your other code
}
class DrawingPanel extends JPanel{
public void paintComponent(Graphics g){
g.drawLine(p1.getX(), p1.getY(), current.getX(), current.getY());
}
}
//the rest of your code.
}
There is a simple answer for triggering graphics: e.g. The following code can be placed inside a click event and used for drawing a few simple objects on a jPanel. jPanel1 in this case was situated on one side of a tabbed jPanel7 and next to the triggering button. To do this in netbeans GUI, the code was placed inside the button action event. Once the usual errors appeared for not having the proper imports, right click on the code and click on "fix imports". Bingo, all is well :-) Warning: the setBackground command for the panel will override the graphics object. If you set the background color without using the graphics object, you will not see your objects!
Graphics g = jPanel1.getGraphics();
g.setColor(Color.blue);
g.drawLine( 0, 50, 20, 50);
g.setColor(Color.white);
g.fillRect(40, 50, 20, 20);
g.setColor(Color.blue);
g.drawRect(40, 50, 20, 20);
g.drawOval(80, 50, 20, 20);
g.setColor(Color.green);
g.fillOval(80, 50, 18, 18);
This restores your faith in true love :-)
The difficulty here is that any change or repaint will erase your effort. This approach is specifically discouraged by the Java founders. But in the current rendition of Netbeans Swing, where extending the jPanel is made difficult by locking code changes, this approach could be your only short term solution. A simple persistent graphic extension for the jPanel would be a most welcome addition to the current Netbeans Swing environment, a graphics panel. This would allow you to drag and drop the graphics panel and then get on with the event driven use of that panel. 40 other IDE's already have this, it seems Java has been slow to add this feature.