4

I have written the following micro-paintbrush program in Java:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;


class AuxClass1 extends JFrame implements MouseListener, MouseMotionListener{

    private JPanel panel1 = new JPanel();
    private JPanel panel2 = new JPanel();
    private JLabel label1_x = new JLabel();
    private JLabel label1_y = new JLabel();
    private JLabel label1_x_info = new JLabel("");
    private JLabel label1_y_info = new JLabel("");
    //add a container keep panels with widgets 
    private Container con1 = getContentPane();

    private int xval1;
    private int yval1;

    private GridLayout layout1 = new GridLayout(2,2,2,2);

    private JOptionPane info1 = new JOptionPane();

    //get the class that controls the mouse
    public AuxClass1(){
        super("Mouse Experiment");
        panel1.setBackground(Color.WHITE);      
        panel1.setLayout(layout1);
        label1_x.setText("X Location");
        label1_x.setBorder(BorderFactory.createLineBorder(Color.BLUE, 2));
        label1_y.setBorder(BorderFactory.createLineBorder(Color.BLUE, 2));
        label1_x_info.setBorder(BorderFactory.createLineBorder(Color.RED, 2));
        label1_y_info.setBorder(BorderFactory.createLineBorder(Color.RED, 2));
        label1_y.setText("Y Location");     
        panel1.add(label1_x);
        panel1.add(label1_y);
        panel1.add(label1_x_info);
        panel1.add(label1_y_info);
        con1.add(panel1, BorderLayout.NORTH);
        panel2.setBackground(new Color(100,200,200));
        panel2.setBorder(BorderFactory.createLineBorder(new Color(255,255,0), 2));
        panel2.addMouseListener(this);
        panel2.addMouseMotionListener(this);
        con1.add(panel2, BorderLayout.CENTER);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(500, 500);
        setLocationRelativeTo(null);
        setVisible(true);


    }

    @Override
    public void mouseClicked(MouseEvent arg0) {


    }

    @Override
    public void mouseMoved(MouseEvent arg0) {
        // TODO Auto-generated method stub
        if (arg0.getSource()==panel2){
            x_var = arg0.getX();
            y_var = arg0.getY();
            label1_x_info.setText(Integer.toString(x_var));
            label1_y_info.setText(Integer.toString(y_var));
        }

    }

    @Override
    public void mouseDragged(MouseEvent e) {
        // TODO Auto-generated method stub
        if (e.getSource()==panel2){
            //info1.showMessageDialog(this, "This is an awesome Mouse toolbox!");
            xval1 = e.getX();
            yval1= e.getY();
            AuxClass2 Inst2 = new AuxClass2(xval1, yval1);
            Inst2.paintComponent(getGraphics());
            }

    }

    @Override
    public void mouseEntered(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseExited(MouseEvent arg0) {
        if (arg0.getSource()==panel2){
            label1_x_info.setText("");
            label1_y_info.setText("");
        }
        // TODO Auto-generated method stub

    }

    @Override
    public void mousePressed(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseReleased(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }


}

class AuxClass2 extends JPanel{

    //JOptionPane info2 = new JOptionPane();
    private int xval2;
    private int yval2;

    public AuxClass2(int input1, int input2){

        xval2 = input1;
        yval2 = input2;
        setSize(500,500);

    }

    @Override
    public void paintComponent(Graphics g){
        super.paintComponents(g);
        g.setColor(Color.BLUE);
        g.fillRect(xval2, yval2+70, 5, 5);  

    }

}

public class MainClass{

    private static AuxClass1 Inst1;

    public static void main(String args[]){

        Inst1 = new AuxClass1();


    }

}

It works alright except for the Y coordinate of the mouseDragged method (see paintComponent method in class t3_aux2). For some reason the Y coordinate used by the method is ~70 pixels less than the actual one in panel2. I suspect this is something to do with the inherited JPanel method in t3_aux2 class but not too sure.

If someone could clarify this point, it would be cool. Thanks.

UPD: If anyone has suggestions on how to improve style and/or optimize code, that would be massively appreciated too.

UPD2: Changed the names to comply with Java naming conventions.

Alex
  • 944
  • 4
  • 15
  • 28
  • 3
    didn't look at your problem, just at your code: a) never-ever use getGraphics b) don't call paintComponent, instead call repaint c) please learn java naming conventions and stick to them – kleopatra Aug 27 '12 at 08:30
  • I agree with c), I'm new to Java. Can you be more specific about a) and b) please. I followed style and approach I've found in various Java tutorials, incl the one on Oracle's website. – Alex Aug 27 '12 at 10:46
  • 1
    cool - how about editing your question to include follow the conventions you have learned so far :-) As to the other points, please have a look at the swing tag wiki - there are some references to must-have-reads. – kleopatra Aug 27 '12 at 14:12
  • I added the update. I'll have a look at the swing tag results. It would be really cool if you could comment on never using the `getGraphics() ` at least. – Alex Aug 28 '12 at 00:29
  • When you call `repaint()`, the component is scheduled for a repaint. Swing will automatically call `paint()` or `paintComponent()` with the appropriate `Graphics` object in parameter. – phsym Aug 28 '12 at 13:01

1 Answers1

5

I tried your code. I think your problem comes from the fact that you paint on the t3_aux1 using t3_aux2 coordinates. I'll try something to confirm that, and I come back here ...

EDIT: OK, that's it.

in t3_aux1 constructor, if you write

System.out.println("panel1 height = " + panel1.getHeight());
System.out.println("label1 height = " + label1_x.getHeight())

it prints

panel1 height = 42
label1 height = 20

So your offset is 42 + 20 + 4*2 = 70

4*2 comes from your lines borders with a thickness of 2.

Since it's possible to calculate the exact offset, you can dynamically fix it.

EDIT 2 :

In fact, the coordinates you uses come from panel2 since the mouseListener is attached to panel2. But you draw on the JFrame Graphics, not on panel2 graphics.

writing this should fix your coordinates problem.

inst2.paintComponent(panel2.getGraphics());

But as Kleopatra said, you're not doing it the right way. You should never call getGraphics() or paintComponent(). I think you should consider using java.awt.Canvas as a super class for your "panel2" object.

One more advice : Be aware that your drawings aren't memorized, so, if you reduce the window or hide it behind another one, everything drawn will be lost.

phsym
  • 1,364
  • 10
  • 20
  • Thanks, can you explain the meaning of "dynamical fix"? – Alex Aug 27 '12 at 10:50
  • What I mean is that you shouldn't use 70 to fix the offset, but you should calculate this value, then if you modify something (for example the line borders thickness), the offset will stay fixed. But I'm preparing a little piece of code improvement for you, I'll post it when I will have time to finish it. – phsym Aug 27 '12 at 10:56
  • I guess you're trying to make a Tic Tac Toe ? I don't understand why you instanciate a new object each time you want to draw ? – phsym Aug 27 '12 at 12:19
  • You mean `inst2` in the mouseDragged method? I don't know any better way of doing it. Can you suggest anything? – Alex Aug 27 '12 at 23:09
  • Yes, in the `mouseDragged` method, instead of creating a new object, you could simply do someting like `getGraphics().fillRect(...)`. But once again, this is not the best way to do. – phsym Aug 28 '12 at 06:53
  • In this question I asked earlier, http://stackoverflow.com/questions/12107163/specifying-the-location-of-canvas-in-swing, it was suggested not to use Canvas, since it is 'heavyweight' (see comments). Who should I trust?) – Alex Aug 28 '12 at 12:08
  • When I say "not the best way", I dont talk about JPanel vs Canvas. I suggested Canvas, since in my mind, Canvas is made for drawings. You can still use JPanel if you have reasons to do it. In fact, what I mean is that you should never call `paint()` or `paintComponents()`, but you should call `repaint()` to schedule a call to `paint()` by swing. Everything is explained [here](http://java.sun.com/products/jfc/tsc/articles/painting/index.html) . – phsym Aug 28 '12 at 12:48
  • And you should not draw on a `Graphic` object obtained by `getGraphics()`. – phsym Aug 28 '12 at 13:07