First coord in this case should be 0,0 and not 8,30. What am i doing wrong(i am using NetBeans)
import java.awt.Color;
import java.awt.Graphics;
public class TEST extends javax.swing.JFrame {
#Override
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.blue);
g.drawRect(8, 30, 200, 200);
repaint();
}}
Add a JPanel to the frame and paint in that. The frame's coordinates include the decorations (title bar, borders, etc.). It would look something like this:
public class Test extends JFrame {
public static void main(String[] args) {
new Test();
}
private Test() {
add(new MyPanel());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(600, 600);
setVisible(true);
}
private class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
g.drawRect(8, 30, 200, 200);
}
}
}
Also, don't call repaint(); in paint();. That will cause an infinite loop and will freeze the entire program.
The problem is your paint(..) method is not taking into account the JFrame Insets by calling getInsets which as docs state:
If a border has been set on this component, returns the border's
insets.
this code works fine:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
createAndShowGui();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void createAndShowGui() {
JFrame frame = new JFrame() {
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.blue);
g.drawRect(0 + getInsets().left, 0 + getInsets().top, 200, 200);
}
};
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
however this is not best practice.
Rather add JPanel to JFrame and override paintComponent(Graphics g) of JPanel dont forget call to super.paintComponent(g) as first call in the overridden method and than draw there (dont forget to override getPreferredSize() and return correct Dimensions so the JPanel will fit its drawing/graphic content) this problem will no longer persist as JPanel is added at correct co-ordinates on contentPane like so:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
createAndShowGui();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void createAndShowGui() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.setColor(Color.blue);
g2d.drawRect(0, 0, 200, 200);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
The above includes Graphics2D and RenderingHints i.e anti-aliasing. Just for some better looking drawings :)
Related
If I create a JFrame 800x600 pixels and draw a line from (0,0) to (800,600) it doesn't go from corner to corner, so, where is the (0,0) and where is the (800,600)?
Here is the code
import java.awt.Graphics;
import javax.swing.JFrame;
public class Point0_0test extends JFrame {
public Point0_0test() {
setTitle("Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setLocationRelativeTo(null);
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawLine(0, 0, 800, 600);
}
public static void main(String[] args) {
Point0_0test test = new Point0_0test();
test.setVisible(true);
}
}
Here you can see what appears when the program is running
If you want a drawing area that's 800 x 600 pixels, then set a drawing area that's 800 x 600 pixels. Who cares how big the frame is?
Here's a simple drawing GUI that I created. I made it 400 x 300 pixels so it would fit in the answer easier.
Here's the code. It's a minimal, runnable example for setting the size of the drawing area.
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SimpleDrawingArea implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new SimpleDrawingArea());
}
#Override
public void run() {
JFrame frame = new JFrame("Simple Drawing Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawingPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawingPanel() {
this.setPreferredSize(new Dimension(400, 300));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(4f));
g2d.drawLine(0, 0, 400, 300);
}
}
}
The JFrame size and coordinates count the size of the decorations, such as the top part of the window contains the bar with the close button, the rest contain the extra outline that is added on Windows(Ubuntu, at least, doesn't seem to add an extra outline). In order to get a line like you would want to, you should use JFrame.getInsets(), which returns the size of the GUI that decorates the JFrame, like this:
import java.awt.Insets;
#Override
public void paint(Graphics g) {
super.paint(g);
Insets in = getInsets();
g.drawLine(in.left, in.top, 800-in.right, 600-in.bottom);
}
Edit: this means that you don't have an actual 800x600 space. The Insets class seems to be "created" when setVisible(true) is called, as far as I can tell. So this would be how the code for that looks like:
import javax.swing.JFrame;
import java.awt.Insets;
import java.awt.Graphics;
public class InsetsTest extends JFrame {
public InsetsTest() {
super();
setTitle("Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800,600);
setVisible(true);
Insets insets= getInsets();
setSize(800+insets.right+insets.left,600+insets.top+insets.bottom);
setLocationRelativeTo(null);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Insets in = getInsets();
g.drawLine(in.left, in.top, 800+in.left, 600+in.top);
}
public static void main(String[] args) {
InsetsTest test = new InsetsTest();
test.setVisible(true);
}
}```
The window size should be defined without OS specific window decoration.
Try to add
this.setUndecorated(true);
before the
this.setVisible(true);
package drawinglinebymethods;
import java.awt.*;
import javax.swing.JFrame;
public class DrawingLineByMethods extends Frame {
public JFrame f=new JFrame();
void fra_size()
{
f.setSize(450, 300);
}
void fra_visible()
{
f.setVisible(true);
}
void fra_title()
{
f.setTitle(" java frame");
}
void exit()
{
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void line(Graphics g) {
g.drawLine(10, 10, 20, 300);
}
public static void main(String[] args) {
DrawingLineByMethods obj = new DrawingLineByMethods();
obj.fra_size();
obj.fra_title();
obj.fra_visible();
obj.fra_exit();
obj.line(g); // <-- error here
}
}
Your question suggests that you are not yet clear on how graphics and drawing works in Swing GUI's. Some suggestions for you:
Don't have your class extend java.awt.Frame as this makes no sense. You're not creating an AWT Frame window and have no need of this.
Create a class that extends JPanel and draw in its paintComponent method as the Swing painting tutorials (link now added) show you.
You never call drawing code directly but rather it is indirectly called by the JVM.
If you want to draw from outside of the GUI itself, then draw to a BufferedImage, one that is then displayed within the GUI.
Don't use a Graphics object obtained by calling getGraphics() on a GUI component as the object thus obtained will not persist, and this risks you creating unstable graphics or worse -- throwing a NullPointerException.
For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
#SuppressWarnings("serial")
public class LineDraw extends JPanel {
private static final int PREF_W = 450;
private static final int PREF_H = 300;
public LineDraw() {
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// use rendering hints to draw smooth lines
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// do drawing here
g.drawLine(10, 10, 20, 300);
}
private static void createAndShowGui() {
LineDraw mainPanel = new LineDraw();
JFrame frame = new JFrame("Line Draw");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
If you want to add lines as the program runs, again, use a BufferedImage that is drawn within the JPanel's paintComponent method. When you need to add a new line to the GUI, extract the Graphics or Graphics2D object from the BufferedImage using getGraphics() or createGraphics() respectively (it's OK to do this), draw with this Graphics object, dispose of the Graphics object, and repaint the GUI. For example in the code below, I draw a new line when the button is pressed by adding code within the JButton's ActionListener (actually its AbstractAction which is similar to an ActionListener but more powerful):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class LineDraw extends JPanel {
private static final int PREF_W = 450;
private static final int PREF_H = 300;
private BufferedImage img;
private int yDistance = 20;
private int deltaY = 10;
public LineDraw() {
img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
add(new JButton(new DrawLineAction("Draw Line", KeyEvent.VK_D)));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// draw the buffered image here
if (img != null) {
g.drawImage(img, 0, 0, this);
}
// use rendering hints to draw smooth lines
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// do drawing here
g.drawLine(10, 10, 20, 300);
}
public void drawNewLines() {
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.BLACK);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
yDistance += deltaY;
g2.drawLine(10, 10, yDistance, PREF_H);
g2.dispose();
repaint();
}
private class DrawLineAction extends AbstractAction {
public DrawLineAction(String name, int mnemonic) {
super(name); // give button its text
putValue(MNEMONIC_KEY, mnemonic); // alt-hot key for button
}
#Override
public void actionPerformed(ActionEvent e) {
drawNewLines();
}
}
private static void createAndShowGui() {
LineDraw mainPanel = new LineDraw();
JFrame frame = new JFrame("Line Draw");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
Line is a non-static method, the only way to call it from a static method (main here) is to have an instance of the class.
I have been struggling with Paint methods, and paint components, and extends JFrame, and have been trying all sorts of ways to get a simple rectangle to draw. here is a class called Window:
import javax.swing.*;
import java.awt.Graphics;
public class Window extends JFrame
{
/**
*
*/
private static final long serialVersionUID = 1L;
Window()
{
setSize(300,300);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void paint(Graphics g)
{
g.drawRect(300,300,300,300);
}
}
then class Main
public class Main {
public static void main(String args[])
{
Window mainWindow = new Window();
mainWindow.setBounds(100,100,300,300);
}
}
The sole purpose of this program is just draw a damn rectangle. I have no idea what I could be doing wrong, and I have been trying to drawRect or drawString for several days now, to no avail. I also tried with a panel.
Don't override paint of top level containers like JFrame, this is the quickest way to end up with a world of weird and unexpected results.
Between the frames actual surface and the use, there is a JRootPane, a contentPane and possibly a glassPane...
All of these can interface/erase what you've painted in the paint method.
Instead, start with a JPanel and override it's paintComponent. Create an instance of this and place it on an instance of a JFrame when you want to show it.
Have a look at Painting in AWT and Swing and Performing Custom Painting for more details
Also, beware that when painting, 0x0 is the top/left of your component, so in your example, you start painting at 300x300, but your frame is only 300x300, so you're actually painting of the screen
As an example:
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestPaint {
public static void main(String[] args) {
new TestPaint();
}
public TestPaint() {
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 PaintPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintPane extends JPanel {
public PaintPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawRect(10, 10, getWidth() - 20, getHeight() - 20);
g2d.dispose();
}
}
}
could you try this code
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JPanel {
public static void main(String[] a) {
JFrame f = new JFrame();
f.setSize(400, 400);
f.add(new Main());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
public void paint(Graphics g) {
g.fillRect (5, 15, 50, 75);
}
}
I have the following java programm:
import java.awt.*;
import java.awt.Graphics;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
public class Lapex extends JPanel implements MouseListener{
JPanel p = new JPanel();
Lapex(){
JFrame f = new JFrame();
p.addMouseListener(this);
p.setPreferredSize(new Dimension(600, 600));
f.add(p);
f.pack();
f.show(true);
}
public void paint(Graphics g){
paintComponents(g);
g.setColor(Color.RED);
g.drawLine(10, 10, 100, 100);
}
public void mouseClicked(MouseEvent me){
System.out.println("AAAA");
repaint();
}
}
public static void main(String[] args){
new Lapex();
}
}
Clicking the mouse, at the console is displayied "AAAAA", but draws no line.(I deleted the other mouse event)
How to modify ?
You have to call the super method and use paintComponent.
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.drawLine(10, 10, 100, 100);
}
A few things to note:
Your class extends JPanel, but then you create another JPanel inside the class that you actually add to the frame. Add the instance of your class instead.
Override paintComponent instead of paint.
Use a call to invokeLater to start your program on the EDT. See Event Dispatch Thread for more info.
Override getPreferredSize rather than call setPreferredSize.
Here is a complete example that toggles the line on/off when the mouse button is clicked:
import java.awt.*;
import java.awt.Graphics;
import javax.swing.*;
import java.awt.event.*;
public class Lapex extends JPanel {
boolean drawLine = false;
Lapex(){
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent me){
drawLine = !drawLine;
repaint();
}
});
f.add(this);
f.pack();
f.setVisible(true);
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
if(drawLine) {
g.setColor(Color.RED);
g.drawLine(10, 10, 100, 100);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
new Lapex();
}});
}
}
No!, don't override paint() leave this up to Swing itself. All you should do is override paintComponent().
hi there i'm trying to improve myself about java2D and first of all i'm dealing with drawing polygons. However, i can not see the polygon on frame. I read some tutorials and examples but as i said i face with problems. here is the sample code of drawing a polygon;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import javax.swing.JFrame;
public class jRisk extends JFrame {
private JFrame mainMap;
private Polygon poly;
public jRisk(){
initComponents();
}
private void initComponents(){
mainMap = new JFrame();
mainMap.setSize(800, 600);
mainMap.setResizable(false);
mainMap.setVisible(true);
mainMap.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int xPoly[] = {150,250,325,375,450,275,100};
int yPoly[] = {150,100,125,225,250,375,300};
poly = new Polygon(xPoly, yPoly, xPoly.length);
}
protected void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.BLUE);
g.drawPolygon(poly);
}
/**
* #param args
*/
public static void main(String[] args) {
new jRisk();
}
}
JFrame does not have a paintComponent(Graphics g) method. Add the #Override annotation and you will get a compile time error.
1) Use JPanel and override paintComponent (you would than add JPanel to the JFrame viad JFrame#add(..))
2) Override getPreferredSize() to return correct Dimensions which fit your drawing on Graphics object or else they wont be seen as JPanel size without components is 0,0
3) dont call setSize on JFrame... rather use a correct LayoutManager and/or override getPrefferedSize() and call pack() on JFrame after adding all components but before setting it visible
4) Have a read on Concurrency in Swing specifically about Event Dispatch Thread
5) watch class naming scheme should begin with a capital letter and every first letter of a new word thereafter should be capitalized
6) Also you extend JFrame and have a variable JFrame? Take away the extend JFrame and keep the JFrame variable as we dont want 2 JFrames and its not good practice to extend JFrame unless adding functionality
Here is your code with above fixes (excuse picture quality but had to resize or it was going to 800x600):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Polygon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JRisk {
private JFrame mainMap;
private Polygon poly;
public JRisk() {
initComponents();
}
private void initComponents() {
mainMap = new JFrame();
mainMap.setResizable(false);
mainMap.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
int xPoly[] = {150, 250, 325, 375, 450, 275, 100};
int yPoly[] = {150, 100, 125, 225, 250, 375, 300};
poly = new Polygon(xPoly, yPoly, xPoly.length);
JPanel p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawPolygon(poly);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
};
mainMap.add(p);
mainMap.pack();
mainMap.setVisible(true);
}
/**
* #param args
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JRisk();
}
});
}
}
As per your comment:
i am preparing a map which includes lots of polygons and yesterday i
used a JPanel over a JFrame and i tried to check if mouse was inside
of the polygon with MouseListener. later i saw that mouseListener gave
false responds (like mouse is not inside of the polygon but it acts
like it was inside the polygon). so i deleted the JPanel and then it
worked
Here is updated code with MouseAdapter and overridden mouseClicked to check if click was within polygon.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JRisk {
private JFrame mainMap;
private Polygon poly;
public JRisk() {
initComponents();
}
private void initComponents() {
mainMap = new JFrame();
mainMap.setResizable(false);
mainMap.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
int xPoly[] = {150, 250, 325, 375, 450, 275, 100};
int yPoly[] = {150, 100, 125, 225, 250, 375, 300};
poly = new Polygon(xPoly, yPoly, xPoly.length);
JPanel p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawPolygon(poly);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
};
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent me) {
super.mouseClicked(me);
if (poly.contains(me.getPoint())) {
System.out.println("Clicked polygon");
}
}
};
p.addMouseListener(ma);//add listener to panel
mainMap.add(p);
mainMap.pack();
mainMap.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JRisk();
}
});
}
}
JFrame does not extend JComponent so does not override paintComponent. You can check this by adding the #Override annotation.
To get this functionality extract paintComponent to a new class which extends JComponent. Don't forget to call super.paintComponent(g) rather than super.paintComponents(g).
Replace
protected void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.BLUE);
g.drawPolygon(poly);
}
With
protected void paint(Graphics g){
super.paint(g);
g.setColor(Color.BLUE);
g.drawPolygon(poly);
}