GUI freezes when drawing Wave from animation on JPanel, although I used Swing Timer

Look at my code snippets, what's wrong with it, it frrezes the GUI, when is the Swing timer statistics that flaunts on jpnael ??

class WaveformPanel extends JPanel { Timer graphTimer = null; AudioInfo helper = null; WaveformPanel() { setPreferredSize(new Dimension(200, 80)); setBorder(BorderFactory.createLineBorder(Color.BLACK)); graphTimer = new Timer(15, new TimerDrawing()); } /** * */ private static final long serialVersionUID = 969991141812736791L; protected final Color BACKGROUND_COLOR = Color.white; protected final Color REFERENCE_LINE_COLOR = Color.black; protected final Color WAVEFORM_COLOR = Color.red; protected void paintComponent(Graphics g) { super.paintComponent(g); int lineHeight = getHeight() / 2; g.setColor(REFERENCE_LINE_COLOR); g.drawLine(0, lineHeight, (int) getWidth(), lineHeight); if (helper == null) { return; } drawWaveform(g, helper.getAudio(0)); } protected void drawWaveform(Graphics g, int[] samples) { if (samples == null) { return; } int oldX = 0; int oldY = (int) (getHeight() / 2); int xIndex = 0; int increment = helper.getIncrement(helper .getXScaleFactor(getWidth())); g.setColor(WAVEFORM_COLOR); int t = 0; for (t = 0; t < increment; t += increment) { g.drawLine(oldX, oldY, xIndex, oldY); xIndex++; oldX = xIndex; } for (; t < samples.length; t += increment) { double scaleFactor = helper.getYScaleFactor(getHeight()); double scaledSample = samples[t] * scaleFactor; int y = (int) ((getHeight() / 2) - (scaledSample)); g.drawLine(oldX, oldY, xIndex, y); xIndex++; oldX = xIndex; oldY = y; } } public void setAnimation(boolean turnon) { if (turnon) { graphTimer.start(); } else { graphTimer.stop(); } } class TimerDrawing implements ActionListener { @Override public void actionPerformed(ActionEvent e) { byte[] bytes = captureThread.getTempBuffer(); if (helper != null) { helper.setBytes(bytes); } else { helper = new AudioInfo(bytes); } repaint(); } } } 

I call setAnimation of WaveFormPanel from my parent class. When the animation begins, it draws nothing but a hang. please give me a solution.

Thanks Mihir Pareh

+3
source share
2 answers

java.swingx.Timer calls ActionPerformed in EDT . Then the question arises: what time should be done. It could be a call to captureThread.getTempBuffer , it could be a help construct, but I suspect it's just the amount of data you're trying to draw.

Playing with this recently, it takes quite a while to process the waveform.

One suggestion might be to reduce the number of patterns you draw. Instead of drawing each, perhaps draw every second or fourth sample point depending on the width of the component. You should still get the same joke, but without any work ...

UPDATED

All samples, 2.18 seconds

Allsamples

Every 4th sample, 0.711 seconds

enter image description here

Every eighth sample, 0.450 seconds

enter image description here

Instead of drawing in response to a timer, you may need to draw in response to a batch of data.

Since your bootloader thread has a “chunk” of data, it may then be red.

As suggested by HoverCraftFullOfEels, you can first draw this in a BufferedImage and then draw it on the screen ...

SwingWorker can achieve this for you

UPDATED

This is the code that I use to draw the above patterns.

 // Samples is a 2D int array (int[][]), where the first index is the channel, the second is the sample for that channel if (samples != null) { Graphics2D g2d = (Graphics2D) g; int length = samples[0].length; int width = getWidth() - 1; int height = getHeight() - 1; int oldX = 0; int oldY = height / 2; int frame = 0; // min, max is the min/max range of the samples, ie the highest and lowest samples int range = max + (min * -2); float scale = (float) height / (float) range; int minY = Math.round(((height / 2) + (min * scale))); int maxY = Math.round(((height / 2) + (max * scale))); LinearGradientPaint lgp = new LinearGradientPaint( new Point2D.Float(0, minY), new Point2D.Float(0, maxY), new float[]{0f, 0.5f, 1f}, new Color[]{Color.BLUE, Color.RED, Color.BLUE}); g2d.setPaint(lgp); for (int sample : samples[0]) { if (sample % 64 == 0) { int x = Math.round(((float) frame / (float) length) * width); int y = Math.round((height / 2) + (sample * scale)); g2d.drawLine(oldX, oldY, x, y); oldX = x; oldY = y; } frame++; } } 

I use the AudioStream stream to load a Wav file and create 2D samples.

+4
source

I assume that your wave-drawing code, which is called from the paintComponent(...) method, takes longer than you think and ties together both the Swing and the EDT.

If this was my code, I would think about drawing my waves in BufferedImages once, making ImageIcons from these images, and then just changing the icons in my Swing timer.

+3
source

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


All Articles