为VLCJ音频创建一个音量滑块

huangapple go评论78阅读模式
英文:

Creating a volume slider for VLCJ audio

问题

我正在尝试创建一个音量级别条,其中不同音量级别用不同的颜色表示,以下是我的方法:

我有两个数组

Color[] scales 为每个音量级别提供不同的颜色表示,如果这个数组的长度是4,那么就有4个音量级别,依此类推

float[] weights 表示每种颜色在条上应占用多少百分比/空间

例如

private final Color scales[]={Color.GREEN,Color.YELLOW,Color.RED};
private final float weights[]={0.3f,0.2f,0.5f};

这意味着有3个音量级别:

  1. 如果当前音量<=最大音量的30%,则音量条的30%由绿色覆盖
  2. 如果当前音量>30%且<=50%(30% + 20%),则音量条的下一个20%由黄色覆盖
  3. 如果当前音量>50%且<=100%(50% + 50%),则音量条的最后50%由红色覆盖

现在用户可以通过单击和拖动鼠标与音量条进行交互,假设音量条的尺寸是(x=120,y=50),如果我单击或拖动到X位置=25,则:

  • 30% of 120 = 36
  • XPosition = 25
  • 25 < 36,因此必须绘制一个绿色矩形,其尺寸为x=0,y=0,宽度=36-25=12,高度=50

接下来,我们按照相同的方式处理剩余位置,计算用户单击的位置并绘制不同颜色的矩形,直到该点。

现在,我认为我可能解释得不够清楚,但我不是在请求代码,因为我已经实现了它。这是我的最终代码示例:

final class VolumeBar extends JPanel 
{
 VolumeBar()
 {
  super(new BorderLayout());
  
  add(Box.createRigidArea(new Dimension(500,100)),BorderLayout.NORTH);
  
  add(Box.createRigidArea(new Dimension(500,100)),BorderLayout.SOUTH);
  
  JPanel container=new JPanel(new BorderLayout());
  
  container.add(Box.createRigidArea(new Dimension(120,50)),BorderLayout.WEST);
  
  container.add(Box.createRigidArea(new Dimension(120,50)),BorderLayout.EAST);
  
  container.add(new JVolume(),BorderLayout.CENTER);
  
  add(container,BorderLayout.CENTER);
 }
 
 private final class JVolume extends JLabel
 {
  private final Color scales[]={Color.GREEN,Color.YELLOW,Color.RED};
  private final float weights[]={0.6f,0.2f,0.2f};
  private int endingX;
  
  private JVolume()
  {
   addMouseMotionListener(new Drag());
   
   addMouseListener(new Click());
   
   setPreferredSize(new Dimension(260,50));
  }
  
  @Override
  public void paintComponent(Graphics g)
  {
   super.paintComponent(g);
   
   Graphics2D g2d=(Graphics2D)g;
   Dimension size=getSize();
  
  
   float endPoints[]=new float[scales.length+1];
   endPoints[0]=0;
   for(int i=1;i<endPoints.length;i++){endPoints[i]=endPoints[i-1]+(size.width*weights[i-1]);}
   
   for(int i=1;i<endPoints.length;i++)
   {
    float
    prev=endPoints[i-1],
    current=endPoints[i];
     
    if(endingX>prev) 
    {
     g2d.setColor(scales[i-1]);
  
     g2d.fill(new Rectangle2D.Float(prev,0,endingX>current?current-prev:endingX-prev,size.height));       
    }
    else{break;}
   }
   
   g2d.setColor(getBackground());
   Polygon clear=new Polygon();
   clear.addPoint(0,0);
   clear.addPoint(size.width,0);
   clear.addPoint(0,size.height);
   clear.addPoint(0,0);
   g2d.fill(clear);  //clear the upper left triangle with background to make it look like an increasing triangle
   
   g2d.setColor(Color.BLACK);  // draw the lower right triangle to give the bar some border
   Polygon polygon=new Polygon();
   polygon.addPoint(1,size.height-1);
   polygon.addPoint(size.width-1,1);
   polygon.addPoint(size.width-1,size.height-1);
   polygon.addPoint(1,size.height-1);
   g2d.drawPolygon(polygon);
  }
  
  private void compute(MouseEvent m)
  {
   endingX=m.getX();
   
   repaint();
  }
  
  private final class Drag extends MouseMotionAdapter
  {
   @Override
   public void mouseDragged(MouseEvent m){compute(m);}
  }

  private final class Click extends MouseAdapter
  {
   @Override
   public void mouseClicked(MouseEvent m){compute(m);}
  }
 }
}

希望这能帮助你实现你想要的音量条效果!

英文:

I am trying to create an volume level bar where different level's of volume are represented with an different color here is my approach

I have 2 arrays

Color[] scales gives different color representation for each volume level if the length of this array is lets say 4 then there are 4 volume level's and so on

float[] weights denotes how much percentage/space each color should occupy in the bar

For example

private final Color scales[]={Color.GREEN,Color.YELLOW,Color.RED};
private final float weights[]={0.3f,0.2f,0.5f};

means there are 3 levels of volume where

  1. if the current volume is <=30% of max then 30% of the volume bar is covered in GREEN

  2. if the current volume is >30% and <= (30+20)=50% the next 20% of the volume bar is covered in YELLOW

  3. if the current volume is >50% and <= (50+50)=100% the final 50% of the volume bar is covered in RED

Now the user interacts with the volume bar by clicking & dragging the mouse hence let' say if the volume bar has dimensions (x=120,y=50) and lets say I click or drag till Xposition=25 then

30% of 120=36
XPosition=25
25&lt;36 hence must draw an green color rect of dimensions x=0,y=0,width=36-25=12,height=50

and we continue likewise for the remaining positions calculating where the user clicks and drawing different color rectangles till that point.

Now I think I butchered the explanation but I am not asking for the code I already have it implemented here

final class VolumeBar extends JPanel 
{
VolumeBar()
{
super(new BorderLayout());
add(Box.createRigidArea(new Dimension(500,100)),BorderLayout.NORTH);
add(Box.createRigidArea(new Dimension(500,100)),BorderLayout.SOUTH);
JPanel container=new JPanel(new BorderLayout());
container.add(Box.createRigidArea(new Dimension(120,50)),BorderLayout.WEST);
container.add(Box.createRigidArea(new Dimension(120,50)),BorderLayout.EAST);
container.add(new JVolume(),BorderLayout.CENTER);
add(container,BorderLayout.CENTER);
}
private final class JVolume extends JLabel
{
private final Color scales[]={Color.GREEN,Color.YELLOW,Color.RED};
private final float weights[]={0.6f,0.2f,0.2f};
private int endingX;
private JVolume()
{
addMouseMotionListener(new Drag());
addMouseListener(new Click());
setPreferredSize(new Dimension(260,50));
}
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d=(Graphics2D)g;
Dimension size=getSize();
float endPoints[]=new float[scales.length+1];
endPoints[0]=0;
for(int i=1;i&lt;endPoints.length;i++){endPoints[i]=endPoints[i-1]+(size.width*weights[i-1]);}
for(int i=1;i&lt;endPoints.length;i++)
{
float
prev=endPoints[i-1],
current=endPoints[i];
if(endingX&gt;prev) 
{
g2d.setColor(scales[i-1]);
g2d.fill(new Rectangle2D.Float(prev,0,endingX&gt;current?current-prev:endingX-prev,size.height));       
}
else{break;}
}
g2d.setColor(getBackground());
Polygon clear=new Polygon();
clear.addPoint(0,0);
clear.addPoint(size.width,0);
clear.addPoint(0,size.height);
clear.addPoint(0,0);
g2d.fill(clear);  //clear the upper left triangle with background to make it look like an increasing triangle
g2d.setColor(Color.BLACK);  draw the lower right triangle to give the bar some border
Polygon polygon=new Polygon();
polygon.addPoint(1,size.height-1);
polygon.addPoint(size.width-1,1);
polygon.addPoint(size.width-1,size.height-1);
polygon.addPoint(1,size.height-1);
g2d.drawPolygon(polygon);
}
private void compute(MouseEvent m)
{
endingX=m.getX();
repaint();
}
private final class Drag extends MouseMotionAdapter
{
@Override
public void mouseDragged(MouseEvent m){compute(m);}
}
private final class Click extends MouseAdapter
{
@Override
public void mouseClicked(MouseEvent m){compute(m);}
}
}
}

And here is how it look's like just click or drag anywhere on the bar

为VLCJ音频创建一个音量滑块

Look's great for the most part but what I am aiming for is the volume bar in VLC media player

为VLCJ音频创建一个音量滑块

Forgive the blurriness, I had to scale the image up but if you look closely you can notice how the color's blend at the boundary for example there is an gradient from green->yellow making some white in between at the boundary and there is an gradient from yellow->red making some orange in between

I want to achieve this gradient.

Ideas anyone?

答案1

得分: 3

根据上面的评论,建议您可以使用MultipleGradientPaint来使用LinearGradientPaint

目前,我对您需要哪种渐变方式感到困惑,因为您之前说过:

  1. 如果当前音量小于等于最大音量的30%,则音量条的30%将变为绿色。

  2. 如果当前音量大于30%且小于等于(30+20)= 50%,则音量条的下一个20%将变为黄色。

  3. 如果当前音量大于50%且小于等于(50+50)= 100%,则音量条的最后50%将变为红色。

然后您又说:

我需要我的条形图中的60%为绿色,然后20%为黄色,而不是线性渐变所需的反过来的方式,现在明白为什么有问题了吗?

但那只是数字。

您可以这样创建LinearGradientPaint

Rectangle2D rect = new Rectangle2D.Double(10, 10, 250, 150);

Point2D startPoint = new Point2D.Double(rect.getMinX(), rect.getCenterY());
Point2D endPoint = new Point2D.Double(rect.getMaxX(), rect.getCenterY());
float[] percentages = new float[] {0.0f, 0.6f, 0.8f};
Color[] colors = new Color[] {Color.GREEN, Color.YELLOW, Color.RED};

LinearGradientPaint gradient = new LinearGradientPaint(startPoint, endPoint, percentages, colors, CycleMethod.REPEAT);

您之前对渐变的起始点感到困惑,我猜您的百分比是:0.6f, 0.2f, 0.2f,但实际上您需要定义起始点,然后从那里添加下一个百分比,0.0f, 0.6f, 0.8f(这将从0%开始,然后上升到60%变为绿色,然后上升到80%变为黄色,然后其余部分变为100%的红色)。

然后您会得到这个输出。

为VLCJ音频创建一个音量滑块

用于测试更改的MRE(最小可重现示例)如下:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.RenderingHints;
import java.awt.MultipleGradientPaint.CycleMethod;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class LinearGradientExample {
    private JFrame frame;
    private JPanel pane;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new LinearGradientExample()::createAndShowGUI);
    }

    @SuppressWarnings("serial")
    private void createAndShowGUI() {
        frame = new JFrame(getClass().getSimpleName());

        Rectangle2D rect = new Rectangle2D.Double(10, 10, 250, 150);
        Point2D startPoint = new Point2D.Double(rect.getMinX(), rect.getCenterY());
        Point2D endPoint = new Point2D.Double(rect.getMaxX(), rect.getCenterY());
        float[] percentages = new float[] {0.0f, 0.6f, 0.8f};
        Color[] colors = new Color[] {Color.GREEN, Color.YELLOW, Color.RED};

        LinearGradientPaint gradient = new LinearGradientPaint(startPoint, endPoint, percentages, colors, CycleMethod.REPEAT);

        pane = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g;

                g2d.setPaint(gradient);
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.fill(rect);
            }

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(300, 200);
            }
        };

        frame.add(pane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}
英文:

As recommended by @AndrewThompson in the comments above you can use MultipleGradientPaint using a LinearGradientPaint.

Currently I'm confused by which of the 2 you need, above you said:

> 1. if the current volume is <=30% of max then 30% of the volume bar is covered in GREEN
>
> 2. if the current volume is >30% and <= (30+20)=50% the next 20% of the volume bar is covered in YELLOW
>
> 3. if the current volume is >50% and <= (50+50)=100% the final 50% of the volume bar is covered in RED

And then you said:

> I need 60% of my bar in green then 20% in yellow not the other way around which is what LinearGradient requires.you see why it's a problem now?

But those are just numbers.

What you can do is create your LinearGradientPaint this way:

Rectangle2D rect = new Rectangle2D.Double(10, 10, 250, 150);
Point2D startPoint = new Point2D.Double(rect.getMinX(), rect.getCenterY());
Point2D endPoint = new Point2D.Double(rect.getMaxX(), rect.getCenterY());
float[] percentages = new float[] {0.0f, 0.6f, 0.8f};
Color[] colors = new Color[] {Color.GREEN, Color.YELLOW, Color.RED};
LinearGradientPaint gradient = new LinearGradientPaint(startPoint, endPoint, percentages, colors, CycleMethod.REPEAT);

You were confused at where you need to start the gradient because I guess your percentages were: 0.6f, 0.2f, 0.2f but instead you need to define the start point and then add the next percentage from there, 0.0f, 0.6f, 0.8f (This will start at 0% then go up to 60% to green, and then up to 80% to yellow, and then the rest to 100% on red.

And you get this output.

为VLCJ音频创建一个音量滑块


MRE for you to test changes:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.RenderingHints;
import java.awt.MultipleGradientPaint.CycleMethod;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class LinearGradientExample {
private JFrame frame;
private JPanel pane;
public static void main(String[] args) {
SwingUtilities.invokeLater(new LinearGradientExample()::createAndShowGUI);
}
@SuppressWarnings(&quot;serial&quot;)
private void createAndShowGUI() {
frame = new JFrame(getClass().getSimpleName());
Rectangle2D rect = new Rectangle2D.Double(10, 10, 250, 150);
Point2D startPoint = new Point2D.Double(rect.getMinX(), rect.getCenterY());
Point2D endPoint = new Point2D.Double(rect.getMaxX(), rect.getCenterY());
float[] percentages = new float[] {0.0f, 0.6f, 0.8f};
Color[] colors = new Color[] {Color.GREEN, Color.YELLOW, Color.RED};
LinearGradientPaint gradient = new LinearGradientPaint(startPoint, endPoint, percentages, colors, CycleMethod.REPEAT);
pane = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setPaint(gradient);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fill(rect);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
};
frame.add(pane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}

huangapple
  • 本文由 发表于 2020年7月29日 19:28:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/63152561.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定