Copy and modify your canvas to implement the KeyListener interface, add itself as its own KeyListener , and call setFocusable(true) in order to receive keyboard focus. When a key is typed, your program should draw the corresponding character (see KeyEvent.getKeyChar() ) on the canvas at the location of the last mouse event. If another key is typed without the mouse being clicked, then draw the next character to
the right of the previous one as if you were typing in a text field. Again, think about what state you need to maintain to do this. It doesn’t have to be perfect (you can hard-code the width of the characters if you like).
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Canvas05 extends JComponent implements KeyListener {
public Canvas05() {
addKeyListener(this);
setFocusable(true);
}
#Override
public void keyTyped(KeyEvent e) {
System.out.print(e.getKeyChar());
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
public static void main (String[] args){
Canvas05 c = new Canvas05();
JFrame frame = new JFrame("Q05");
frame.add(c);
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Here you go. The location from mouseEvent is very easily acessable from the MouseListener event where you can declare both an x and a y variable from
MouseListener.getX() and MouseListener.getY();
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JPanel{
public static int WIDTH = 500,HEIGHT = 500;
public static char myChar = ' ';
public static Game game = new Game();
public static JFrame frame = new JFrame();
public Game() {
this.addKeyListener(new KeyListener(){
public void keyPressed(KeyEvent e) {
myChar = (char)e.getKeyCode();
repaint();
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
});
setFocusable(true);
}
public void paint(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g.clearRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.red);
g.setFont(new Font("Cambria",Font.BOLD,30));
g.drawString(String.valueOf(myChar),100, 100);
}
public static void main(String [] args){
frame.add(game);
frame.setSize(WIDTH, HEIGHT);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Related
I have been creating a 2D camera in Swing. But then I discovered that if I use graphics.translate (to move the origin of coordinates) and set the position of the children using coordinates relative to the start of the world, unexpected behavior occurs:
In my original program, the JComponents don't redraw when they should.
In the published mcve, the image is still drawn where it was initially created, as well as being drawn on the correct side and not updating anymore.
The idea would be that, having the coordinates relative to the start of the "world", that the redraw process automatically converts that into coordinates relative to the JPanel.
What would be the correct way to achieve it without directly using the coordinates relative to the JPanel.
Application.java
package regexlang;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class Application extends JFrame{
public Application() {
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new Panel());
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
Application ex = new Application();
ex.setVisible(true);
});
}
}
Panel.java
package regexlang;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
#SuppressWarnings("serial")
public class Panel extends JPanel implements ActionListener, KeyListener{
private int x;
private int y;
private JLabel label;
public Panel() {
setLayout(null);
setBackground(Color.black);
addKeyListener(this);
setFocusable(true);
this.label = new JLabel("hola mundo");
this.label.setBounds(700, 0, 100, 100);
this.label.setOpaque(true);
add(this.label);
Timer timer = new Timer(1000, this);
timer.setRepeats(true);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.translate(-this.x, -this.y);
}
public void paintComponents(Graphics g) {
g.translate(-this.x, -this.y);
super.paintComponents(g);
}
#Override
public void actionPerformed(ActionEvent e) {
Random random = new Random();
Color color = new Color(random.nextInt(256),
random.nextInt(256),
random.nextInt(256));
this.label.setBackground(color);
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
this.x += 1;
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
Edit After some more thinking, I have a hypothesis that the coordinates used by swing are calculated before it gets to translate the origin of coordinates with Graphics.translate. I've tried to get around this by overriding the getGraphics method, to no avail (since it doesn't seem to be used much internally).
This is a word-for-word example straight out of the book Java How to Program by Paul and Harvey Deitel.
PaintPanel.java
// Using class MouseMotionAdapter
import java.awt.Point;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JPanel;
public class PaintPanel extends JPanel {
private int pointCount = 0;
// array of 10,000 java.awt.Point references
private Point[] points = new Point[10000];
// set up gui and register mouse event handler
public PaintPanel() {
addMouseMotionListener(new MouseMotionAdapter() {
// store drag coordinates and repaint
public void MouseDragged(MouseEvent e) {
if (pointCount < points.length) {
points[pointCount] = e.getPoint();
pointCount++;
repaint();
} // end if
}
}
);
}
// draw ovals in a 4 x 4 bounding box at specified location on the window
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // clear drawing area
g.setColor(Color.BLUE);
// draw all points in the array
for(int i = 0; i < pointCount; i++)
g.fillOval(points[i].x, points[i].y, 4, 4);
}
}
Driver program Painter.java
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Painter {
public static void main(String[] args) {
JFrame app = new JFrame("A Simple Paint Program");
PaintPanel pp = new PaintPanel();
app.add(pp, BorderLayout.CENTER);
app.add(new JLabel("Drag the rat to draw"), BorderLayout.SOUTH);
app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
app.setSize(400, 200);
app.setVisible(true);
}
}
When I run it, it shows the drawing panel but nothing happens when I try to draw on it with the mouse. All code is copied verbatim from the book. What gives?
Java is case sensitive. It's mouseDragged, not MouseDragged. This is why you should always use #Override on methods you "think" you're overriding, this way you get compile time protection.
Runnable example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new PaintPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintPanel extends JPanel {
private int pointCount = 0;
// array of 10,000 java.awt.Point references
private Point[] points = new Point[10000];
// set up gui and register mouse event handler
public PaintPanel() {
addMouseMotionListener(new MouseMotionAdapter() {
// store drag coordinates and repaint
#Override
public void mouseDragged(MouseEvent e) {
if (pointCount < points.length) {
points[pointCount] = e.getPoint();
pointCount++;
repaint();
} // end if
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
// draw ovals in a 4 x 4 bounding box at specified location on the window
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // clear drawing area
g.setColor(Color.BLUE);
// draw all points in the array
for (int i = 0; i < pointCount; i++) {
g.fillOval(points[i].x, points[i].y, 4, 4);
}
}
}
}
I have written a Java code to draw a polygon on an image. When I put my cursor inside the polygon it prints "Inside" otherwise "Outside". So the detection of the points inside the polygon is working fine.
But I want to implement the effect of setToolTipText inside the polygon i.e. at the time of mouse hover inside the polygon, it will show the floating text "Inside".
Similar to the effect in this image:
http://www.java2s.com/Code/Java/Swing-JFC/WorkingwithTooltipText.htm
What are the minimal changes to be made in the following code to get the desired effect?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.image.*;
import java.awt.Graphics.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
class page1 extends JFrame implements MouseListener,MouseMotionListener ,ActionListener
{
JFrame f;
JLabel l;
JPanel p1;
ImageIcon ii;
Image img;
int height;
int width;
Container c;
int pixels[];
PixelGrabber pg;
JPanel panel;
Graphics2D gg;
Polygon pp1=new Polygon();
boolean startHovercurrent,startHoverprev=false;
page1()
{
f=new JFrame("Sample Page");
ii=new ImageIcon("sample.jpg");
img=ii.getImage();
height=ii.getIconHeight();
width=ii.getIconWidth();
pixels=new int[ii.getIconWidth()*ii.getIconHeight()];
pg=new PixelGrabber(img,0,0,ii.getIconWidth(),ii.getIconHeight(),pixels,0,ii.getIconWidth());
try
{
pg.grabPixels();
}
catch(InterruptedException k)
{
}
//add points of polygon
pp1.addPoint(300,300);
pp1.addPoint(380,300);
pp1.addPoint(380,220);
pp1.addPoint(300,220);
l=new JLabel(ii,JLabel.CENTER);
c=f.getContentPane();
JDesktopPane desk = new JDesktopPane();
JInternalFrame p = new JInternalFrame("Image Frame",false, false, true, false);
JScrollPane scroll = new JScrollPane(l);
p.setContentPane(scroll);
p.setBounds(0, 0, 740, 600);
desk.add(p);
p.setVisible(true);
l.addMouseListener(this);
l.addMouseMotionListener(this);
c.add(desk, BorderLayout.CENTER);
f.setSize(1024,738);
f.setVisible(true);
}
public static void main(String args[])
{
new page1();
}
public void mouseClicked(MouseEvent me)
{
}
public void mouseEntered(MouseEvent me)
{
}
public void mouseExited(MouseEvent me)
{
}
public void mousePressed(MouseEvent me)
{
}
public void mouseReleased(MouseEvent me)
{
}
public void mouseMoved(MouseEvent me)
{
boolean contain1;
int mx,my;
gg=(Graphics2D)l.getGraphics();
gg.setColor(new Color(255,0,0) );
gg.fillPolygon(pp1);
mx = me.getX();
my = me.getY();
//check if mouse cursor is inside polygon or not
// do not print anything if next cursor position is in same state
contain1=pp1.contains(mx,my);
if (contain1) {
startHovercurrent = true;
if(startHovercurrent!=startHoverprev)
System.out.println("Inside");
startHoverprev=startHovercurrent;
}
else {
startHovercurrent = false;
if(startHovercurrent!=startHoverprev)
System.out.println("Outside");
startHoverprev=startHovercurrent;
}
}
public void mouseDragged(MouseEvent me)
{
}
public void actionPerformed(ActionEvent ae)
{
}
}
For this usage, How to Use Tool Tips suggests overriding the getToolTipText() method of the enclosing JComponent. This answer outlines the approach for JMapViewer and ChartPanel. In the example below, getToolTipText() simply returns the name of any Shape that contains() the triggering mouse event. For comparison, the JLabel at window's bottom gets a conventional too tip via setToolTipText().
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.ToolTipManager;
/**
* #see https://stackoverflow.com/a/53609066/230513
* #see https://stackoverflow.com/a/25944439/230513
*/
public class ShapeToolTip {
private static class ShapePanel extends JPanel {
private final List<Shape> list = new ArrayList<>();
public ShapePanel() {
Polygon p = new Polygon();
p.addPoint(500, 100);
p.addPoint(500, 400);
p.addPoint(200, 400);
list.add(p);
list.add(new Ellipse2D.Double(100, 100, 200, 200));
ToolTipManager.sharedInstance().registerComponent(this);
}
#Override
public String getToolTipText(MouseEvent e) {
for (Shape shape : list) {
if (shape.contains(e.getX(), e.getY())) {
return shape.getClass().getName();
}
}
return "Outside";
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(2));
for (Shape shape : list) {
g2d.draw(shape);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
}
private void display() {
JFrame f = new JFrame("ShapeToolTip");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new ShapePanel());
JLabel title = new JLabel("Shape Tool Tip", JLabel.CENTER);
title.setToolTipText("Title");
title.setFont(title.getFont().deriveFont(Font.BOLD, 24));
f.add(title, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new ShapeToolTip()::display);
}
}
I am trying to create a graphics drawing program that allows the user to draw red pixels on the screen by dragging their mouse over it. So in a way, you can think of this program as Microsoft's Paint program but with only the pencil drawing tool and color red.
Unfortunately the mouseDragged() function in my program is not working properly. It will skip some of the pixels on the screen if I move my mouse too fast, like this:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FrameView extends JFrame {
JPanel panel;
Graphics2D drawingContext;
public static void main(String[] args) {
new FrameView();
}
public FrameView() {
panel = new JPanel();
panel.addMouseMotionListener(new MouseControls());
panel.setBackground(Color.WHITE);
this.add(panel);
this.setSize(new Dimension(500, 500));
this.setTitle("Drawing Program");
this.setVisible(true);
drawingContext = (Graphics2D)panel.getGraphics();
}
private class MouseControls extends MouseAdapter {
#Override
public void mouseDragged(MouseEvent e) {
int x = e.getX();
int y = e.getY();
final int WIDTH = 1;
final int HEIGHT = 1;
Shape pixel = new Rectangle(x, y, WIDTH, HEIGHT);
drawingContext.setColor(Color.RED);
drawingContext.draw(pixel);
}
}
}
getGraphics is NOT how painting works in Swing, instead, you should be overriding the paintComponent method of the component and performing your custom painting there.
Painting is destructive, it is expected that when ever paintComponent is called, you will completely repaint the current state of the component.
Have a look at Painting in AWT and Swing and Performing Custom Painting for more details
As to you "mouse" problem, this is actually how it works, you won't be notified of EVERY pixel position the mouse has to pass through, your mouse would lag horribly across the screen if it did. Instead, the OS moves the mouse in ever increasing steps based on the speed of the movement of the user input.
Instead of drawing just the points, draw lines between them, for example
nb: I've deliberately painted the points larger so you can see where they are been reported, you will see that all the dots (for a single drag) are connected
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.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
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 TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<List<Point>> points = new ArrayList<>(25);
private List<Point> activeList;
public TestPane() {
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (activeList != null) {
activeList.add(e.getPoint());
repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {
activeList = new ArrayList<>(25);
points.add(activeList);
}
#Override
public void mouseReleased(MouseEvent e) {
if (activeList != null && activeList.isEmpty()) {
points.remove(activeList);
}
activeList = null;
}
};
addMouseMotionListener(ma);
addMouseListener(ma);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
for (List<Point> group : points) {
Point previous = null;
for (Point p : group) {
// You can get rid of this, it's simply to show
// where the points would actually be rendered
g2d.fill(new Ellipse2D.Float(p.x - 2, p.y - 2, 4, 4));
if (previous != null) {
g2d.draw(new Line2D.Float(previous, p));
}
previous = p;
}
}
g2d.dispose();
}
}
}
I am very new to graphics with Java, so just ask if any additional information is needed :)
I am trying to paint shapes based on where the mouse clicks on the screen. Because of this, I need to pass the x and y coordinates of where I clicked to the paintComponent() method so that it will know where to paint the shape.
public void mouseClicked(MouseEvent e) {
System.out.println("Adding Shape");
repaint();
}
class CanvasDrawArea extends JPanel{
//this should run when the program first starts
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
canvas.setBackground(CANVAS_COLOR);
}
//here is where the question is
public void paintComponent(Graphics g, int x, int y){
super.paintComponent(g);
g.fillRect(x, y, RECTANGLE_WIDTH, RECTANGLE_HEIGHT);
}
}
basically I am trying to overload the paintComponent by having one that runs right when the program starts by calling the repaint() / pack() method, and one that will run when I give it the x and y coordinates. I am unsure, however, how I am supposed to go about passing the x and y parameters, as there is no way to pass them in the repaint() method.
You should never have the need to call paintComponent or paint directly these are called automatically by the repaint manager when required...
Create java.util.List and store the Point of each mouse click in it, call repaint from the mouseClicked method after you have done this.
In your paintComponent(Graphics) method, iterate over the List of points and paint the shape you need.
As a simple example...
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.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Dotty {
public static void main(String[] args) {
new Dotty();
}
public Dotty() {
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 DottyPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DottyPane extends JPanel {
private List<Point> points;
public DottyPane() {
points = new ArrayList<>(25);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
points.add(e.getPoint());
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
for (Point p : points) {
g2d.fillOval(p.x - 5, p.y - 5, 10, 10);
}
g2d.dispose();
}
}
}