为 VLCJ 音频创建音量滑块

Creating a volume slider for VLCJ audio

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

我有 2 个数组

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

float[] 权重表示 percentage/space 每种颜色在栏中应占多少

例如

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% 且 <= (30+20)=50%,则音量栏的下一个 20% 会被黄色覆盖

  3. 如果当前音量 >50% 且 <= (50+50)=100%,则音量条的最后 50% 会被红色覆盖

现在用户通过单击和拖动鼠标与音量条交互,因此假设音量条是否具有尺寸 (x=120,y=50) 并假设我单击或拖动直到 Xposition=25 然后

30% of 120=36

XPosition=25

25<36 hence must draw an green color rect of dimensions x=0,y=0,width=36-25=12,height=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);}
  }
 }
}

下面是它的外观,只需单击或拖动栏上的任意位置

大部分看起来很棒,但我的目标是 VLC 媒体播放器中的音量条

请原谅模糊,我不得不按比例放大图像,但如果你仔细观察,你会注意到颜色在边界处是如何混合的,例如有一个从绿色到黄色的渐变,在边界处中间有一些白色并且有一个从黄色到红色的渐变,中间有一些橙色

我想实现这个渐变。

有人有想法吗?

正如@AndrewThompson 在上面的评论中所推荐的,您可以使用 MultipleGradientPaint 使用 LinearGradientPaint.

目前我对你需要哪两个感到困惑,上面你说:

  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

然后你说:

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?

但这些只是数字。

您可以这样创建 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% 变为红色。

你得到这个输出。


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);
    }
}