Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best to handle 2 overlaying live updated panels?

Tags:

java

swing

In very basic terms I have a panel that is drawing a line pixel by pixel and is being updated in real time. On top of this I want another panel that draws a box around the current pixel but clears itself later. Both are in real time

My current situation is a wrapper JPanel that has an OverlayLayout. The bottom panel has the line that is drawn with the Graphics2D object fetched from its JPanel. The top panel the box that follows around that is also drawn with the Graphics2D object fetched from its JPanel.

The issues in this system are many. Since I'm just drawing on the Graphics2D object separately and not overriding the JPanel's paint() not only is all the lines lost when the panel needs to repaint, I think I'm going against Swing's threading model by only having a single thread update the screen. I have also not gotten the top panel to work correctly, it just keeps clearing the screen and won't let the bottom panel draw a line.

What would be the best way to approach this situation? I have little experience with image processing and the low-level displaying of images in Swing, I just know the basics. I've heard of BufferedImage, but not knowing where to put that image, if it will be updated when changed later, the efficiency of doing that, and the fact that its buffered scare me off. I'm not sure what to use

Can someone point me in the right direction of what I need to use to accomplish this?

like image 248
TheLQ Avatar asked Sep 09 '11 17:09

TheLQ


2 Answers

You can accumulate your points in a suitable Shape, such as GeneralPath, as shown in LissajousPanel. Use a javax.swing.Timer to cause periodic updates, and highlight the most recently added point with a surrounding rectangle.

like image 132
trashgod Avatar answered Oct 04 '22 22:10

trashgod


I suggest

  • that you do not get your JPanel's Graphics or Graphics2D object via getGraphics as this object is not meant to be stable and will not work once the component has been repainted for any reason.
  • that you instead do all your drawing in a single JPanel's paintComponent method, but first in that method call the super's method.
  • that you again draw in only one JPanel, not two,
  • that you draw your line in a BufferedImage, since that is a more permanent part of your image.
  • That you get the BufferedImage's Graphics2D object via its createGraphics method
  • That you properly dispose of the BufferedImage's Graphics object when done using it so as to conserve resources.
  • that you display your BufferedImage in the paintComponent method of your JPanel (after calling the super method first)
  • that you draw your box, the more fleeting portion of the image, directly in the paintComponent using int class variables to tell paintComponent where to draw and perhaps a class boolean variable to tell if to draw.
  • and that most important, you review the tutorials on Swing graphics as to do this properly, you'll have to throw all old assumptions out and learn the correct way from the ground up (as we all had to do).

For example:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

@SuppressWarnings("serial")
public class BufferedImageEg extends JPanel {
   private static final int BI_WIDTH = 700;
   private static final int BI_HEIGHT = 500;
   private static final Color BACKGROUND = new Color(255, 255, 240);
   private static final int THIS_PT_WIDTH = 12;
   private static final int THIS_PT_HEIGHT = THIS_PT_WIDTH;
   private static final float THIS_PT_STROKE_WIDTH = 2f;
   private static final Color THIS_PT_BORDER_COLOR = Color.red;
   private static final Color THIS_PT_FILL_COLOR = new Color(250, 250, 0, 125);
   private static final int TIMER_DELAY = 30;
   private static final int X_MIN = 0;
   private static final int X_MAX = 100;
   private static final double X_STEP = 0.1;
   private static final double X_SCALE = (double) BI_WIDTH
         / ((double) X_MAX - X_MIN);
   private static final double Y_SCALE = 8;
   private static final float LINE_WIDTH = 4;
   private static final Color LINE_COLOR = Color.blue;

   private Point lastPoint = null;
   private Point thisPoint = null;

   private BufferedImage bImage = new BufferedImage(BI_WIDTH, BI_HEIGHT,
         BufferedImage.TYPE_INT_RGB);
   private double xValue = X_MIN;

   public BufferedImageEg() {
      Graphics biG = bImage.getGraphics();
      biG.setColor(BACKGROUND);
      biG.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
      setBackground(BACKGROUND);
      new Timer(TIMER_DELAY, new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            timerActionPerformed(e);
         }
      }).start();
   }

   private void timerActionPerformed(ActionEvent e) {
      if (xValue <= X_MAX) {
         lastPoint = thisPoint;
         double tempX = xValue;
         double yValue = function(xValue);

         tempX *= X_SCALE;
         yValue *= Y_SCALE;
         yValue = BI_HEIGHT / 2.0 - yValue;

         thisPoint = new Point((int) tempX, (int) yValue);

         if (lastPoint != null) {
            drawInBufferedImage();
         }

         xValue += X_STEP;
      } else {
         ((Timer) e.getSource()).stop();
         thisPoint = null;
      }
      repaint();
   }

   private void drawInBufferedImage() {
      Graphics2D g2 = bImage.createGraphics();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setStroke(new BasicStroke(LINE_WIDTH, BasicStroke.CAP_ROUND,
            BasicStroke.JOIN_ROUND));
      g2.setColor(LINE_COLOR);
      int x1 = lastPoint.x;
      int y1 = lastPoint.y;
      int x2 = thisPoint.x;
      int y2 = thisPoint.y;
      g2.drawLine(x1, y1, x2, y2);
      g2.dispose();
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(BI_WIDTH, BI_HEIGHT);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.drawImage(bImage, 0, 0, null);
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

      if (thisPoint != null) {
         drawThisPoint(g2);
      }
   }

   private void drawThisPoint(Graphics2D g2) {
      int x = thisPoint.x - THIS_PT_WIDTH / 2;
      int y = thisPoint.y - THIS_PT_HEIGHT / 2;
      Graphics2D g2b = (Graphics2D) g2.create();
      g2b.setStroke(new BasicStroke(THIS_PT_STROKE_WIDTH));
      g2b.setColor(THIS_PT_FILL_COLOR);
      g2b.fillOval(x, y, THIS_PT_WIDTH, THIS_PT_HEIGHT);
      g2b.setColor(THIS_PT_BORDER_COLOR);
      g2b.drawOval(x, y, THIS_PT_WIDTH, THIS_PT_HEIGHT);
      g2b.dispose();
   }

   private double function(double x) {
      return 24 * Math.sin(x / 12.0) * Math.sin(x);
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("BufferedImage Example");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new BufferedImageEg());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}
like image 25
Hovercraft Full Of Eels Avatar answered Oct 04 '22 21:10

Hovercraft Full Of Eels