Java painter program drawing shapes - java

I have a problem in this java code.
I want to make a painter program but whenever I choose a shape and draw it
all the shapes that were drawn before become the same as this shape. Here's the code.
I know that the problem is from the for statement in the paintComponent but what can I replace it with?
class inner extends JPanel implements MouseListener,MouseMotionListener{
private int oldx,oldy,newx,newy;
private Point point1,point2;
private Shape newRec,line1;
Rectangle currRec;
private Vector shape;
private boolean status,status1;
private int count=0;
private Object line;
inner(){
point1=point2=new Point(0,0);
shape = new Vector();
addMouseListener(this);
addMouseMotionListener(this);
}
public void mouseDragged(MouseEvent event) {
point2=event.getPoint();
newx = point2.x;
newy = point2.y;
if(Universal==7){
line = new Object(oldx,oldy,newx,newy);
status = true;
repaint();
}
currRec = new Rectangle(Math.min(point1.x,point2.x),Math.min(point1.y,point2.y),Math.abs(point1.x-point2.x),Math.abs(point1.y-point2.y));
status = true;
repaint();
}
#Override
public void mouseMoved(MouseEvent arg0) {}
public void mouseClicked(MouseEvent arg0) {}
public void mouseEntered(MouseEvent arg0) {}
#Override
public void mouseExited(MouseEvent arg0) {}
public void mousePressed(MouseEvent event) {
point1=event.getPoint();
oldx=event.getX();
oldy=event.getY();
}
#Override
public void mouseReleased(MouseEvent event) {
point2=event.getPoint();
newx=event.getX();
newy=event.getY();
//count++;
if(Universal==7){
line1 = new Shape(point1.x,point1.y,point2.x,point2.y);
shape.add(line1);
//Graphics g = getGraphics();
//g.setColor(colour);
//g.drawLine(point1.x,point1.y,point2.x,point2.y);
count++;
repaint();
}
else if(Universal==1||Universal==2||Universal==3||Universal==4||Universal==5||Universal==6){
newRec = new Shape(Math.min(point1.x,point2.x),Math.min(point1.y,point2.y),Math.abs(point1.x-point2.x),Math.abs(point1.y-point2.y));
shape.add(newRec);
count++;
repaint();
}
}
///// the problem is in here
public void paintComponent(Graphics g){
super.paintComponent(g);
Shape c;
g.setColor(colour);
for(int i=0;i<shape.size();i++){
c = (Shape) shape.get(i);
if(Universal==1){
g.drawRect(c.x, c.y, c.w, c.h);
if(status){
g.drawRect(currRec.x, currRec.y, currRec.width, currRec.height);
}
}
if(Universal==2){
g.fillRect(c.x, c.y, c.w, c.h);
if(status){
g.fillRect(currRec.x, currRec.y, currRec.width, currRec.height);
}
}
if(Universal==3){
g.drawRoundRect(c.x, c.y, c.w, c.h, c.w/4, c.h/4);
if(status){
g.drawRoundRect(currRec.x, currRec.y, currRec.width, currRec.height,currRec.width/4,currRec.height/4);
}
}
if(Universal==4){
g.fillRoundRect(c.x, c.y, c.w, c.h, c.w/4, c.h/4);
if(status){
g.fillRoundRect(currRec.x, currRec.y, currRec.width, currRec.height,currRec.width/4,currRec.height/4);
}
}
if(Universal==5){
g.drawOval(c.x, c.y, c.w, c.h);
if(status){
g.drawOval(currRec.x, currRec.y, currRec.width, currRec.height);
}
}
if(Universal==6){
g.fillOval(c.x, c.y, c.w, c.h);
if(status){
g.fillOval(currRec.x, currRec.y, currRec.width, currRec.height);
}
}
if(Universal==7){
g.drawLine(c.x, c.y, c.w, c.h);
if(status){
g.drawLine(line1.x, line1.y, line1.w,line1.h);
}
}
if(Universal==8){
shape.clear();
}
}
}

Universal is only ever going to be a given value at any given time.
Paints are not accumulative, they are destructive.
That is, each time paintComponent is called, all the previous contents is removed/wiped clean and you are expected to "repaint" the contents.
Instead of relying on a single flag, you should add the Shapes to some kind of List and redraw them all when ever paintComponent is called. Equally, you could simply add the "type" (int) to a List and process that list on each repaint
Take a look at Painting in AWT in Swing for an explanation of the paint process

See Custom Painting Approaches for two different ways to do this:
Add shapes to a List and then repaint all the Shapes from the list every time paintComponent() is invoked.
Draw Shapes to a BufferedImage and then just repaint the image ever time paintComponent() is invoked.
Neither example does exactly what you want, it only shows you the approach.

Related

Removing element from array doesn't change graphic

In my application, I made an array to control the flag images in my output. This worked fine but when I remove an element from my array the picture doesn't change at all.
class Flag{
Image FlagImage;
int FlagNum = 0;
public Flag(int FlagNum) {
this.FlagNum = FlagNum;
try{
FlagImage = ImageIO.read(new File("flag1.png"));
}catch(Exception e){
}
}
public void Update() {
}
public void Draw(Graphics g) {
//Draw Flag
g.drawImage(FlagImage, ((FlagNum) % 3+1) * 100-100, (int)((FlagNum) / 3) * 100+100, null);
}
}
public class Flags extends JPanel {
/**
* Creates new form Flags
*/
public Flags(){
initComponents();
FlagSet.add(new Flag(1));
final Timer timer =new Timer(10, new ActionListener(){
#Override
public void actionPerformed(final ActionEvent e){
repaint();
for (Flag f: FlagSet){
f.Update();
}
}
});
}
public static ArrayList<Flag> FlagSet = new ArrayList();
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
for (Flag f: FlagSet){
f.Draw(g);
}
}
I then try to add flags like so:
flagCounter = 4;
while(flagCounter > -1){
Flags.FlagSet.add(new Flag(flagCounter));
flagCounter--;
}
Which works fine but my image doesn't change if I put in a Flgas.FlageSet.remove(//Some flag)later on. Any ideas? Thanks in advance.
It looks like you're missing a call to repaint().
Repaint is a signal sent to the drawing component to tell it that something has changed, and that it needs to call the paint methods again. In this case, as your addition to your Flags list will change how it is drawn, you should simply call repaint() after you've finished adding your flags.

Cannot find graphics variable when method is called?

This is a JButton that needs to have action listener when clicked will call drawPiece method. Currently error is connect find symbol variable g.
JButton column3 = new JButton();
column3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
x = 2;
//.drawPiece(g);
column3.drawPiece(g);
}
});
This is the drawPiece method and where the graphics are initialized.
public void paintComponent(Graphics pen) {
super.paintComponent(pen);
drawBoard(pen);
drawPiece(pen);
boardarray();
}
public void drawPiece(Graphics g) {
x = x;
y=0;// fixed at 0
int turn=0;
boolean p1Win = false;
boolean p2Win = false;
//while(p1Win==false && p2Win==false) {
checkPiece();
g.setColor(Color.RED);
g.fillOval(10+x*110,10+y*110,100,100);
//checkWin();
p1Win = true;
}
Any suggestions are appreciated.
column3.drawPiece(g);
You should never invoke a painting method from a listener directly. If you want to repaint the component then you tell the component to repaint itself:
column3.repaint();
The makes a call to the RepaintManager to schedule the repainting. Ultimately the paintComponent() method will be invoked with the appropriate Graphics object.

KeyHandler not responding to keyevents

I am trying to to set up a KeyListener to respond to my keystrokes. I have already setup a mouselistener but for some reason I am un-able to get the keylistener to respond to any keystrokes.
I have created a class that implements KeyListener and overridden the functions. I then created an instance of the new class and added the handler to the JPanel and JFrame. Still no dice
public class main_program extends JFrame {
private int mX_cord, mY_cord,prior_selected_vertex, current_selected_vertex;
private int verticies_to_edge1, verticies_to_edge2;
private int radius =10;
private boolean vertex_selected1 = false, vertex_selected2 = false, edge_ready = false,delete_vertex_ready = false;
private Edge tempEdge = null;
private ArrayList<Integer> vertex_xcord = new ArrayList<Integer>();
private ArrayList<Integer> vertex_ycord = new ArrayList<Integer>();
private ArrayList<Edge> edge = new ArrayList<Edge>();
HandlerMouse handler = new HandlerMouse();
HandlerKey keyhand = new HandlerKey();
private JPanel masterPanel;
private JTextArea masterTextArea;
private JScrollPane masterScrollPane;
private Point point1, point2;
Graphics g;
public main_program(){
setTitle("Graph");
setSize(600, 400);
setDefaultCloseOperation(new JFrame().EXIT_ON_CLOSE);
//this must be set for custom layout of components
setLayout(null);
masterPanel = new JPanel();
masterPanel.setSize(600,300);
masterPanel.setLocation(0, 0);
masterPanel.setBackground(Color.WHITE);
masterPanel.addMouseListener(handler);
masterPanel.addMouseMotionListener(handler);
masterPanel.addKeyListener(keyhand);
masterTextArea = new JTextArea();
masterTextArea.setBackground(Color.green);
masterScrollPane = new JScrollPane();
masterScrollPane.add(masterTextArea);
masterScrollPane.setSize(600, 100);
masterScrollPane.setLocation(0, 300);
masterScrollPane.addMouseListener(handler);
masterScrollPane.addMouseListener(handler);
masterScrollPane.addKeyListener(keyhand);
add(masterPanel);
add(masterScrollPane);
setLocationRelativeTo(null);
setVisible(true);
}
public void paint(Graphics g){
super.paint(g);
for(int i = 0 ; i < vertex_xcord.size(); i++){
g.fillOval(vertex_xcord.get(i), vertex_ycord.get(i), radius, radius);
}
for(int i = 0 ; i<edge.size(); i++){
tempEdge = edge.get(i);
g.drawLine(vertex_xcord.get(tempEdge.vertex1), vertex_ycord.get(tempEdge.vertex1), vertex_xcord.get(tempEdge.vertex2), vertex_ycord.get(tempEdge.vertex2));
}
//g.fillOval(mX_cord, mY_cord, radius, radius);
//repaint();
}
private class HandlerKey implements KeyListener{
public void keyPressed(KeyEvent evt){
System.out.println("key pressed");
if(evt.getKeyCode() == KeyEvent.VK_ENTER && edge_ready){
edge.add(new Edge(prior_selected_vertex, current_selected_vertex));
edge_ready = false;
repaint();
}
}
public void keyReleased(KeyEvent evt){
System.out.println("key rel");
}
public void keyTyped(KeyEvent evt){
System.out.println("key type");
}
}
private class HandlerMouse implements MouseListener, MouseMotionListener{
public void mouseClicked(MouseEvent evt){
mX_cord = evt.getX()-5;
mY_cord = evt.getY()+15;
if( evt.getClickCount() == 1){
//mX_cord = evt.getX();
//mY_cord = evt.getY();
vertex_xcord.add(mX_cord);
vertex_ycord.add(mY_cord);
repaint();
}
else{
for(int i = 0 ; i < vertex_xcord.size(); i++){
if(Math.abs(vertex_xcord.get(i) - mX_cord ) < 15 && Math.abs(vertex_ycord.get(i) - mY_cord ) < 15 ){
if(vertex_selected1 == false){
prior_selected_vertex = i;
vertex_selected1 = true;
}
else{
current_selected_vertex = i;
vertex_selected2 = true;
}
System.out.println("YOU HAVE SELECTED A VERTEX: " + i);
break;
}
}
}
if(vertex_selected2 == true){
edge_ready = true;
verticies_to_edge1 = prior_selected_vertex;
verticies_to_edge2 = current_selected_vertex ;
vertex_selected1 = vertex_selected2 = false;
System.out.println("Ready for edge!");
}
else{
delete_vertex_ready = true;
}
}
public void mouseEntered(MouseEvent arg0)
{
}
public void mouseExited(MouseEvent arg0)
{
}
public void mousePressed(MouseEvent evt)
{
}
public void mouseReleased(MouseEvent arg0)
{
}
public void mouseDragged(MouseEvent e)
{
}
public void mouseMoved(MouseEvent e)
{
}
}
class Edge {
int vertex1, vertex2;
public Edge(int v1, int v2){
vertex1 = v1;
vertex2 = v2;
}
}
public static void main(String[] args){
main_program circle = new main_program();
}
}
You've got several problems with that program, and it suggests that you'd do well to read many of the Swing Q&A's on this site, because these problems (and your main problem) are quite common, and solutions are often posted.
As to your main problem, the problem again is very common: KeyListeners only work if the listened to component has focus. If it loses focus or is not focusable, then you're out of luck. The best solution is often not to use a KeyListener but rather the higher level and more flexible Key Bindings. Google will find the tutorials for you for this.
As for other problems with your code:
You're using null layout, a layout that leads to inflexible GUI's that are very difficult to upgrade and enhance, and that look terrible on all but your current platform and screen resolution. Solution: study and use the layout managers.
You're drawing directly into a JFrame's paint(Graphics g) method, which has risks as you risk messing up the painting of any and all of the JFrame's constituents by doing this. Much better to draw in a JPanel's paintComponent(Graphics g) method, and gain the benefit of Swing (rather than AWT) graphics including automatic double buffering.
Your class has a Graphics variable, g, which suggests that you're contemplating using a stored Graphics object either from a component or from the JVM. This increases the risk of your program throwing a NullPointerException when that Graphics object no longer exists, either that or drawing with it and but not seeing any effect. Solution: draw inside the painting method (again better with a JComponent's paintComponent method) only, or with the Graphics object from a BufferedImage.
You're adding a MouseListener directly to a JPanel but are drawing in a different component, the JFrame, and by doing so without taking insets into account, are placing points in the wrong location. Use the MouseListener on the same component that you're drawing on.
Again, please have a look around here, as I think you'll find a lot of treasures on this site that can be used to enhance your program.

using Graphics g in inner class in java

Why can not I see the following output?
g2.drawString(new Date().toString(), 0, 150);
(i used g2 (global variable) for using g in paint method in inner class).
Thanks a lot in advance!
public class RedRect extends Frame
{
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new RedRect();
}
});
}
public static Point p;
RedRect()
{ super("RedRect");
try{
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e){System.exit(0);}});
setSize (800, 600);
add("Center", new CvRedRect());
show();
}
catch(Exception ex){
}
}
}
class CvRedRect extends Canvas
{
Vector<Point> v=new Vector<Point>();
CvRedRect(){
addMouseListener((new MouseAdapter() {
public void mousePressed(MouseEvent evt){
if(v.size()<3){
v.add(evt.getPoint());
}
else{
flag=false;
//v.removeElementAt(0);
//v.add(evt.getPoint());
}
p=evt.getPoint();
repaint();
}
}));
}
Point p=new Point();
boolean flag=true;
int i=0;
public static Graphics g2;
public void paint(Graphics g)
{
try{
g2=g;
Dimension d = getSize();
int maxX = d.width - 1, maxY = d.height - 1;
g.setColor(Color.red);
g.drawRect(0, 0, maxX, maxY);
g.drawString("x ="+p.x, 10, 30);
g.drawString("y = " +p.y, 10, 60);
if(v.size()>2){
g2.drawLine(v.get(0).x,v.get(0).y,v.get(1).x,v.get(1).y);
g2.drawLine(v.get(0).x,v.get(0).y,v.get(2).x,v.get(2).y);
g2.drawLine(v.get(1).x,v.get(1).y,v.get(2).x,v.get(2).y);
Thread t=new Thread(){
public void run(){
try{
while(flag){
///The following comand//////
g2.drawString(new Date().toString(), 0, 150);
///////////////////////////
Thread.sleep(300);
System.out.println (v.size());
Thread.sleep(300);
}
}
catch(Exception ex){
System.out.println (ex.getMessage());
}
}
};
t.start();
}
//System.out.println ("size="+v.size());
if(!flag){
g.clearRect(0,0,maxX,maxY);
Thread.sleep(1000);
g.drawString("FINISH", 5, 30);
flag=true;
}
}
catch(Exception ex){
}
}
}
The reason your code isn't working is because you're using Graphics wrong. The Graphics object should not be a class field much less a static one. It is not a long-lived object, and so if you try to have it persist in this way, you'll end up with either a null reference or a non-null reference that doesn't work.
Instead if your program is an AWT program, then use the Graphics object inside of the paint method where the JVM supplies you with it when it calls paint. Otherwise if Swing do likewise with the paintComponent method.
Suggestions:
First and foremost, don't code AWT unless this is an absolute requirement for a class. Instead use Swing.
Next read the Swing graphics tutorials as they'll teach you all this and more.
Next do your drawing within the paintComponent(...) overload of a JPanel or other component that extends JComponent.
Don't forget to call the super.paintComponent(g) method within your override.
Don't forget to annotate your override with the #Override annotation.
Use a Swing Timer to do what you're currently using a while loop and Thread.sleep(...) to do.

How to "do something" on Swing component resizing?

I've a class which extends JPanel. I overwrote protected void paintComponent(Graphics g).
There is a variable which has to be recalculated when the panel's dimensions change. How do I do that in a proper way?
Like Adam Paynter suggested, you can also add an inner class to your code, like this:
class ResizeListener extends ComponentAdapter {
public void componentResized(ComponentEvent e) {
// Recalculate the variable you mentioned
}
}
The code you have entered between the innermost brackets will be executed everytime the component get resized.
Then you add this listener to your component with
myJPanel.addComponentListener(new ResizeListener());
You can get your component by using e.getComponent(). This way you can call any method of your component from inside the inner class like
e.getComponent().getWeight();
I suppose you could override the various setSize and resize methods and perform the calculation there. However, you may not find all the places where the size can be changed. You may want to have your class implement ComponentListener and simply listen to itself for resize events.
Warning: I am not a Swing expert.
Warning: I have not compiled this code.
public class MyJPanel extends JPanel implements ComponentListener {
public MyJPanel() {
this.addComponentListener(this);
}
public void paintComponent(Graphics g) {
// Paint, paint, paint...
}
public void componentResized(ComponentEvent e) {
// Perform calculation here
}
public void componentHidden(ComponentEvent e) {}
public void componentMoved(ComponentEvent e) {}
public void componentShown(ComponentEvent e) {}
}
If I understand the question correctly then you should read the section from the Swing tutorial on How to Write a Component Listener which shows you how to listen for a change in a components size.
If the calculation isn't time consuming, I would just re-calculate the value each time in paintComponent().
Otherwise, you can save a value that is the size of the component and check it against the new size in paintComponent. If the size changed, then recalculate, otherwise don't.
private Dimension size;
protected void paintComponent(Graphics g){
if (!size.equals(getSize())){
size = getSize();
// recalculate value
}
}
Or, you can do the calculation on a resize event.
//in the constructor add the line
addComponentListener(resizeListener);
private ComponentListener resizeListener = new ComponentAdapter(){
public void componentResized(ActionEvent e){
// recalculate value
}
};
The simplest way is to implement a ComponentListener:
myjpanel.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
//recalculate variable
}
});
Here, I have used a ComponentAdapter because I only intend on overriding componentResized().
Here's what I use (where CoordinatePlane is a JPanel):
I'm not an expert
public CoordinatePlane() {
setBackground(Color.WHITE);
this.addComponentListener(new ComponentAdapter(){
public void componentResized(ComponentEvent e) {
//YOUR CODE HERE
}
});
}
It resizes automatically if it's
inside a BorderLayout panel and
put there as BorderLayout.CENTER component.
If it doesn't work, you probably have forgotten one of these two.
This simple example is drawing a red circle in the resized frame....
import java.awt.*;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.*;
import java.awt.geom.*;
public class RedCircle extends JFrame implements ComponentListener {
int getWidth;
int getHeight;
public RedCircle() {
super("Red Circle");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addComponentListener(this);
pack();
setVisible(true);
}
public void componentResized(ComponentEvent e) {
getWidth = e.getComponent().getWidth();
getHeight = e.getComponent().getHeight();
Panel pane = new Panel(getWidth,getHeight);
add(pane);
}
public static void main(String[] args) {
RedCircle rc = new RedCircle();
}
public void componentMoved(ComponentEvent e) {
}
public void componentShown(ComponentEvent e) {
}
public void componentHidden(ComponentEvent e) {
}
}
class Panel extends JPanel {
int panelWidth;
int panelHeight;
public Panel(Integer getWidth,Integer getHeight) {
panelWidth = getWidth;
panelHeight = getHeight;
}
public void paintComponent(Graphics comp) {
super.paintComponent(comp);
Graphics2D comp2D = (Graphics2D) comp;
int realWidth = panelWidth - 17;
int realHeight = panelHeight - 40;
float Height = (realHeight);
float Width = (realWidth);
// draw the Red Circle
comp2D.setColor(Color.red);
Ellipse2D.Float redCircle = new Ellipse2D.Float(0F, 0F, Width, Height);
comp2D.fill(redCircle);
}
}

Categories