Is it best to handle 2 overlays of live updated panels?

In very simple terms, I have a panel that draws a pixel of a line pixel by pixel and is updated in real time. In addition to this, I want the other panel to draw a rectangle around the current pixel, but it will be cleared later. Both are in real time.

My current situation is a JPanel wrapper with OverlayLayout . The bottom panel has a line that is drawn with a Graphics2D object derived from its JPanel . The top panel that follows it is also drawn using the Graphics2D object extracted from its JPanel .

There are many problems in this system. Since I just draw the Graphics2D object separately and without overriding JPanel paint() , not only all the lines are lost when the panel needs to be redrawn, I think I'm going against the Threading Swing model, having only one thread updates the screen. I also did not get the top panel for proper operation, it just clears the screen and does not allow the bottom panel to draw a line.

What would be the best way to approach this situation? I have little experience with image processing and low-level image display in Swing, I just know the basics. I heard about BufferedImage , but not knowing where to put this image, if it will be updated when it is changed later, the effectiveness of this and the fact that its buffering scares me. I'm not sure what to use

Can someone point me in the right direction what I need for this?

+6
source share
2 answers

I suggest

  • that you don’t get your JPanel Graphics or Graphics2D through getGraphics, since this object should not be stable and will not work as soon as the component has been repainted for any reason.
  • so that you complete your entire drawing in one JPanel paintComponent method, but first, the super method is called in this method.
  • that you draw only one JPanel again, not two,
  • that you draw your line in BufferedImage, as this is a more permanent part of your image.
  • What do you get a BufferedImage Graphics2D object through your createGraphics method
  • That you properly handle the BufferedImage Graphics object when you do this to conserve resources.
  • so that you display your BufferedImage in the paintComponent method of your JPanel (after the first call to the super method)
  • so that you draw your box, the more fleeting part of the image, directly into paintComponent, using int class variables to tell paintComponent where to draw, and possibly a boolean class variable to indicate whether to draw.
  • and most importantly, you are looking at Swing graphics tutorials to do it right, you have to throw away all the old assumptions and learn the right way from scratch (as we all should have done).

For instance:

 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(); } }); } } 
+3
source

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

+4
source

Source: https://habr.com/ru/post/897006/


All Articles