I want to program an application that lets you draw circles with a mouse click on the left side of a JFrame
, and all the points are getting "mirrored" to the right side. The first problem I encountered was that when I try to implement this draw-mechanic in my frame, no circles appear.
public class Application{
int x,y;
private JPanel container;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Application().gui();
}
});
}
public void gui()
{
int height = 250;
int width = 700;
JFrame jframe = new JFrame();
container = new JPanel();
container.setLayout(new BorderLayout());
container.add(new DrawCircle(), BorderLayout.WEST);
container.setVisible(true);
jframe.add(container);
//jframe.add(new DrawCircle());
jframe.setSize(500,700);
jframe.setVisible(true);
jframe.setTitle("Title");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setResizable(false);
}
}
It works (on the whole frame) when I use container.add(new DrawCircle)
but if I want to add constraints, it doesn't.
Here is the circle class:
public class DrawCircle extends JPanel implements MouseListener
{
ArrayList<Point> p = new ArrayList<Point>();
public DrawCircle()
{
addMouseListener(this);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(Point point : p)
{
g.fillOval(point.x,point.y,30,30);
}
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
p.add(new Point(e.getY(), e.getX()));
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
public void mouseMoved(MouseEvent arg0) {
}
}
Let's go through your problems:
The first problem I encountered was that when I try to implement this draw-mechanic in my frame, no circles appear.
This is because you forgot to call JPanel#revalidate()
and JPanel#repaint()
whenever you click somewhere in the DrawCircle
class.
So, you could change your mousePressed()
method to:
@Override
public void mousePressed(MouseEvent e) {
p.add(new Point(e.getX(), e.getY()));
revalidate();
repaint();
}
Note that I also changed the e.getX()
and e.getY()
calls, because they were on the wrong places (unless you want them that way).
That will make your circles to appear, but, your DrawCircle
is really thin (I changed the height of your JFrame
to 200 for this image, otherwise it would be really tall):
The red part is your DrawCircle
panel.
To fix this you need to override its getPreferredSize()
method:
@Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
That will make your JPanel
to return half the size, width
and height
were passed as parameters to the constructor, and your class DrawCircle
should now look like this:
class DrawCircle extends JPanel implements MouseListener {
ArrayList<Point> p = new ArrayList<Point>();
int width = 0;
int height = 0;
public DrawCircle(int width, int height) {
this.width = width;
this.height = height;
addMouseListener(this);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Point point : p) {
g.fillOval(point.x, point.y, 30, 30);
}
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
p.add(new Point(e.getX(), e.getY()));
revalidate();
repaint();
}
@Override
public void mouseReleased(MouseEvent e) {
}
}
And the output would be something like this:
It works (on the whole frame) when I use container.add(new DrawCircle)
That's because by default BorderLayout
places by default the elements on the CENTER
region, and if you have nothing else in the rest of orientations (NORTH
, SOUTH
, etc) it will take the whole space.
Now let's continue with how to solve your problem:
I also made some changes to the Application
class (which in my case I renamed to CustomPaintingInHalfFrame
):
These changes were:
- Create final constants for the
WIDTH
andHEIGHT
attributes. - Removal of unnecessary
JPanel
withBorderLayout
layout, asJFrame
already has this layout by default, I simply added ourDrawClass
to it. - Drawing of a border for the
DrawCircle
panel (as you don't want a division between both (left and right) parts of yourJFrame
as stated in your previous question you can simply remove it (I recommend you to leave it there while you're testing so you know where left panel ends and right panel starts. - Passing
WIDTH / 2
andHEIGHT
as parameters forDrawCircle
constructor, so it can return the correctDimension
.
So, our class should now look like this:
public class CustomPaintingInHalfFrame {
int x, y;
public static final int WIDTH = 500;
public static final int HEIGHT = 200;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new CustomPaintingInHalfFrame().gui();
}
});
}
@SuppressWarnings("serial")
public void gui() {
JFrame jframe = new JFrame("Title");
DrawCircle dc = new DrawCircle(WIDTH / 2, HEIGHT);
dc.setBorder(BorderFactory.createLineBorder(Color.RED));
jframe.add(dc, BorderLayout.WEST);
jframe.setSize(WIDTH, HEIGHT);
jframe.setVisible(true);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setResizable(false);
}
}
Additional Tips
I recommend you to rename your
DrawCircle
toCircle
or something like that. As a convention, Classes names should be nounsRename
gui()
method tocreateGui()
for example because, as Classes names, method names should be verbs
来源:https://stackoverflow.com/questions/41700866/draw-on-one-side-of-a-jpanel