Java paintComponent(Graphics g) drawn graphics disappear - java

I am new to the graphics and paint on java swing component. I have a few code issue related to these areas.
I have a customJPanel that extends JPanel. Inside the panel, there is a "+" and "-" button to increase the number of image by 1 at a time (minimum 1 image, maximum 50 image). The images are already stored in a list. The buttons are listener that takes care of the add/remove image on the customJPanel:
//ADD BUTTON LISTENER
imagePanel.add(imageList.get(i);
add(imagePanel, BorderLayout.CENTER); //customPanel contains a imagePanel(center), and another panel(south)
repaint();
revalidate();
Once the images are added, I have a function that draws lines to link the images to a fixed point(x1, y1) on the JPanel.
public void drawLinkedLine(){
Graphics2D g2d = (Graphics2D) imagePanel.getGraphics();
g2d.setColor(Color.BLACK);
for(int i = 0; i < imagesList.size(); i++){
//some codes to get the image location on the imagePanel
g2d.drawLine(x1, y1, x2, y2);
}
}
This method is called by the override paintComponent(Graphics g):
public void paintComponent(Graphics g){
super.paintComponent(g);
drawLinkedLine();
}
The issues I am facing now is when I click on the button, it adds/removes 1 image. It suppose to draw line from that image to (x1,y1). However, I can see the lines appear in a flash and disappear. Why would this happening and is there a way to solve this?

Related

Build a grid and let the squares blink

I'm not well familiar with Java and try to build a grid in a window but I'm not sure which Class I should extend (like JFrame) and which method is the best way to get that grid.
My goal is to create a grid and let the squares blink randomly.
I tried it JPanel but not sure if it is the right way
JPanel content = new JPanel(new GridLayout(4,4));
I would use a JPanel on a JFrame. You override the paintComponent Method of the JPanel to fit your needs:
#Override
public void paintComponent(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLACK);
//draw rects
for(int i=0; i<n; i++){
//draw rects
g2d.drawRect(x, y, width, height);
}
//fill rects
for(int i=0; i<n i++){
//set random color for blinking effect
g2d.setColor(/*random color*/);
g2d.fillRect(x, y, width, height);
}
}
You have to compute the grid yourself though, using the size of your JPanel and the size of the squares you want to draw.
Then, set a Timer and redraw every time you want that blinking effect.
If you are not familiar with java Swing and simple draw operations, you should watch same tutorials etc. because im not going to explain it all here ;).

how to draw a black rectangle over Image icon?

in my application I have a cross road picture in the background and I want to draw traffic lights on the top of it (black rectangle with 3 circles)
The problem is, I cannot see the rectangle at all, as if it was under the image or something. And if I switch the order in which the items are painted, I get all black image.
Do you have any idea how this can be solved?I am new to graphics and searched similar questions, but none helped me.
Thank you.
public MainFrame() throws HeadlessException {
super("semafor");
crossroad = new ImageIcon("cross.png");
initFrame();
initComponents();
sem1 = new Semafor(true, 100, 100);
add(sem1);
repaint();
setVisible(true);
}
//here I paint the image
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(crossroad.getImage(), 0, 45, this);
}
//and in class Semafor i paint the actual traffic lights
#Override
public void paint(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.darkGray);
//and then the circles
}
The first thing I'm noticing is that you are calling <unknown>.getWidth() and <unknown>.getHeight() for the rectangle size. If it's covering the entire image, this suggests that it is getting that width and height from the panel it is being drawn on.
A simple stack trace,
(new Exception).printStackTrace();
or
Thread.dumpStack();
will tell you as much. You could also query the width and height with a System.out call to verify that you're getting the values you're expecting, or, if this really gets out of control, learn to use JUnit and the assert statement. Honestly, though, it looks like you're just accidentally calling the wrong method.

BasicStroke causes offcenter

Changing the BasicStroke of a Graphics2D object to anything other than 1 causes it to not draw something on the center of a JPanel on startup.
This is a JPanel which is on a JFrame. This is the basic idea of my project, but it is not the entire thing.
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
if(this.centered){
this.myShape.setCenterX(this.getWidth()/2);
this.myShape.setCenterY(this.getHeight()/2);
}
g2.setStroke(new BasicStroke(3)); //new BasicStroke(1) works fine
g2.draw(this.myShape);
}
When you click and drag the myShape, myShape will immediately jump to the center. But when I initially compile and run it, paintComponent() paints it about a centimeter above the center of the screen if the stroke is not 1.
Is there something wrong with how I'm centering? I defined the MyShape class, so there could be an error there. Maybe the distance between the center and the drawing point is the space between JPanel and the top of the JFrame? How do I fix it?
Edit: added picture
http://s21.postimage.org/dfpmz73et/Untitled_1.png
The first shape is right where I want it. The other two are above where I want it. But it appears the displacement from the center are the same regardless of stroke size.
Yes, I believe this is the normal behaviour for a shape. It assumes an outline of 1 pixel. So you need to change the center calculation when you know you are going to change the basic stroke size. Something like:
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
BasicStroke stroke = new BasicStroke(3);
int adjustment = stroke.getLineWidth() - 1;
if(this.centered){
this.myShape.setCenterX(this.getWidth() + adjustment / 2);
this.myShape.setCenterY(this.getHeight() + adjustment / 2);
}
g2.setStroke(stroke);
g2.draw(this.myShape);
}

Jpanel Zooming like in a paint program

I've got a problem over a zoom feature on a program. Here's the deal, I got a canvas which extends a jpanel and has a grid drawn on it. My problem is how to implement a zoom function. By zooming on the jpanel each small squares on the grid will divided into 3x3.
I've tried doing a 3 panel zoom, 3 panels with 3 different sizes with different division on the grid but it takes up a lot of memory and run time. I'm implementing only 1 jpanel with fix size and will zoom on it by using Graphics2d.scale(...) but seems to have an offset on the mouse coordinates and the jpanel's. I know it could be fix but my other concern is the jpanel is implemented with jscrollpane. Will fixing the coordinate offset will solve this issue, i haven't tried because i don't know how.
paint in the jpanel drawing the grid
public void paint(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int x=0;int y=0;
g2.setColor(Color.GRAY);
for(int i=1; i<this.divisions; i++){
x = i *divSize;
g2.drawLine(x, 0, x, this.size);
}
for(int i=1; i<this.divisions; i++){
y = i *divSize;
g2.drawLine(0, y, this.size, y);
}
/*code for filling the small squares with colors*/
}
You can draw all your content on a BufferedImage. Graphics of the image can be scaled to achieve desired zoom effect.
But anyway if you use JScrollPane with panel inside the panel's size (preferred size) must be adapted to show scrollbars when it's needed.

Move multiple BufferedImage in Java2D?

How can I mousedrag different BufferedImages in Java2D?
For instance, if I have ten or more images, how can I move that images which my mouse is over?
Now I'm importing an BufferedImage with
BufferedImage img = new BufferdImage(new File("filename"));
And I'm painting this with Graphics2D with
public void paintComponent(Graphics g) {
super.paintComponent(g);
g2d = (Graphics2D) g;
g2d.drawImage(img, x1, y1, null);
g2d.drawImage(img2, x2, y2,null);
}
Everytime I'm moving on a image I'm repaint()-ing the entire screen.
My mousemove class is as follows
class MouseMotionHandler extends MouseMotionAdapter {
#Override
public void mouseDragged(MouseEvent e) {
x1 = e.getX() - (img.getWidth() / 2);
y1 = e.getY() - (img.getHeight() / 2);
repaint();
}
}
With this method I'm able to "drag" one picture, but what to do when I will drag more individually?
Use the BufferedImage to create an ImageIcon which you use to create a JLabel. Then you add the JLabel to the panel that uses a null layout. No custom painting code is required to do this.
Now if you want to drag the label around you can use the Component Mover.
You can try making a custom component that contains only a single image. Along with your painting and mouse motion handling code, the component overrides the contains method so that it returns true only if the coordinates are within the image.
These components are then stacked in a JLayeredPane, (hopefully) only moving the images that the mouse is on top of.
From what you ask I suppose that your current repainting logic is global. You need to apply it to every image you have. So, if you for instance display every image in JPanel attach MouseMotionListener to every such panel and make this logic happen in JPanel.
If you post more code - especially of the component you show your images in - I will be able to go into more details.
Here's is a simple example that implements dragging for either single- or multiple-selections. The object Node would correspond roughly to your object Card.
Addendum: Also considered the Overlap Layout mentioned in this answer to a related question. Instead of List<Node>, your program would manage a List<Card>, where each Card is a JLabel having a card image.
I should make tree arrays:
one for the x-values
one for the y-values
one for the BufferedImages
So, something like this:
int[] xValues = new int[10];
int[] yValues = new int[10];
BufferedImage[] imgs = new BufferedImage[10];
Then the
class MouseMotionHandler extends MouseMotionAdapter {
#Override
public void mouseDragged(MouseEvent e) {
for (int i = 0; i < 10; i++)
{
xValues[i] = e.getX() - (imgs[i].getWidth() / 2);
yValues[i] = e.getY() - (imgs[i].getHeight() / 2);
}
repaint();
}
}
Then paint them like this:
public void paintComponent(Graphics g) {
super.paintComponent(g);
g2d = (Graphics2D) g;
for (int i = 0; i < 10; i++)
{
g2d.drawImage(imgs[i], xValues[i], yValues[i], null);
}
}
I think something like this is what you need.
Here's the code for my JLayeredPane init. My problem here is that my images don't show up...
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new java.awt.Dimension(500, 410));
layeredPane.setBorder(javax.swing.BorderFactory.createTitledBorder(
"Center deck"));
for(BufferedImage imgs : images){
JLabel label = new JLabel(new ImageIcon(imgs));
layeredPane.add(label, JLayeredPane.DEFAULT_LAYER);
}
add(layeredPane);

Categories

Resources