can't draw on a JPanel after repaint method - java

I'm experimenting on a GUI that I programmed and I don't understand how I can fix my problem:
My GUI contains a jPanel that on receiving a mouseclick, paints a point with filloval command.
private void myPnlMousePressed(java.awt.event.MouseEvent evt) {
changed = true;
p.x = evt.getX();
p.y = evt.getY();
drewPoints(p.x, p.y);
}
private void drewPoints (int x, int y) {
if (gf == null) {
gf = (Graphics)myPnl.getGraphics();
}
myPointsList.add(new Point(x, y));
gf.fillOval(x, y, 5, 5);
xVal.setText("X = " + x);
yVal.setText("Y = " + y);
}
everything works fine but when I want to open an XML file that I created to save all the points it doesn't work.
The problem is that when I use the repaint method on the jPanel after choosing a file, all the points loads fine but the panel can't draw the points.
If I put the repaint method in the open button listener (before the choosing file) it works, but then if the user cancels the open option so the panel stays blank and I don't want to draw the points again.
I think it happens because the repaint process is not finished.
All the points added to a private List.
private void OpenFile() {
try {
File thisFile;
JFileChooser of = new JFileChooser();
int option = of.showOpenDialog(of);
if (option == JFileChooser.APPROVE_OPTION){
thisFileName = of.getSelectedFile().getPath();
thisFile = new File(thisFileName);
if (!of.getSelectedFile().getName().endsWith(".xml")) {
String error = "Error, You didn't select XML file";
JOptionPane.showMessageDialog(this, error, "Wrong type of file", JOptionPane.INFORMATION_MESSAGE);
return;
}
myPnl.repaint();
myPointsList.clear();
....
....
....
for (int i = 0; i < pointsList.getLength(); i++) {
Element point = (Element) pointsList.item(i);
p.x = Integer.parseInt(point.getElementsByTagName("X").item(0).getTextContent());
p.y = Integer.parseInt(point.getElementsByTagName("Y").item(0).getTextContent());
drewPoints(p.x, p.y);
}
....
how can I make it work??

Don't use gf = (Graphics)myPnl.getGraphics();, this is not how painting in Swing works. The getGraphics method can return null and is nothing more then a snap shot of the last paint cycle, any thing you paint to it will be erased on the next paint cycle (repaint).
Instead, override the JPanels paintComponent and put all you painting logic there. There is an expectation that when called, you are expected to fully re-paint the current state of the component.
See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing

You have to use the repaint() and override the paint() method:
class MyPanel extends JPanel implements MouseListener
{
private int x;
private int y;
public MyPanel() {
super();
addMouseListener(this);
}
#Override public void mouseEntered(MouseEvent e) { }
#Override public void mouseExited(MouseEvent e) { }
#Override public void mouseClicked(MouseEvent e) { }
#Override public void mousePressed(MouseEvent e) { }
#Override public void mouseReleased(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override public void paint(Graphics g) {
super.paint(g);
g.fillOval(x, y, 10, 10);
}
}
If you want to draw all points, don't use x and y but a list of points:
class MyPanel extends JPanel implements MouseListener
{
private ArrayList<Point> points = new ArrayList<>();
public MyPanel() {
super();
addMouseListener(this);
}
#Override public void mouseEntered(MouseEvent e) { }
#Override public void mouseExited(MouseEvent e) { }
#Override public void mouseClicked(MouseEvent e) { }
#Override public void mousePressed(MouseEvent e) { }
#Override public void mouseReleased(MouseEvent e) {
points.add(new Point(e.getX(), e.getY()));
repaint();
}
#Override public void paint(Graphics g) {
super.paint(g);
for (Point p : points)
g.fillOval(p.getX(), p.getY(), 10, 10);
}
}
where:
class Point
{
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Then use it:
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
MyPanel myPanel = new MyPanel();
frame.add(myPanel);
frame.setVisible(true);
}

Related

Why the menubar is displayed twice, and the drawn lines only appear on a quarter of the page? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I am learning Java. And I have a problem, certainly basic.
The menubar is displayed twice, and the drawn lines only appear on a quarter of the page.
Do you think there is a relation between the Panel and the JMenuBar ?
Do you think the problem is related to the repaint() method ?
Here is the code :
Class panel:
public class Panel extends JPanel {
private String colorName = "All";
private Color color = Color.RED;
private String shape = "Circle";
private int size1 = 30;
private int x = 0, y = 0;
private boolean allow = false;
#Override
public void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
if (allow == true) {
if (colorName == "Red")
g.setColor(Color.RED);
else if (colorName == "Blue")
g.setColor(Color.BLUE);
else if (colorName == "All") {
int r = (int) ((Math.random()) * 256);
int v = (int) ((Math.random()) * 256);
int b = (int) ((Math.random()) * 256);
color = new Color(r, v, b);
g.setColor(color);
}
if (shape == "Circle")
g.fillOval(x, y, size1, size1);
if (shape == "Square")
g.fillRect(x, y, size1, size1);
}
repaint();
}
public String getColorName() {
return colorName;
}
public void setColorName(String colorName) {
this.colorName = colorName;
}
public boolean isAllow() {
return allow;
}
public void setAllow(boolean allow) {
this.allow = allow;
}
public String getShape() {
return shape;
}
public void setForme(String forme) {
this.shape = shape;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getSize1() {
return size1;
}
public void setSize1(int size1) {
this.size1 = size1;
}
}
Class frame :
public class Frame extends JFrame{
JMenuBar mb = new JMenuBar();
JMenu file = new JMenu("File");
JMenu edit = new JMenu("Edit");
Panel p = new Panel();
public Frame() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setSize(400,400);
this.setTitle("Test");
this.addMouseListener(new MouseAdapter(){
#Override
public void mousePressed(MouseEvent e) {
int a = e.getX() - (p.getSize1()/2);
int b = e.getY() - (p.getSize1());
p.setX(a);
p.setY(b);
p.setAllow(true);
}
});
this.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseMoved(MouseEvent e) {
}
#Override
public void mouseDragged(MouseEvent e) {
int a = e.getX() - (p.getSize1()/2);
int b = e.getY() - (p.getSize1());
p.setX(a);
p.setY(b);
p.setAllow(true);
}
});
mb.add(file);
mb.add(edit);
this.setJMenuBar(mb);
this.setLayout(new BorderLayout());
this.add(p, BorderLayout.CENTER);
this.setVisible(true);
}
public static void main(String[] args) {
new Frame();
}
}
Can you help me please?
You've a very bad typographical bug in your code:
#Override
public void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponents(g);
should be:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Please note the difference in the super call since paintComponents != paintComponent
Also, don't compare Strings using == or !=. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two object references are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here.
And so, not:
if (colorName == "Red") {
// ....
}
but rather:
if (colorName.equalsIgnoreCase("Red")) {
// ....
}
Also, never call repaint() within a painting method. Also, don't randomize the painting or change object state within paintComponent since you do not have control over when or if the method will be called. Randomize in a listener, such as the mouse listener, and if you need animation separate from what the mouse listener provides, use a Swing Timer
ALSO
This:
public int getX() {
// ...
}
Overrides a key method of JPanel inherited from the Component class, that is key to placement of the JPanel, same for getY(). Rename those methods ASAP

Drawing shape on mouse drag

class MyPanel extends JPanel implements Observer, MouseMotionListener, MouseListener {
private MyModel model;
private View view;
private String mode;
private Rectangle rectangle;
private Square square;
public MyPanel(MyModel model, View view) {
this.setBackground(Color.black);
this.setPreferredSize(new Dimension(300, 300));
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.model = model;
this.model.addObserver(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
ArrayList<Rectangle> rectangles = this.model.getRectangles();
for (Rectangle r : getRectangles()) {
int width = Math.abs(r.getStartPoint().getX() - r.getEndPoint().getX());
int height = Math.abs(r.getStartPoint().getY() - r.getEndPoint().getY());
}
ArrayList<Square> squares = this.model.getSquares();
for (Square sqr : getSquares()) {
int xPosition = Math.min(sqr.getStartPoint().getX(), sqr.getEndPoint().getX());
int yPosition = Math.min(sqr.getStartPoint().getY(), sqr.getEndPoint().getY());
int width = Math.abs(sqr.getStartPoint().getX() - sqr.getEndPoint().getX());
int height = Math.abs(sqr.getStartPoint().getY() - sqr.getEndPoint().getY());
}
g2d.dispose();
}
public void update(Observable o, Object arg) {
this.repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
if (this.mode.equals("Rectangle")) {
this.rectangle.setEndPoint(e.getX(), e.getY());
this.model.addRectangle(this.rectangle);
}
else if (this.mode.equals("Square")) {
// What code should I add here?
this.model.addSquare(this.square);
}
}
// MouseListener below
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {
if (this.mode.equals("Rectangle")) {
this.rectangle = new Rectangle(e.getX(), e.getY());
}
else if (this.mode.equals("Square")) {
this.square = new Square(e.getX(), e.getY());
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (this.mode.equals("Rectangle")) {
this.rectangle.setEndPoint(e.getX(), e.getY());
this.model.addRectangle(this.rectangle);
this.rectangle = null;
}
else if (this.mode.equals("Square")) {
this.model.addSquare(this.square);
this.square = null;
}
}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
}
The user chooses a mode, rectangle or square. Then they can draw a square or a rectangle with their mouse (live feedback is shown). Here is my drawing panel class. I was successfully able to implement the rectangle mode. The user can draw a rectangle and as they move their mouse, the rectangle is shown in mid construction. I want to do the same for the square mode. For some reason, I'm having a hard time doing this. How would I show a perfect square in mid construction when the user is moving their mouse and how would I draw it once released? What code should I add to my paintComponent method, mouseDragged, mousePressed and mouseReleased method to do this? It was easy for a rectangle because there was no constraint but I'm not sure how to do it for a square with my current implementation.
int width = Math.abs(r.getStartPoint().getX() - r.getEndPoint().getX());
int height = Math.abs(r.getStartPoint().getY() - r.getEndPoint().getY());
I would guess that the "size" of the square would be the maximum of the above two values.
Then I would think you would just use:
r.drawStyle(g2d, xPosition, yPosition, size, size);

Moving a JFrame with custom title bar

How can I move a JFrame having a custom title bar?
I remove the default title bar and I did my own design. This is how it looks like:
I want to know how to drag a JFrame when the cursor is placed on the title bar only and not the whole frame. I've searched already and I have seen a lot of samples but I still don't get it. Do you guys have any simple code that I can understand?
I haven't started the code yet since I don't know how to start it. All I know is that, it is about mouseDragged or MouseMotionListener.
I implemented the following:
public class DragFrame extends JFrame {
int mpX, mpY;
public DragFrame() {
addMouseListener( new MouseAdapter() {
#Override
public void mousePressed( MouseEvent e ) {
mpX = e.getX();
mpY = e.getY();
}
} );
addMouseMotionListener( new MouseMotionAdapter() {
#Override
public void mouseDragged( MouseEvent e ) {
setLocation(
getLocation().x + e.getX() - mpX,
getLocation().y + e.getY() - mpY );
}
} );
}
}
Thanks to #peeskillet for giving the crucial link to Drag and Resize undecorated JFrame with the inspiration to save the mouse position on mousePressed(...).
Your guess that you'll need to overwrite the MoseMotionListener.mouseDragged method was correct. Then, you need to call JFrame.setLocation to move your JFrame, like this:
class FrameMoveListener extends MouseAdapter
{
private Point lastPos;
private Frame frame;
public FrameMoveListener (Frame f)
{
frame = f; // mustn't be null
}
public void mouseDragged (MouseEvent evt)
{
if (lastPos != null)
{
int x = lastPos.x - evt.getX();
int y = lastPos.y - evt.getY();
f.setLocation(f.getLocationOnScreen().x + x,
f.getLocationOnScreen().y + y);
}
lastPos = new Point(evt.getX(), evt.getY());
}
}
use this method is simple and perfec
final Component obj - your JFrame, JLabel, any Component
final boolean info - if you want display the position when release de left click
public static void Move(final Component obj,final boolean info) {
MouseInputAdapter d=new MouseInputAdapter() {int x,X,y,Y;
#Override public void mousePressed(MouseEvent e){if(SwingUtilities.isLeftMouseButton(e)){x=e.getXOnScreen();X=obj.getLocation().x;y=e.getYOnScreen();Y=obj.getLocation().y;}}
#Override public void mouseDragged(MouseEvent e){if(SwingUtilities.isLeftMouseButton(e)){obj.setLocation(X+(e.getXOnScreen()-x), Y+(e.getYOnScreen()-y));}}
#Override public void mouseReleased(MouseEvent e){if(info && SwingUtilities.isLeftMouseButton(e)){System.err.println(obj.toString().substring(0,obj.toString().indexOf("["))+" ("+obj.getLocation().x+","+obj.getLocation().y+")");}}};
obj.addMouseListener(d);obj.addMouseMotionListener(d);
}
this is the format code:
public static void Mover(final Component obj, final boolean info) {
MouseInputAdapter d = new MouseInputAdapter() {
int x, X, y, Y;
#Override public void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
x = e.getXOnScreen();
X = obj.getLocation().x;
y = e.getYOnScreen();
Y = obj.getLocation().y;
}
}
#Override public void mouseDragged(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
obj.setLocation(X + (e.getXOnScreen() - x), Y + (e.getYOnScreen() - y));
}
}
#Override public void mouseReleased(MouseEvent e) {
if (info && SwingUtilities.isLeftMouseButton(e)) {
System.err.println(obj.toString().substring(0, obj.toString().indexOf("[")) + " (" + obj.getLocation().x + "," + obj.getLocation().y + ")");
}
}
};
obj.addMouseListener(d);
obj.addMouseMotionListener(d);
}

Drawing a dynamic graph.

By saying dynamic graph i mean that the user can drag Vertices around the screen and later remove and more.
I am stuck at this point where i want to paint more then one Vertex, and am trying to avoid making JVM paint the whole graph all over again when the graph changes.
do i have to make it paint the whole graph or is there another way to do that?
here's my code:
class GraphPanel extends JPanel {
private static final long serialVersionUID = 1L;
private Vector<Vertex> V=new Vector<Vertex>();
private Vertex v;
private int R = 20;
public GraphPanel() {
V.add(new Vertex(70,70));
V.add(new Vertex(10,50));
paintGraph();
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
for (int i=0;i<V.size();i++) {
if ((V.get(i).getX()<=e.getX() && V.get(i).getX()+R>=e.getX()) && ( V.get(i).getY()<=e.getY() && V.get(i).getY()+R>=e.getY())) {
v=V.get(i);
moveVertex(e.getX(),e.getY());
v.changeState();
}
}
}
public void mouseReleased(MouseEvent e) {
v.changeState();
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
if (v.isPressed()) moveVertex(e.getX(),e.getY());
}
});
}
private void paintGraph() {
int OFFSET = 1;
for (int i=0;i<V.size();i++) {
v=V.get(i);
repaint(v.getX(),v.getY(),R+OFFSET,R+OFFSET);
}
}
private void moveVertex(int x, int y) {
int OFFSET = 1;
if ((v.getX()!=x) || (v.getY()!=y)) {
repaint(v.getX(),v.getY(),R+OFFSET,R+OFFSET);
v.setLocation(x-10, y-10);
repaint(v.getX(),v.getY(),R+OFFSET,R+OFFSET);
}
}
public Dimension getPreferredSize() {
return new Dimension(250,200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (v!=null) {
g.setColor(Color.RED);
g.fillOval(v.getX(),v.getY(),R,R);
g.setColor(Color.BLACK);
g.drawOval(v.getX(),v.getY(),R,R);
}
}
}
public class Vertex {
private int x,y;
boolean isPressed;
Vertex(int x0,int y0) {x=x0;y=y0;isPressed=false;}
public void setLocation(int x0,int y0) {x=x0;y=y0;}
public int getX() {return x;}
public int getY() {return y;}
public boolean isPressed() {return isPressed;}
public boolean changeState() {return isPressed=!isPressed;}
}
public class Tester {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new GraphPanel());
f.pack();
f.setVisible(true);
}
}
Let's consider graph is list of Ovals and list of Lines. IN the paintComponent() method of Graph we have to draw all the lists' members.
Add a check that g.getClipBounds rectangle intersects Oval (or Line) rectangle. If they intersect we draw oval or line.
When vertex is moved somewhere we have old and new position and can get rectangle to be repainted.
Use the rectangle location and size and pass in the graph panel's repaint().
That way you will repaint changed region only and only ovals and lines visible in the rectangle.
This example can easily handle thousands of vertices. Larger numbers may benefit from using the flyweight pattern for rendering; one approach is illustrated here.

java jlabel click / drag

The blue label is meant to move when you click and drag it. This works but the x / y position then jumps in a funny way.
Here's the code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class test extends JFrame implements MouseListener, MouseMotionListener {
private JPanel panel = new JPanel(null);
private JLabel label1 = new JLabel();
private JLabel label2 = new JLabel();
private int mouseX = 200;
private int mouseY = 100;
private boolean drag = false;
public test() {
this.add(panel);
panel.setBackground(Color.WHITE);
panel.add(label1);
label1.setOpaque(true);
label1.setBackground(Color.BLUE);
label1.setBounds(mouseX, mouseY, 100, 50);
label1.addMouseMotionListener(this);
label1.addMouseListener(this);
panel.add(label2);
label2.setOpaque(true);
label2.setBackground(Color.RED);
label2.setBounds(mouseX + 200, mouseY, 100, 50);
label2.addMouseMotionListener(this);
label2.addMouseListener(this);
}
#Override
public void mousePressed(MouseEvent e) {
if (e.getSource() == label1) {
drag = true;
}
}
#Override
public void mouseReleased(MouseEvent e) {
drag = false;
}
#Override
public void mouseDragged(MouseEvent e) {
if (drag == true) {
mouseX = e.getX();
mouseY = e.getY();
label1.setBounds(mouseX, mouseY, 100, 50);
}
}
public void mouseMoved(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
public static void main(String[] args) {
test frame = new test();
frame.setVisible(true);
frame.setSize(600, 400);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Just put this on your MouseDragged method:
public void mouseDragged(MouseEvent e)
{
if (drag == true)
{
JComponent jc = (JComponent)e.getSource();
jc.setLocation(jc.getX()+e.getX(), jc.getY()+e.getY());
}
}
The coordinates returned by MouseEvent::getX() and MouseEvent::getY() represent the location of the event relative to the event's subject (i.e. relative to the label itself), which explains why your solution results in the label erratically jumping.
By using MouseEvent::getComponent() to grab the label and then querying its position (possibly relative to the position when dragging commenced), you can devise a working solution.
Your problem is your setting your bounds based on the mouse location in the MouseListener, but the MouseListener has its location relative to the JLabel itself, but the JLabel's location should be set relative to the panel. You'll need to do some simple vector addition to figure this out.
edit: oops, I didn't see that this was already answered, and they say the same thing... sorry.
Maybe try adding something like that
The red one will do it better
private int clicX = 0;
private int clicY = 0;
public void mousePressed(MouseEvent e) {
drag = true;
if (e.getSource() == label1) {
}
if (e.getSource() == label2) {
clicX = e.getX();
clicY = e.getY();
}
}
public void mouseDragged(MouseEvent e) {
if (e.getSource() == label2) {
JComponent jc = (JComponent)e.getSource();
jc.setLocation(jc.getX()+e.getX()-clicX, jc.getY()+e.getY()-clicY);
}
Create two global variables:
int x_pressed = 0;
int y_pressed = 0;
then create two events (mousePressed and mouseDragged over JLabel):
lbl_banner.addMouseListener(new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent e) {
//catching the current values for x,y coordinates on screen
x_pressed = e.getX();
y_pressed = e.getY();
}
});
lbl_banner.addMouseMotionListener(new MouseMotionAdapter(){
#Override
public void mouseDragged(MouseEvent e){
//and when the Jlabel is dragged
setLocation(e.getXOnScreen() - x_pressed, e.getYOnScreen() - y_pressed);
}
});

Categories

Resources