Wrap xuggler inside a JPanel - java

I am unable to find any post that clearly demonstrates how to wrap Xuggler within a JPanel. I can see some posts for JFrame though, but the solution doesn't easily translate to JPanel. (Or maybe I am too naive!)
To be more specific, the following method does not work for JPanel as it does for JFrame -
private class MyVideoFrame extends JFrame
{
....
public void paint(Graphics g)
{
if (image != null)
{
g.drawImage(image, 0, 0, null);
}
}
}
Thanks!

The VideoImage source actually uses JComponent, which is not the best choice, but is the parent to JPanel.
The fact they've overridden paint and failed to call super.paint is a really bad example.
Instead, they should have used a JPanel (it's not transparent by default), overridden paintComponent and called super.paintComponent before rendering the frame.
So based on DecodeAndPlayAudioAndVideo or DecodeAndPlayVideo
You should be able to replace the reference to com.xuggle.xuggler.demos.VideoImage with the one below, which uses a JPanel as the main container for the vide frame container for displaing...
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class VideoImage extends JFrame {
private final ImagePane mOnscreenPicture;
public VideoImage() {
super();
mOnscreenPicture = new ImagePane();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().add(mOnscreenPicture);
this.setVisible(true);
this.pack();
}
public void setImage(final BufferedImage aImage) {
mOnscreenPicture.setImage(aImage);
}
//....Inner class here....//
public class ImagePane extends JPanel {
private BufferedImage mImage;
public void setImage(BufferedImage image) {
SwingUtilities.invokeLater(new ImageRunnable(image));
}
#Override
public Dimension getPreferredSize() {
return mImage == null ? new Dimension(200, 200) : new Dimension(mImage.getWidth(), mImage.getHeight());
}
private class ImageRunnable implements Runnable {
private final BufferedImage newImage;
public ImageRunnable(BufferedImage newImage) {
super();
this.newImage = newImage;
}
#Override
public void run() {
ImagePane.this.mImage = newImage;
Dimension size = getPreferredSize();
final Dimension newSize = new Dimension(mImage.getWidth(), mImage.getHeight());
if (!newSize.equals(size)) {
VideoImage.this.invalidate();
VideoImage.this.revalidate();
VideoImage.this.pack();
repaint();
}
repaint();
}
}
public ImagePane() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (mImage != null) {
g.drawImage(mImage, 0, 0, this);
}
}
}
}

Related

Adding markers on a map - labels on a lable, on button click Java Netbeans [duplicate]

I used JFrame to import and display an image, and used mousemotionlistener to detect the mouse clicks, and I want to be able to draw on top of the image. I want to be able to, if the user makes a click, make that pixel a certain color while preserving the rest of the image, however, I couldn't find out how to use Graphics to do so without deleting the rest of the image or opening a new window.
public class Simple extends JFrame{
static ImageIcon icon;
static JFrame myframe;
static JLabel mylabel;
static BufferedImage image = null;
public static void main(String[] args) {
try{
image = ImageIO.read(new File("mypic.png"));
}
catch (IOException e) {
e.printStackTrace();
}
icon=new ImageIcon(image);
myframe=new JFrame();
myframe.setSize(200,200);
myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mylabel=new JLabel();
mylabel.setIcon(icon);
myframe.getContentPane().add(mylabel);
myframe.pack();
Container container = myframe.getContentPane();
MouseMotionEvents3 mousemotion = new MouseMotionEvents3();
container.add(mousemotion);
myframe.setVisible(true);
while(1 == 1) {
if(mousemotion.signal == true) {
System.out.println("second message");
mousemotion.signal = false;
}
}
}
}
class MouseMotionEvents3 extends JPanel implements MouseListener,
MouseMotionListener {
public boolean signal;
public MouseMotionEvents3() {
addMouseListener(this);
addMouseMotionListener(this);
signal = false;
}
public void mouseClicked(MouseEvent me) {
// System.out.println("i hate you");
}
public void mouseEntered(MouseEvent me) {
}
public void mouseExited(MouseEvent me) {
}
public void mousePressed(MouseEvent me) {
signal = true;
System.out.println("message");
}
public void mouseReleased(MouseEvent me) {
}
public void mouseDragged(MouseEvent me) {
}
public void mouseMoved(MouseEvent me) {
}
}
I would highly recommend that you start by having a read through Performing Custom Painting and the 2D Graphics Trail, they will provide you with a starting point.
There are a number of ways you might achieve this, this example simply keeps track of the click points and draws dots over the top of the image
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<Point> points;
private BufferedImage image;
public TestPane() {
points = new ArrayList<>(25);
try {
image = ImageIO.read(new File("/Users/shanewhitehead/Desktop/Screen Shot 2017-03-09 at 1.55.18 pm.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
points.add(e.getPoint());
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(200, 200) : new Dimension(image.getWidth(), image.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (image != null) {
g2d.drawImage(image, 0, 0, this);
}
g2d.setColor(Color.RED);
for (Point p : points) {
g2d.fillOval(p.x - 4, p.y - 4, 8, 8);
}
g2d.dispose();
}
}
}
This example draws the dots directly to the image itself...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage image;
public TestPane() {
try {
image = ImageIO.read(new File("/Users/shanewhitehead/Desktop/Screen Shot 2017-03-09 at 1.55.18 pm.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (image != null) {
Point p = e.getPoint();
Graphics2D g2d = image.createGraphics();
g2d.setColor(Color.RED);
g2d.fillOval(p.x - 4, p.y - 4, 8, 8);
g2d.dispose();
repaint();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(200, 200) : new Dimension(image.getWidth(), image.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(image, 0, 0, this);
g2d.dispose();
}
}
}
In both cases, they simply make use of the Graphics2D API
The simplest method would be to have a list of points that represent the pixels you wish to colour. Then override the paint method for the label to first call super.paint (to display the image) and then paint the pixels that have been clicked.
List<Point> points = new ArrayList<>();
myLabel = new JLabel() {
#Override
public void paint(Graphics g) {
super.paint(g);
points.forEach(p -> g.fillRect(p.x, p.y, 1, 1));
}
};
In your mouse handling just add the current point to the list and repaint the label.
public void mouseClicked(MouseEvent me) {
points.add(me.getPoint());
myLabel.repaint();
}
There are more sophisticated methods that involve buffered images but this is likely good enough to get you started.
I figured it out, I can use the getGraphics() method of the JFrame to allow myself to draw on top of the image.
edit: Andrew Thompson is right, minimizing the window removes the changes.

How to draw on top of an image in Java?

I used JFrame to import and display an image, and used mousemotionlistener to detect the mouse clicks, and I want to be able to draw on top of the image. I want to be able to, if the user makes a click, make that pixel a certain color while preserving the rest of the image, however, I couldn't find out how to use Graphics to do so without deleting the rest of the image or opening a new window.
public class Simple extends JFrame{
static ImageIcon icon;
static JFrame myframe;
static JLabel mylabel;
static BufferedImage image = null;
public static void main(String[] args) {
try{
image = ImageIO.read(new File("mypic.png"));
}
catch (IOException e) {
e.printStackTrace();
}
icon=new ImageIcon(image);
myframe=new JFrame();
myframe.setSize(200,200);
myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mylabel=new JLabel();
mylabel.setIcon(icon);
myframe.getContentPane().add(mylabel);
myframe.pack();
Container container = myframe.getContentPane();
MouseMotionEvents3 mousemotion = new MouseMotionEvents3();
container.add(mousemotion);
myframe.setVisible(true);
while(1 == 1) {
if(mousemotion.signal == true) {
System.out.println("second message");
mousemotion.signal = false;
}
}
}
}
class MouseMotionEvents3 extends JPanel implements MouseListener,
MouseMotionListener {
public boolean signal;
public MouseMotionEvents3() {
addMouseListener(this);
addMouseMotionListener(this);
signal = false;
}
public void mouseClicked(MouseEvent me) {
// System.out.println("i hate you");
}
public void mouseEntered(MouseEvent me) {
}
public void mouseExited(MouseEvent me) {
}
public void mousePressed(MouseEvent me) {
signal = true;
System.out.println("message");
}
public void mouseReleased(MouseEvent me) {
}
public void mouseDragged(MouseEvent me) {
}
public void mouseMoved(MouseEvent me) {
}
}
I would highly recommend that you start by having a read through Performing Custom Painting and the 2D Graphics Trail, they will provide you with a starting point.
There are a number of ways you might achieve this, this example simply keeps track of the click points and draws dots over the top of the image
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<Point> points;
private BufferedImage image;
public TestPane() {
points = new ArrayList<>(25);
try {
image = ImageIO.read(new File("/Users/shanewhitehead/Desktop/Screen Shot 2017-03-09 at 1.55.18 pm.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
points.add(e.getPoint());
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(200, 200) : new Dimension(image.getWidth(), image.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (image != null) {
g2d.drawImage(image, 0, 0, this);
}
g2d.setColor(Color.RED);
for (Point p : points) {
g2d.fillOval(p.x - 4, p.y - 4, 8, 8);
}
g2d.dispose();
}
}
}
This example draws the dots directly to the image itself...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage image;
public TestPane() {
try {
image = ImageIO.read(new File("/Users/shanewhitehead/Desktop/Screen Shot 2017-03-09 at 1.55.18 pm.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (image != null) {
Point p = e.getPoint();
Graphics2D g2d = image.createGraphics();
g2d.setColor(Color.RED);
g2d.fillOval(p.x - 4, p.y - 4, 8, 8);
g2d.dispose();
repaint();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(200, 200) : new Dimension(image.getWidth(), image.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(image, 0, 0, this);
g2d.dispose();
}
}
}
In both cases, they simply make use of the Graphics2D API
The simplest method would be to have a list of points that represent the pixels you wish to colour. Then override the paint method for the label to first call super.paint (to display the image) and then paint the pixels that have been clicked.
List<Point> points = new ArrayList<>();
myLabel = new JLabel() {
#Override
public void paint(Graphics g) {
super.paint(g);
points.forEach(p -> g.fillRect(p.x, p.y, 1, 1));
}
};
In your mouse handling just add the current point to the list and repaint the label.
public void mouseClicked(MouseEvent me) {
points.add(me.getPoint());
myLabel.repaint();
}
There are more sophisticated methods that involve buffered images but this is likely good enough to get you started.
I figured it out, I can use the getGraphics() method of the JFrame to allow myself to draw on top of the image.
edit: Andrew Thompson is right, minimizing the window removes the changes.

Multiple problems regarding Java paint program while painting

I have a Java paint program, and I've got two problems to do with it. Both problems are relatively simple, and just regard how the mouse input is handled and how the image uses colors. Here's a photo of the app:
So here's my first problem:
As you can see, by the look of the app, there's a spray of dots on the paint area. Each of those dots is a mouseclick. The program does not recognize when a user is holding down the mouse button, so you have to click individually.
This is obviously counterproductive, user-unfriendly and unacceptable. Now, how I fix this, I'm not sure. I've tried using a permanent while (true) loop, but that does not work. How do I make it so that instead of having to click every time, each time the mouse is held down it sprays out dots?
The second problem is the color of the dots. As you can see, at the bottom, there are color buttons. These function, but there is a problem: Whenever I change the color, all the dots currently on the screen change color. The color is run by a variable called currentColor which is run by the actionListeners controlled by all the color buttons on the bottom panel. How do I make sure that colors already placed on the screen are not affected anymore?
I believe that all the code that can be fixed for these two problems lies in my custom JPanel which is used for the program to paint on. I'll post the entire class below, and if you have any other questions, please let me know.
int xCord, yCord;
public class PaintPanel extends JPanel implements MouseListener {
// default serial whatever...
private static final long serialVersionUID = -6514297510194472060L;
public PaintPanel() {
addMouseListener(this);
}
ArrayList<Point> points = new ArrayList<Point>();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Point point : points) {
g.setColor(currentColor);
g.fillOval(point.x, point.y, 12, 12);
}
repaint();
}
#Override
public void mouseClicked(MouseEvent m) {
}
#Override
public void mouseEntered(MouseEvent m) {
}
#Override
public void mouseExited(MouseEvent m) {
}
#Override
public void mousePressed(MouseEvent m) {
if (paintPanel.contains(m.getPoint())) {
points.add(m.getPoint());
xCord = m.getX();
yCord = m.getY();
System.out.println("x: " + xCord + " y: " + yCord);
}
}
#Override
public void mouseReleased(MouseEvent m) {
}
}
Painting in Swing is destructive.
That is to say, when Swing requests that a repaint occur on a component, the component is expected to clear what ever was previously paint and update itself.
The problem with your color issue is that you only ever have a single color specified.
A possible solution would be to paint to backing buffer (like BufferedImage) instead of relying on paintComponent.
Instead of repainting all the dots each time paintComponent is called, you would simply paint the BufferedImage instead.
As to your issue with the mouse, you need to implement a MouseMotionListener, this will allow you to detect when the mouse is dragged across the surface, painting a trail of dots
Update with very BASIC 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.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SimplePaint04 {
public static void main(String[] args) {
new SimplePaint04();
}
public SimplePaint04() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private PaintPane paintPane;
public TestPane() {
setLayout(new BorderLayout());
add((paintPane = new PaintPane()));
add(new ColorsPane(paintPane), BorderLayout.SOUTH);
}
}
public class ColorsPane extends JPanel {
public ColorsPane(PaintPane paintPane) {
add(new JButton(new ColorAction(paintPane, "Red", Color.RED)));
add(new JButton(new ColorAction(paintPane, "Green", Color.GREEN)));
add(new JButton(new ColorAction(paintPane, "Blue", Color.BLUE)));
}
public class ColorAction extends AbstractAction {
private PaintPane paintPane;
private Color color;
private ColorAction(PaintPane paintPane, String name, Color color) {
putValue(NAME, name);
this.paintPane = paintPane;
this.color = color;
}
#Override
public void actionPerformed(ActionEvent e) {
paintPane.setForeground(color);
}
}
}
public class PaintPane extends JPanel {
private BufferedImage background;
public PaintPane() {
setBackground(Color.WHITE);
setForeground(Color.BLACK);
MouseAdapter handler = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
drawDot(e.getPoint());
}
#Override
public void mouseDragged(MouseEvent e) {
drawDot(e.getPoint());
}
};
addMouseListener(handler);
addMouseMotionListener(handler);
}
protected void drawDot(Point p) {
if (background == null) {
updateBuffer();;
}
if (background != null) {
Graphics2D g2d = background.createGraphics();
g2d.setColor(getForeground());
g2d.fillOval(p.x - 5, p.y - 5, 10, 10);
g2d.dispose();
}
repaint();
}
#Override
public void invalidate() {
super.invalidate();
updateBuffer();
}
protected void updateBuffer() {
if (getWidth() > 0 && getHeight() > 0) {
BufferedImage newBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = newBuffer.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, getWidth(), getHeight());
if (background != null) {
g2d.drawImage(background, 0, 0, this);
}
g2d.dispose();
background = newBuffer;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (background == null) {
updateBuffer();
}
g2d.drawImage(background, 0, 0, this);
g2d.dispose();
}
}
}

draw a movable canvas on Jpanel

i want to draw a canvas that will be movable on a Jpanel. That is when the user clicks on the canvas and drags it it must move to a new positon. i have implemented the MouseMotionListener but i have no idea of what to include inside to make the canvas move as per requierements. here is the DisplayCanvas class:
class DisplayCanvas extends Canvas
{
public DisplayCanvas()
{
setBounds(20, 40, 300, 300);
setBackground(Color.white);
}
}
class shape extends JFrame implements MouseMotionListener{
static JPanel panel;
static Container contentpane;
static DisplayCanvas canvas;
shape()
{
canvas=new DisplayCanvas();
canvas.addMouseMotionListener(this);
panel= new JPanel();
panel.setBounds(20,20,250,140);
panel.setLayout(null);
contentpane = getContentPane();
contentpane.add(canvas);
contentpane.add(panel);
}
#Override
public void mouseDragged(MouseEvent e) {}
#Override
public void mouseMoved(MouseEvent arg0) {}
}
this is how i test it.
public class display
{
static JFrame frame;
public static void main(String[] args)
{
frame=new shape();
frame.setBounds(380, 200, 500, 400);
frame.setTitle("SHAPE AND COLOR");
frame.setVisible(true);
}
}
NB: please do not suggest that i use the JPanel am required to use the canvas.
The fact you don't want to extend JPanel seems quite weird but it is not unfeasible. Yet you will likely encounter issues at some point because you are mixing lightweight and heavyweight components. You will probably have visual glitches and other display issues.
However I would draw your attention to several important mistakes you made in your current code:
Don't extends classes if not needed (no need to extend JFrame nor Canvas)
Don't make variables static unless absolutely necessary
Follow Java naming conventions: class names always start with an Upper-case letter
Don't use a null LayoutManager.
Here is a snippet illustrating very basic way you can make this work (code needs to be refactored to separate aspects properly)
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager2;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestHeavyweightLightweight {
public class MyLayoutManager implements LayoutManager2 {
private Map<Component, Rectangle> constraints = new LinkedHashMap<Component, Rectangle>();
#Override
public void addLayoutComponent(String name, Component comp) {
constraints.put(comp, comp.getBounds());
}
#Override
public void removeLayoutComponent(Component comp) {
constraints.remove(comp);
}
#Override
public Dimension preferredLayoutSize(Container parent) {
Rectangle rect = new Rectangle();
for (Rectangle r : constraints.values()) {
rect = rect.union(r);
}
return rect.getSize();
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}
#Override
public void layoutContainer(Container parent) {
for (Map.Entry<Component, Rectangle> e : constraints.entrySet()) {
e.getKey().setBounds(e.getValue());
}
}
#Override
public void addLayoutComponent(Component comp, Object constraints) {
if (constraints instanceof Rectangle) {
this.constraints.put(comp, (Rectangle) constraints);
} else {
addLayoutComponent((String) null, comp);
}
}
#Override
public Dimension maximumLayoutSize(Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
#Override
public float getLayoutAlignmentX(Container target) {
return 0;
}
#Override
public float getLayoutAlignmentY(Container target) {
return 0;
}
#Override
public void invalidateLayout(Container target) {
}
public void setConstraints(Component component, Rectangle rect) {
constraints.put(component, rect);
}
public class MouseDragger extends MouseAdapter {
private Point lastLocation;
private Component draggedComponent;
#Override
public void mousePressed(MouseEvent e) {
draggedComponent = e.getComponent();
lastLocation = SwingUtilities.convertPoint(draggedComponent, e.getPoint(), draggedComponent.getParent());
}
#Override
public void mouseDragged(MouseEvent e) {
Point location = SwingUtilities.convertPoint(draggedComponent, e.getPoint(), draggedComponent.getParent());
if (draggedComponent.getParent().getBounds().contains(location)) {
Point newLocation = draggedComponent.getLocation();
newLocation.translate(location.x - lastLocation.x, location.y - lastLocation.y);
newLocation.x = Math.max(newLocation.x, 0);
newLocation.x = Math.min(newLocation.x, draggedComponent.getParent().getWidth() - draggedComponent.getWidth());
newLocation.y = Math.max(newLocation.y, 0);
newLocation.y = Math.min(newLocation.y, draggedComponent.getParent().getHeight() - draggedComponent.getHeight());
setConstraints(draggedComponent, new Rectangle(newLocation, draggedComponent.getSize()));
if (draggedComponent.getParent() instanceof JComponent) {
((JComponent) draggedComponent.getParent()).revalidate();
} else {
draggedComponent.getParent().invalidate();
draggedComponent.getParent().validate();
}
lastLocation = location;
}
}
#Override
public void mouseReleased(MouseEvent e) {
lastLocation = null;
draggedComponent = null;
}
public void makeDraggable(Component component) {
component.addMouseListener(this);
component.addMouseMotionListener(this);
}
}
}
private Canvas canvas;
private JPanel panel;
protected void createAndShowGUI() {
JFrame frame = new JFrame(TestHeavyweightLightweight.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canvas = new Canvas();
canvas.setBackground(Color.WHITE);
panel = new JPanel();
MyLayoutManager mgr = new MyLayoutManager();
panel.setLayout(mgr);
panel.add(canvas, new Rectangle(20, 40, 300, 300));
MyLayoutManager.MouseDragger mouseDragger = mgr.new MouseDragger();
mouseDragger.makeDraggable(canvas);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestHeavyweightLightweight().createAndShowGUI();
}
});
}
}

JButton isn't in the right place when a BufferedImage is used in it's container

I'm trying to create a simple game using AWT but I want to have some JButtons aswell to exit/reset the game. The problem is, I want the BufferedImage to be drawn inside the visible frame like so in my container I have this at the end:
g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);
My problem is, when I add a JButton to that frame, it only detects rollover in space that doesn't take into account the offsetting, but is drawn in a space that does. This is the relevant code (con is the container).
private void addButtons()
{
reset = new JButton("reset");
reset.setBounds(180,460, 75,30);
reset.addActionListener( this );
con.add(reset);
exit = new JButton("exit");
exit.setBounds(290,460, 60,30);
exit.addActionListener( this );
con.add(exit);
con.repaint();
}
The paint method in the Container
public void paint(Graphics g)
{
bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics b = bf.getGraphics();
b.setColor(Color.GRAY);
b.fillRect(0, 0, this.getWidth(), this.getHeight());
b.setColor(Color.BLACK);
b.drawRect(0,0,420,420);
super.paint(b);
g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);
}
How can I make the button be drawn and detected in the same spot?
here is a screenshot of the problem
As requested:
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class Draw implements ActionListener{
private SnakeFrame frame;
private SnakeCon con;
JButton reset, exit;
private boolean res;
public Draw()
{
frame = new SnakeFrame("Snake");
frame.setResizable(false);
frame.setLayout(null);
frame.setSize(600,600);
frame.setVisible(true);
con = new SnakeCon();
con.setBounds(0,0,600,600);
frame.add(con);
}
private void addButtons()
{
reset = new JButton("reset");
reset.setBounds(180,460, 75,30);
reset.addActionListener( this );
con.add(reset);
exit = new JButton("exit");
exit.setBounds(290,460, 60,30);
exit.addActionListener( this );
con.add(exit);
con.repaint();
}
public void run()
{
addButtons();
res = false;
boolean dead = false;
while(!dead)
{
if( (res) )
dead = true;
if (!dead)
{
try{
Thread.sleep(100);
}
catch (Exception e)
{}
frame.repaint();
}
}
con.removeAll();
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == reset)
res = true;
else if (e.getSource() == exit)
System.exit(0);
}
}
--
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class SnakeCon extends Container{
private BufferedImage bf;
public SnakeCon()
{
super();
setBounds(0,0,600,600);
}
public void paint(Graphics g)
{
bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics b = bf.getGraphics();
b.setColor(Color.GRAY);
b.fillRect(0, 0, this.getWidth(), this.getHeight());
b.setColor(Color.BLACK);
b.drawRect(0,0,420,420);
super.paint(b);
g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);
}
public void update(Graphics g)
{
paint(g);
}
}
--
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class SnakeFrame extends Frame implements WindowListener{
private BufferedImage bf;
public SnakeFrame(String s)
{
super(s);
addWindowListener( this );
}
public void paint(Graphics g)
{
bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics b = bf.getGraphics();
super.paint(b);
g.drawImage(bf,0,0,null);
}
public void update(Graphics g)
{
paint(g);
}
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
public void windowClosed(WindowEvent e) { }
public void windowOpened(WindowEvent e) { }
public void windowIconified(WindowEvent e) { }
public void windowDeiconified(WindowEvent e) { }
public void windowActivated(WindowEvent e) { }
public void windowDeactivated(WindowEvent e) { }
}
--
public class Main {
public static void main(String[] args)
{
boolean never = false;
Draw d = new Draw();
while(!never)
{
d.run();
}
System.exit(0);
}
}
Im not sure exactly what is wrong/what you want (why do you have a loop to constantly drawing buttons and invoking removeAll()? etc but i cant shake the feeling it might be implemented in a more readable/efficient way)...
But here are some suggestions that can only help your code get better:
Dont use null/Absolute Layout choose an appropriate LayoutManager.
Do not override JFrame paint(..), rather add JPanel to JFrame and override paintComponent(Graphics g) of JPanel and do drawing there.(Do not forget to have super.paintComponent(..) as 1st call in overriden paintComponent method. See here for more: Performing Custom Painting
Do not set JFrame visible before adding all components to JFrame
Always create and manipulate Swing components on Event Dispatch Thread like so:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//create Swing components
}
});
Do not do long running tasks on Event Dispatch Thread rather use Swing Timer/Swing Worker
Do not call setSize(..) on JFrame rather override getPreferredSize() of JPanel and return Dimensions which fit all components (see here for reasoning), than call pack() on JFrame before setting it visible
Dont extend JFrame unnecessarily or Container!
Adding WindowListener for detecting JFrame exit is not worth the lines rather use:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
to exit Swing application when X is pressed.

Categories