问题描述
请看看我的代码片段,它是错误的,当它在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.
谢谢
Mihir Parekh
Thank YouMihir Parekh
推荐答案
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秒
每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 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会冻结的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!