Swing Graphics on JFrame - java

Using Java Graphics, I tried to draw a simple rectangle.
As Applet it runs well but when I use it to show on a JFrame, the rectangle is coming but with some unusual background
Here is coding:
package graphicsex;
import java.awt.Graphics;
public class Graphics2 extends javax.swing.JFrame {
public static void main(String[] args) {
Graphics2 inst = new Graphics2();
inst.setVisible(true);
}
public Graphics2() {
super();
initGUI();
}
private void initGUI() {
try {
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
pack();
setSize(400, 300);
} catch (Exception e) {
e.printStackTrace();
}
}
public void paint(Graphics g) {
g.drawRect(10, 20, 30, 40);
}
}
Then I tried to use JTextArea using these two classes but in this case the rectangle is not displaying at all.
GraphicsEx1.java:
package graphicsex;
import javax.swing.JTextArea;
import java.awt.Graphics;
public class GraphicsEx1 extends javax.swing.JFrame {
private JTextArea jTextArea1;
{
//Set Look & Feel
try {
javax.swing.UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
GraphicsEx1 inst = new GraphicsEx1();
inst.setVisible(true);
}
public GraphicsEx1() {
super();
initGUI();
}
private void initGUI() {
try {
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
getContentPane().setLayout(null);
{
jTextArea1 = new JTextArea();
getContentPane().add(jTextArea1);
jTextArea1.setBounds(7, 7, 371, 245);
jTextArea1.setEnabled(false);
}
pack();
setSize(400, 300);
} catch (Exception e) {
e.printStackTrace();
}
postInitGUI();
}
public void postInitGUI() {
DisplayItems dp = new DisplayItems();
jTextArea1 = dp;
dp.setVisible(true);
this.add(jTextArea1);
}
}
And DisplayItems.java:
package graphicsex;
import java.awt.Dimension;
import java.awt.Graphics;
public class DisplayItems extends javax.swing.JTextArea {
public DisplayItems() {
super();
initGUI();
}
private void initGUI() {
try {
setPreferredSize(new Dimension(400, 300));
} catch (Exception e) {
e.printStackTrace();
}
}
public void paint(Graphics g) {
g.drawRect(10, 20, 50, 100);
g.drawString("Kalai", 90, 150);
}
}
Can any one help me display graphics components on any swing containers like JFrame,JPanelorJTextarea` etc.

It is inadvisable to override the paint method of a top level container...
JFrame contains a number of important layers onto which many other components are placed, buy doing this...
public void paint(Graphics g){
g.drawRect(10,20,30,40);
}
You've successfully stopped any of the child components from begin painted, or in fact, anything other then your rectangle.
(The secret life of a top level swing container - Picture taken from How to use Root Panes)
While some might suggest simple adding a call to super.paint(g), I would not recommend it.
Better to use something like the JFrame's glass pane...This will allow you to paint over the components that reside within the frame. If you need to paint under the components, replace the JFrame's content pane instead.
You may find...
Performing Custom Painting
Painting in AWT and Swing
How to Decorate Components with the JLayer Class
Of use...
Update
I think I'm beginning to see you problem with trying to perform custom painting on a text area.
The problem is, paintComponent paints the background AND the text in one foul swoop, meaning that any painting you do before calling super.paintComponent will be rendered over, but any painting done over it will paint over the text.
You could set the text area to be non-opaque and paint the background yourself...
public class CustomTextArea extends JTextArea {
public CustomTextArea() {
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.fillRect(0, 0, 100, 100);
super.paintComponent(g);
}
}
The problem is though, it's easy for people to rest the opaque level and destroy your work. Sure you could override the setOpaque or getOpaque, but how do you known when the user actually wants to set the component transparent, so you can stop fill the back ground?

* Using jPanel *
using jpanel, the graphics elements can be drawn;
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;
public class GraphicsEx1 extends javax.swing.JFrame {
private JScrollPane jsp1;
private JTextArea jta1;
private JPanel jpnl1;
{
//Set Look & Feel
try {
javax.swing.UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");
} catch(Exception e) {e.printStackTrace();}
}
public static void main(String[] args) {
GraphicsEx1 inst = new GraphicsEx1();
inst.setLocationRelativeTo(null);
inst.setVisible(true);
}
public GraphicsEx1() {
super();
initGUI();
postInitGUI();
}
private void initGUI() {
try {
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
getContentPane().setLayout(null);
{
jsp1 = new JScrollPane();
getContentPane().add(jsp1);
jsp1.setBounds(10, 32, 372, 223);
{
jpnl1 = new JPanel(); //<----------------
jsp1.setViewportView(jpnl1); //<----------------
jpnl1.setBackground(new java.awt.Color(255,255,255));
jpnl1.setLayout(null);
//jpnl1.setPreferredSize(new java.awt.Dimension(359, 327));
}
}
pack();
setSize(400, 300);
} catch (Exception e) {e.printStackTrace();}
}
public void postInitGUI(){
frmGrpView gp=new frmGrpView();
jta1=new JTextArea();
jta1=gp;
jta1.setBounds(0,0, 336, 197);
jta1.setVisible(true);
//jpnl1.setBounds(0, 0, 336, 197);
jpnl1.add(jta1); //<----------------
jpnl1.revalidate();
jsp1.revalidate();
}
}
//----------------------- Second Class --------------------------
class frmGrpView extends JTextArea{
public frmGrpView() {
super();
setEditable(false);
}
public void paint(Graphics g){
super.paint(g);
g.drawRect(10, 10, 100, 100);
}
}

Related

MouseListener not giving accurate mouse location

I am attempting to have a circle appear on the screen and follow the mouse around. (Eventually I'm going to turn it into a game with ray casting) I am using a MouseMotionListener and am trying to use the mouseMoved method to get accurate mouse location within my JPanel. The problem is though that the farther I move my mouse down the screen, the less accurate it becomes. By the time my mouse gets to the bottom, it is drawing circles about 20 pixels above. It is not a lagging thing because it never catches up, it is always a few pixels above where it should be.
I've tried using different methods that call from MouseEvents and have tried using MousePointerInfo but none work correctly. It does seem to work when I have the JFrame set to undecorated, but obviously that does not look good for a program and thus I want to avoid that.
public class Driver {
public static void main(String[] args) {
JFrame frame = new JFrame("Moonlight");
frame.setSize(700, 700);
frame.setLocation(350, 50);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new MoonlightPanel());
frame.setVisible(true);
}
}
public class Panel extends JPanel {
private BufferedImage myImage;
private Graphics myBuffer;
private Timer t;
public Panel () {
myImage = new BufferedImage(700, 700, BufferedImage.TYPE_INT_RGB);
myBuffer = myImage.getGraphics();
t = new Timer(0, new Listener());
t.start();
addMouseMotionListener(new Mouse());
}
private class Listener implements ActionListener {
public void actionPerformed(ActionEvent e) {
drawBackground();
/*try {
Point pos = getMousePosition();
myBuffer.setColor(Color.WHITE);
myBuffer.fillOval(pos.x - 10, pos.y - 10, 20, 20);
}
catch(NullPointerException en) {}*/
repaint();
}
}
private class Mouse implements MouseMotionListener {
public void mouseMoved(MouseEvent e) {
Point pos = new Point(e.getX(), e.getY());
System.out.println(pos);
myBuffer.setColor(Color.BLUE);
myBuffer.fillOval(pos.x - 10, pos.y - 10, 20, 20);
}
public void mouseDragged(MouseEvent e) {}
}
public void drawBackground() {
setBackground(Color.BLACK);
}
public void paintComponent(Graphics g) {
g.drawImage(myImage, 0, 0, getWidth(), getHeight(), null);
}
}
Your code is much more complex than it needs to be. The Panel class members are unnecessary. All you need to do is save the mouse location in the mouseMoved() method - in a class member variable - and reference it in the paintComponent() method to draw your blue circle. The below code is a stripped-down version which displays a blue circle that follows the mouse pointer around on the screen.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MoonLite extends JPanel implements MouseMotionListener {
private Point pt;
public MoonLite() {
setBackground(Color.BLACK);
setForeground(Color.BLUE);
addMouseMotionListener(this);
}
public void mouseMoved(MouseEvent e) {
pt = e.getPoint();
repaint();
}
public void mouseDragged(MouseEvent e) {
// Do nothing.
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (pt != null) {
g.fillOval(pt.x - 10, pt.y - 10, 20, 20);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Moonlight");
frame.setSize(700, 700);
frame.setLocation(350, 50);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new MoonLite());
frame.setVisible(true);
}
});
}
}

Trying to draw lines in java over an image i already drew but i can't get it on top of the image?

I have to draw an archery target with two black lines in the innermost circle that forms a cross, but every time i adjust the lines so that the lines are closer to the centre it goes behind the image instead of appearing on top. How can I stop this? Does it need to have a separate set of instructions entirely?
This is my code:
package sumshapes;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.*;
import javax.swing.*;
public class SumShapes extends JFrame
implements ActionListener {
private JPanel panel;
public void paint(Graphics g)
{
g.setColor(Color.BLACK);
g.drawLine(250, 200, 250, 200);
g.drawOval(140,90,200,200);
g.setColor(Color.BLACK);
g.fillOval(140,90,200,200);
g.drawOval(162,109,155,155);
g.setColor(Color.BLUE);
g.fillOval(162,109,155,155);
g.drawOval(183,129,112,112);
g.setColor(Color.RED);
g.fillOval(183, 129, 112, 112);
g.drawOval(210,153,60,60);
g.setColor(Color.YELLOW);
g.fillOval(210, 153, 60, 60);
g.setColor(Color.BLACK);
}
public static void main(String[] args) {
SumShapes frame = new SumShapes();
frame.setSize(500,400);
frame.setBackground(Color.yellow);
frame.createGUI();
frame.setVisible(true);
}
private void createGUI(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container window = getContentPane();
window.setLayout (new FlowLayout());
}
public void actionPerformed(ActionEvent event) {
Graphics paper = panel.getGraphics();
paper.drawLine(20,80,120,80);
}
}
All your drawing should go into the paintComponent method of a lightweight component, such as a JPanel.
There should never be a need to call getGraphics. If you wish to change the drawing upon a particular action you should a) program the logic into paintComponent b) alter the logic in the Action c) call repaint on the Component
For example:
private JPanel panel = new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);//call parent method first thing
//paint here
}
#Override
public Dimension getPreferredSize(){//provided so you can size this component as necessary
return new Dimension(500,400);
}
};
....
frame.add(panel);
frame.pack();
As an aside, I'd recommend placing all calls to to Swing components on the EDT - this means wrapping your Swing calls in the main method with SwingUtilities. eg
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable(){
#Override
public void run() {
SumShapes frame = new SumShapes();
....
}
});
}

How can I stop an image from flickering/dislocating when a JFrame is resized?

I have a JFrame. Within that JFrame I have a JLayeredPane layed out with an OverlayLayout that contains multiple Jpanels. in one of those JPanels I have a BufferedImage. When the JFrame is resized, the image quickly dissapears and dislocates, then it jumps back again, dislocates again, back again, and so on.
I have tried a lot of things to stop the image from flickering, but I don't know what the cause of the problem exactly is.
The Jpanel that holds the image contains the following code to render the image:
protected void paintComponent (Graphics g) {
super.paintComponent(g);
g.drawImage(myBufferedImage, 0, 0, 200, 200, null);
}
In trying to reconstruct and simplify the problem, I got a working version of what I wanted. I still don't know what the problem is with my other code though.
This is the code that works:
import java.awt.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Main {
public Main() {
// Create the JFrame:
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(600, 400);
window.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
// Create the pane to hold layers:
JLayeredPane layers = new JLayeredPane();
layers.setLayout(new OverlayLayout(layers));
// Add two layers:
layers.add(new MyGraphics());
layers.add(new MyImage());
//
window.add(layers);
window.setVisible(true);
}
public static void main(String[] args) {
Main app = new Main();
}
public class MyImage extends JPanel {
public BufferedImage source;
public MyImage () {
this.setPreferredSize(new Dimension(180,180));
this.setLocation(0,0);
try {
this.source = ImageIO.read(new File("image.jpg"));
} catch (IOException ie) {
ie.printStackTrace();
}
}
protected void paintComponent (Graphics g) {
super.paintComponent(g);
g.drawImage(this.source, 0, 0, 180, 180, null);
}
}
public class MyGraphics extends JPanel {
public MyGraphics () {
this.setOpaque(false);
this.setPreferredSize(new Dimension(180,180));
this.setLocation(0,0);
}
protected void paintComponent (Graphics g) {
super.paintComponent(g);
g.drawLine(0, 0, 180, 180);
}
}
}
Try adding below line of code in constructor:
public FlickerDemo()
{
// No flickering during resize
System.setProperty("sun.awt.noerasebackground", "true");
}

My custom JComponent is not showing up?

I want to make a simple test JComponent so that i can see how things work when calling repaint(), paintComponent() and overriding all of the methods in paint or update. This is for learning only I know that this would not be done in the real world.
To Start with I would like to just to be able to make a component that I can draw a line to x and y points. I want my JComponent class to have every method that should be in a JComponent class even if it is not used. Thus I would like a list of every method that needs to be overridden for creating ones own JComponent. (this is for later)
My main question is why will my component not render on my JPanel that I am using to draw all of my components on.
Question: Why is my component not showing up on my JPanel?
Also I would like to try and make this post a learning option for building a JComponent from scratch. I will add the working code at the bottom as I go and the code that does not work also.
Code:
package testpak;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import java.awt.*;
public class FrameDemo {
JFrame frame = new JFrame("FrameDemo");
JPanel panel = new JPanel();
MyComponent cc = new MyComponent();
FrameDemo() {
setLookFeel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
panel.add(cc);
frame.add(panel);
frame.setSize( new Dimension(200, 200));
frame.setVisible(true);
}
private void setLookFeel() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
}
public static void main(String[] args) {
FrameDemo fd = new FrameDemo();
}
}
JComponent Class:
package testpak;
import java.awt.Graphics;
import javax.swing.JComponent;
public class MyComponent extends JComponent {
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(10, 10, 100, 100);
}
public void paint(Graphics g) {
super.paint(g);
paintComponent(g);
paintBorder(g);
paintChildren(g);
}
}
New Code:
package testpak;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JComponent;
public class MyComponent extends JComponent {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize () {
return new Dimension(100, 25);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(10, 10, 100, 100);
}
public void paintBorder(Graphics g) {
super.paintBorder(g);
g.setColor(Color.YELLOW);
g.fillRect(0, 0, 50, 50);
g.setColor(Color.BLACK);
g.drawRect(0, 0, 50, 50);
}
public void paint(Graphics g) {
super.paint(g);
paintComponent(g);
paintBorder(g);
paintChildren(g);
}
}
Here is the new code. I set the preferred size and then am drawing a filled yellow rectangle and the a black border. The border does not appear to be showing on the bottom and right hand size. Can someone try this and see if it works for them.
Code that will throw and error
I tried to include these two methods into my JComponent. If I only have the first setSize(...) then everything works. If I also include the commented out version then I will receive and error.
#Override
public void setSize(Dimension d) {
this.setSize(d);
}
// #Override
// public void setSize(int x, int y) {
// Dimension d = new Dimension(x,y);
// this.setSize(d);
// }
Error:
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
at testpak.MyComponent.setSize(MyComponent.java:15)
JPanel uses FlowLayout which respects preferred sizes of components. You need to override getPreferredSize for MyComponent.
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 400);
}
Also only use frame.pack() instead of setSize before making the frame visible.
You don't need to worry about the extra panel that you have in your code above, you can just do this:
frame.setLayout(new BorderLayout());
frame.add(cc, BorderLayout.CENTER);
This will ensure that your component fills the maximum available space on the frame.

JScrollPane+Canvas: rendering issue

I'm working on a Java version of MS Paint. You can see what it looks like so far here. (images are far too tall and many to embed in a question)
It uses a JScrollPane to move a subclass of Canvas around. If you don't resize the Window, it operates just fine. If you make the window smaller, at first glance it appears to work just the same.
However, if you scroll around, it becomes apparent that the application is rendering the same "viewport", just moved. If you keep scrolling, it becomes more obvious that it overlaps everything else.
So basically, it's rendering the wrong viewport. Resizing the window updates the viewport to be correct. If you try to draw on a grey area, it draws it just fine, you just can't see it.
I've tried doing repaint() on the canvas any time the scrollbars are moved. It didn't change anything.
What should I do to fix this?
This is the code for the frame: (argument img is the image it will paint on. You have to do setVisible(true) yourself as well)
import java.awt.*;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
public class JPaint extends JFrame {
JPaintPanel panel;
public JPaint(BufferedImage img) {
super("Edit your image");
panel = new JPaintPanel(img);
setContentPane(panel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Trial and error got me these numbers.
//I have no idea how find the proper size...
setSize(img.getWidth()+20-1, img.getHeight()+50+50+2);
}
//go to the panel you hold, ask it to retrieve it from the canvas
public BufferedImage grabImage() {
return panel.grabImage();
}
}
class JPaintPanel extends JPanel {
JTools toolbar;
JCanvas canvas;
JScrollPane scrollPane;
public JPaintPanel(BufferedImage img) {
super(new BorderLayout());
toolbar = new JTools();
canvas = new JCanvas(img);
JScrollPane scrollPane = new JScrollPane(canvas);
scrollPane.getHorizontalScrollBar().addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
canvas.repaint();
}
});
scrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
canvas.repaint();
}
});
setPreferredSize(new Dimension(img.getWidth(),img.getHeight()+50));
add(toolbar, BorderLayout.PAGE_START);
add(scrollPane, BorderLayout.CENTER);
}
public BufferedImage grabImage() {
return canvas.getImage();
}
}
class JTools extends JPanel {
JSlider scale;
public JTools() {
scale= new JSlider(JSlider.HORIZONTAL,
0, 400, 100);
scale.setMajorTickSpacing(100);
scale.setPaintTicks(true);
scale.setPaintLabels(true);
scale.setPreferredSize(new Dimension(300,50));
add(scale);
}
}
class JCanvas extends Canvas {
BufferedImage im;
Graphics2D g2d;
Point old = new Point();
Point now = new Point();
public JCanvas(BufferedImage imIn) {
im = imIn;
g2d = im.createGraphics();
setPreferredSize(new Dimension(im.getWidth(), im.getHeight()));
setColor(Color.WHITE);
setWidth(4);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//g2d.drawRect(5, 5, 40, 20);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
//System.out.println(e.getPoint());
//g2d.fillRect(e.getX()-5, e.getY()-5, 10, 10);
old=e.getPoint();
now=e.getPoint();
g2d.drawLine(e.getX(), e.getY(), e.getX(), e.getY());
repaint();
}
});
addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
//System.out.println(e.getPoint());
old=e.getPoint();
now=e.getPoint();
g2d.drawLine(e.getX(), e.getY(), e.getX(), e.getY());
repaint();
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
//System.out.println(e.getPoint());
//g2d.fillRect(e.getX()-5, e.getY()-5, 10, 10);
old=now;
now=e.getPoint();
g2d.drawLine((int)old.getX(), (int)old.getY(), (int)now.getX(), (int)now.getY());
repaint();
}
});
}
public void paint(Graphics g) {
//super.paint(g);
update(g);
}
public void update(Graphics g) {
//super.update(g);
g.drawImage(im, 0, 0, null);
getToolkit().sync();
}
public void setWidth(float w) {
g2d.setStroke(new BasicStroke(w, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
}
public void setColor(Color c) {
g2d.setColor(c);
}
public BufferedImage getImage() {
return im;
}
}
class JCanvas extends Canvas {
Don't mix Swing with AWT components without good cause. Extend a JComponent instead.

Categories

Resources