I have create a program in Java which allows dragging of two oval shapes. Now I want to convert it to a JApplet so I made the class extend JApplet instead of original JPanel. The problem with this is that super.paintComponent(g) does not work as it is no longer a parent class.
I have tried creating a JPanel within the class then referring to this but I get the error: The method paintComponent(Graphics) from the type JComponent is not visible
Any heads up on what I need to do or any help would be much appreciated thanks.
Here is my code.
public class Main extends JPanel
{
private static final String TITLE = "Drag me!";
private static final int W = 640;
private static final int H = 480;
private Point origin = new Point(W / 2, H / 2);
private Point mousePt;
public Main() {
this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
this.addMouseListener(new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent e)
{
mousePt = e.getPoint();
repaint();
}
});
this.addMouseMotionListener(new MouseMotionAdapter()
{
#Override
public void mouseDragged(MouseEvent e)
{
int dx = e.getX() - mousePt.x;
int dy = e.getY() - mousePt.y;
origin.setLocation(origin.x + dx, origin.y + dy);
mousePt = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(W, H);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(0, origin.y, getWidth(), origin.y);
g.drawOval(origin.x, 0, origin.x, getHeight());
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame(TITLE);
f.add(new Main());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
Instead of modifying your JPanel, keep it and create a new class, your JApplet class:
public class YourJApplet extends JApplet{
public void init(){
final JPanel panel = new YourPanel();
this.setContentPane(panel);
}
}
That's it--now whatever was going on with your panel is now your JApplet.
Related
I would like to draw a line between two xy coordinate with mouse drag, but cannot get anything to draw
its a gui application using swing and awt, I currently have the mouse log the initial and final xy positions using mouse events which are stored in an array as [x1,y1,x2,y2], however, cannot get a line to draw between them.
The drawline is its own function called into the main
edit:
say I have 2 classes;
public class mainApp extends JFrame implements ActionListener, Runnable {
private JPanel jpanel = new JPanel();
private mainApp(String title) throws HeadlessException {
super(title);
}
private void createGUI() {
// TODO
// ...
// cannot call unless is static
drawStraightLine.drawLine(jpanel);
this.pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {}
#Override
public void run() {createGUI();}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new mainApp("drawline"));
}
}
public class drawStraightLine extends JPanel {
public static void drawLine(JPanel jpanel) {
// content which conceivably works
// mouselisteners and repaint()
public void paintComponent (Graphics g){
super.paintComponent(g);
if (check != null) {
Color purple = new Color(128, 0, 128);
g.setColor(purple);
g.drawLine(x1, y1, x2, y2);
}
}
}
i cannot call drawline(jpanel) unless it is a static function, but making it static causes the mouselisteners and repaint to become invalid.
while as long as Graphics g is inside a function and not directly in the class it will become an invalid symbol (ignoring check and xy values as placeholders)
you don't need to have arrays or even X & Y.you can use the getPoint() method of mouseEvent.
try this:
public static void main(String args[]) throws Exception {
JFrame f = new JFrame("Draw a Line");
f.setSize(300, 300);
f.setLocation(300, 300);
f.setResizable(false);
JPanel p = new JPanel() {
Point pointStart = null;
Point pointEnd = null;
{
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
pointStart = e.getPoint();
}
public void mouseReleased(MouseEvent e) {
pointStart = null;
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
pointEnd = e.getPoint();
}
public void mouseDragged(MouseEvent e) {
pointEnd = e.getPoint();
repaint();
}
});
}
public void paint(Graphics g) {
super.paint(g);
if (pointStart != null) {
g.setColor("put your color here");
g.drawLine(pointStart.x, pointStart.y, pointEnd.x, pointEnd.y);
}
}
};
f.add(p);
f.setVisible(true);
}
This code is for drawing on a JPanel. In the paintComponent(Graphics) I am trying to draw curves via repeated Graphics2D#fillOval(x, y, with, height).
The app is working OK, and when I drag the mouse cursor slowly; it draws a continuous curve as I need. But when I speed up dragging the mouse cursor, the result is separated dots and not a continuous curve.
So how to make it draw a continuous curve even if I speed up dragging?
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class Painter extends JPanel {
int x, y;
ArrayList<Point> points;
public Painter() {
setBackground(Color.white);
points = new ArrayList<>();
MouseHandler listener = new MouseHandler();
this.addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
private class MouseHandler extends MouseAdapter implements MouseMotionListener {
#Override
public void mouseDragged(MouseEvent e) {
Point point = new Point(e.getX(), e.getY());
points.add(point);
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (Point point : points) {
g2d.fillOval(point.x, point.y, 15, 15);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setContentPane(new Painter());
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
As mentioned in comment to your previous similar question:
Don't draw discrete ovals in your paintComponent method.
Instead connect the points hold in the List in the paintComponent by drawing lines between adjacent points.
If you need to make the line thicker, change the Stroke property of the Graphics2D object, using one that has a wider thickness.
Be careful with Strokes however since often you don't want the property change to propagate down the paint chain. This means that sometimes you will want to copy the Graphics object and set the Stroke on the new Graphics object and paint with that, then dispose of it.
The simplest way to create a Stroke is to use the BasicStroke class, e.g., new BasicStroke(6f) will get you a nice thick curve.
For example:
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class Painter2 extends JPanel {
private static final float STROKE_WIDTH = 15f;
private static final Stroke STROKE = new BasicStroke(STROKE_WIDTH, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
int x, y;
ArrayList<Point> points;
public Painter2() {
setBackground(Color.white);
points = new ArrayList<>();
MouseHandler listener = new MouseHandler();
this.addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
private class MouseHandler extends MouseAdapter implements MouseMotionListener {
#Override
public void mouseDragged(MouseEvent e) {
Point point = new Point(e.getX(), e.getY());
points.add(point);
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(STROKE);
for (int i = 1; i < points.size(); i++) {
int x1 = points.get(i - 1).x;
int y1 = points.get(i - 1).y;
int x2 = points.get(i).x;
int y2 = points.get(i).y;
g2d.drawLine(x1, y1, x2, y2);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setContentPane(new Painter2());
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
Or better still:
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Painter2 extends JPanel {
private static final float STROKE_WIDTH = 15f;
private static final Stroke STROKE = new BasicStroke(STROKE_WIDTH, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);
private static final Color CURVES_COLOR = Color.BLUE;
private static final Color TEMP_CURVE_COLOR = Color.PINK;
private List<List<Point>> curvesList = new ArrayList<>();
private List<Point> tempCurve = null;
public Painter2() {
setBackground(Color.white);
MouseHandler listener = new MouseHandler();
addMouseListener(listener);
addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
private class MouseHandler extends MouseAdapter implements MouseMotionListener {
#Override
public void mousePressed(MouseEvent e) {
tempCurve = new ArrayList<>();
tempCurve.add(e.getPoint());
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
tempCurve.add(e.getPoint());
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
tempCurve.add(e.getPoint());
curvesList.add(tempCurve);
tempCurve = null;
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setStroke(STROKE);
g2.setColor(CURVES_COLOR);
for (List<Point> curve : curvesList) {
drawCurve(g2, curve);
}
if (tempCurve != null) {
g2.setColor(TEMP_CURVE_COLOR);
drawCurve(g2, tempCurve);
}
g2.dispose();
}
private void drawCurve(Graphics2D g2, List<Point> ptList) {
for (int i = 1; i < ptList.size(); i++) {
int x1 = ptList.get(i - 1).x;
int y1 = ptList.get(i - 1).y;
int x2 = ptList.get(i).x;
int y2 = ptList.get(i).y;
g2.drawLine(x1, y1, x2, y2);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setContentPane(new Painter2());
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
My drawing class: for example I just want to draw a simple line
public class DrawNot1 extends JPanel {
private BasicStroke BS = new BasicStroke(2);
private int x;
private int y;
public DrawNot1(int x, int y){
setSize(100, 100);
this.x = x;
this.y = y;
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
doDrawing(g);
}
private void doDrawing(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(BS);
g2d.drawLine(x, y, x, y+10);
}
my JFrame class:
public class Main extends JFrame{
private int x;
private int y;
public Main() {
initUI();
}
public void initUI() {
setSize(600, 500);
setTitle("Points");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new DrawNot1(20, 20));
add(new JButton("button1"));
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Main ex = new Main();
ex.setVisible(true);
}
});
}
}
I want to show my drawing next to the button but that doesn't appear the only component that appear is the button, my drawing does not.
My ultimate goal is when I press the button my drawing is appear near the button.
JFrame uses a BorderLayout by default, adding two components to the default (CENTRE) position means that only the last one added will be shown.
Try adding the button to the SOUTH position instead
add(new JButton("button1"), BorderLayout.SOUTH);
You may also find the overriding the getPreferredSize method of DrawDot1 and providing a suitable value will also result in a better output
I have an application which has a swing user interface class, which has buttons that send variables to a canvas class like so;
public class createWindow extends JFrame implements ActionListener
{
createCanvas canvas = new createCanvas(10, 10);
JPanel mainPanel = new JPanel();
public createWindow()
{
mainPanel.add(canvas, BorderLayout.CENTER);
}
}
createCanvas is a class which declares a paintComponent;
public class createCanvas extends JPanel
{
int xValue;
int yValue;
int xCoordinate;
int yCoordinate;
public createCanvas(int x, int y)
{
xValue = x;
yValue = y;
}
public void setXCoordinate(int x)
{
xCoordinate = x;
}
public void setYCoordinate(int y)
{
yCoordinate = y;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
drawGrid(g, this.xValue, this.yValue);
g.fillArc(xCoordinate, yCoordinate, 6, 6, 0, 360);
}
public drawGrid(Graphics g, int xLength, int yLength)
{
//creates a grid that is xLength x yLength
}
}
However, I also have a selection of Objects which I want to have a .draw() function, which can use the paintComponent in createCanvas.
The problem is, of course, when I need to draw the node on the grid, I can set the coordinates, but how do I display the node on the canvas I declared in createWindow?
public class Node()
{
int xCoordinate;
int yCoordinate;
//Suitable constructors, sets, gets
public void draw()
{
createCanvas canvas = new createCanvas();
canvas.setXCoordinate(this.xCoordinate);
canvas.setYCoordinate(this.yCoordinate);
canvas.repaint();
}
}
So, I am wondering if there is a way for me to keep what I have drawn on the canvas in createWindow, as well as what I draw in my Object class.
Thanks.
What you want to do is have the draw method in your object take a Graphics argument. This Graphics object will be the same Graphics context in your paintComponent method. You can create the object in your JPanel class. Something like this
public class Circle {
int x, y;
public Circle(int x, int y) {
this.x = x;
this.y = y;
}
public void drawCirlce(Graphics g) {
g.fillRect(x, y, 50, 50);
}
}
Then in you JPanel class
public class CirclePanel extends JPanel {
Circle circle = new Circle(100, 100);
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
circle.drawCircle(g);
}
}
You can have a setter for the x and y in your Circle class. You should change them somewhere in your JPanel class then call repaint() afterwards. You could move it with the press of a key or you can animate it with a java.util.Timer. For example
With a Timer
public class CirclePanel extends JPanel {
Circle circle = new Circle(100, 100);
public CirclePanel() {
Timer timer = new Timer(50, new ActionListener(){
#Override
public void actionPerfomed(ActionEvent e) {
circle.x += 10;
repaint();
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
circle.drawCircle(g);
}
}
With a key binding
public class CirclePanel extends JPanel {
Circle circle = new Circle(100, 100);
public CirclePanel() {
InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED_IN_WINDOW);
inputMap.put(KeyStroke.getKeyStroke("RIGHT"), "moveRight");
getActionMap().put("moveRight", new AbstractAction(){
public void actionPerformed(ActionEvent e) {
circle.x += 10;
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
circle.drawCircle(g);
}
}
With a button press
public class CirclePanel extends JPanel {
Circle circle = new Circle(100, 100);
public CirclePanel() {
JButton button = new JButton("Move Right");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
circle.x += 10;
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
circle.drawCircle(g);
}
}
So I have the following class. I have over-simplified the code, as putting 500+ lines of code is not an option. It is basically a very fancy square:
public class ModuleGui extends JComponent implements ElementInterface {
private String name;
private Rectangle2D s = new Rectangle2D.Double();
private Rectangle2D[] points;
private int resizeSize = 10;
private final ShapeResizeHandler shapeResizeHandler = new ShapeResizeHandler();
public ModuleGui(int x, int y){
this.addMouseListener(shapeResizeHandler);
this.addMouseMotionListener(shapeResizeHandler);
this.x = x;
this.x = y;
points = new Rectangle2D[2];
points[0] = new Rectangle2D.Double(x,y,1,1);
points[1] = new Rectangle2D.Double(x + width, y + height, resizeSize, resizeSize);
this.name = new String("Gate" + Integer.toString(namingCounter++));
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.fill(points[1]);
//Set the main rectangle, fill it and draw it
s.setRect(points[0].getX(), points[0].getY(),
Math.abs(points[1].getCenterX() - points[0].getCenterX()),
Math.abs(points[1].getCenterY() - points[0].getCenterY()));
g2d.setColor(Color.WHITE);
g2d.fill(s);
g2d.setColor(Color.BLACK);
g2d.draw(s);
//Main rectangle draw end
//Add the name and the & symbol
g2d.drawString(this.name, (int) (s.getCenterX()), (int) (s.getY() + this.height/10));
}
private class ShapeResizeHandler extends MouseAdapter{
public void mousePressed(MouseEvent e){
System.out.println("Funny");
}
public void mouseReleased(){
//Do more stuff
}
public void mouseDragged(MouseEvent e){
//Do Stuff
repaint();
}
}
}
Now I have this JComponent inside JPanel..but I don't seem to catch any mouse events. The mouse events show up in the JPanel, but not in the JComponent. I have tried to make a simple mouse listener to just print something, but the same happens.
Make sure your component is visible and has non-zero dimensions. Here is code that works for me:
public class MouseTest extends JComponent {
public MouseTest () {
addMouseListener (new MouseAdapter () {
#Override
public void mousePressed (MouseEvent e) {
System.out.println ("Mouse pressed");
e.consume();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension (320, 240);
}
#Override
public void paint(Graphics g) {
g.setColor (Color.cyan);
g.fillRect (getX (), getY (), getWidth (), getHeight ());
}
public static void main(String[] args) {
JFrame frame = new JFrame ("Mouse Test");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane ().setLayout (new BorderLayout ());
frame.getContentPane ().add (new MouseTest (), BorderLayout.CENTER);
frame.pack ();
frame.setVisible (true);
}
}