尽管我使用了 Swing Timer,但在 JPanel 上从动画绘制 Wave 时 GUI 冻结 [英] GUI freezes when drawing Wave from animation on JPanel though i used Swing Timer

查看:21
本文介绍了尽管我使用了 Swing Timer,但在 JPanel 上从动画绘制 Wave 时 GUI 冻结的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请查看我的代码片段,它有什么问题,当在 jpnael 上重复绘制的 Swing 计时器统计信息时,它会冻结 GUI ??

plese look at my code snippets , wha is wrong with it , it frrezes GUI when the Swing timer stats which is repeteadly paints on the 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();
            }
        }

    }

我正在从其父类调用 WaveFormPanel 的 setAnimation.当动画开始时,它不会绘制任何东西,但会冻结.请给我解决方案.

I am calling setAnimation of WaveFormPanel from its parent class.when animation starts it does not draw anything but freezes. please , give me solution.

谢谢米希尔·帕雷克

推荐答案

java.swingx.Timer 调用 EDT 内的 ActionPerformed.那么问题是,什么需要时间来渲染.它可能是对 captureThread.getTempBuffer 的调用,也可能是帮助的构造,但我怀疑这只是您尝试绘制的共享数据量.

The java.swingx.Timer calls the ActionPerformed within the EDT. The question then is, what's taking the time to render. It could be the call to captureThread.getTempBuffer it could be the construction of the help, but I suspect it's just the share amount of data you are trying to paint.

最近在玩这个,处理波形需要相当多的时间.

Having playing with this recently, it takes quite a bit of time to process the waveform.

一个建议可能是减少您绘制的样本数量.而不是每一个都画,也许根据组件的宽度每第二个或第四个样本点画一次.你仍然应该得到同样的笑话,但没有所有的工作......

One suggestion might be to reduce the number of samples that you paint. Rather then painting each one, maybe paint every second or forth sample point depending on the width of the component. You should still get the same jest but without all the work...

更新

所有样本,2.18 秒

All samples, 2.18 seconds

每 4 个样本,0.711 秒

Every 4th sample, 0.711 seconds

每 8 个样本,0.450 秒

Every 8th sample, 0.450 seconds

而不是响应计时器绘制,也许您需要响应批量数据进行绘制.

Rather then paint in response to the timer, maybe you need to paint in response to batches of data.

由于您的加载器线程有一个块"数据,因此可能会对其进行绘制.

As your loader thread has a "chunk" of data, may be paint it then.

正如 HoverCraftFullOfEels 所建议的,您可以先将其绘制到 BufferedImage 上,然后再将其绘制到屏幕上...

As HoverCraftFullOfEels suggested, you could paint this to a BufferedImage first and then paint that to the screen...

SwingWorker 或许可以为您做到这一点

SwingWorker might be able to achieve this for you

更新

这是我用来绘制上述示例的代码.

This is the code I use to paint the above samples.

// 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++;

    }

}

我使用 AudioStream 流来加载 Wav 文件并生成 2D 样本.

I use an AudioStream stream to load a Wav file an produce the 2D samples.

这篇关于尽管我使用了 Swing Timer,但在 JPanel 上从动画绘制 Wave 时 GUI 冻结的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆