2016-12-26 245 views
4

我正在創建支持透明度的JPanel,並且遇到問題,我不確定如何將相同級別的透明度應用於添加到所有Component的s這個面板。到目前爲止我的代碼:Java Swing - 將透明度應用到透明組件上JPanel

package de.uebertreiberman.project.swing; 

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Rectangle; 

import javax.swing.JPanel; 

@SuppressWarnings("serial") 
public class JTransparancyPanel extends JPanel { 

    float opacity = 1.0f; 

    /**Constructor for JTransparentPanel 
    */ 
    public JTransparancyPanel() 
    { 
     super(); 
     this.setOpaque(false); 
    } 

    /**Getter for opacity value of panel 
    * 
    * @return float containing opacity value of frame (0-1) 
    */ 
    public float getOpacity() 
    { 
     return opacity; 
    } 

    /**Setter for opacity value of panel 
    * 
    * @param value as float for opacity of frame (0-1) 
    */ 
    public void setOpacity(float value) 
    { 
     opacity = value; 
     repaint(); 
    } 

    /**Converts opacity value (0-1) to opacity color (0-255) 
    * 
    * @param opacity as float opacity value (0-1) 
    * @return integer containing converted opacity value (0-255) 
    */ 
    public static int getOpacityColor(float opacity) 
    { 
     return (int)(opacity * 255); 
    } 

    /**Converts opacity color (0-255) to opacity value (0-1) 
    * 
    * @param opacity as integer value (0-255) 
    * @return float containing converted opacity value (0-1) 
    */ 
    public static float getOpacityValue(int opacity) 
    { 
     //Returns more or less the correct, capped value 
     //Just ignore it, it works, leave it :D 
     return capFloat((3.9216f*opacity)/1000f, 0.0f, 1.0f); 
    } 

    /**Returns float capped between minimum and maximum value 
    * 
    * @param value as original value 
    * @param min as minimum cap value 
    * @param max as maximum cap value 
    * @return float containing capped value 
    */ 
    public static float capFloat(float value, float min, float max) 
    { 
     if(value < min) value = min; 
      else if(value > max) value = max; 

     return value; 
    } 

    /**Merges color and opacity to new color 
    * 
    * @param bg as color for old color, only RGB will be used from that 
    * @return color with RGB from bg and A from opacity of frame 
    */ 
    Color getTransparencyColor(Color bg) 
    { 
     return new Color(getOpacityValue(bg.getRed()), getOpacityValue(bg.getGreen()), getOpacityValue(bg.getBlue()), opacity); 
    } 

    @Override 
    public void paintComponent(Graphics g) 
    { 
     //Draw transparent background before painting other Components 
     g.setColor(getTransparencyColor(getBackground())); 
     Rectangle r = g.getClipBounds(); 
     g.fillRect(r.x, r.y, r.width, r.height); 

     //Paint other components 
     super.paintComponent(g); 
    } 
} 

的重要組成部分,基本上是在那裏我overwride的paintComponent(Graphics g)方法結束。

我只需要backgroundcolor,將透明度應用於它並進行設置。

現在我想讓這個面板的所有Component子元素都變得透明,我不太確定什麼是最有效的方法。

你會建議什麼?

+0

這是難以在不覆蓋的各成分的'paint' /'paintComponent'方法。沒有任何東西可以阻止兒童組件以明顯不透明的顏色公然填充其區域。人們可以嘗試將子組件繪製成圖像,然後使用適當的不透明度繪製該圖像。我會試試看,但它可能有點煩瑣。 – Marco13

+0

我還沒有嘗試,今天也沒有時間,但是你能不能只獲取組件('Component [] components = jpanel.getComponents();'),遍歷它們並使用'getGraphics() .setBackgroundColour()'? – MrB

回答

3

我找到了一個解決方案 - 基本上我在評論中已經提到過:面板不是真的畫在屏幕上。相反,它被繪製成圖像,並且該圖像被塗上適當的AlphaComposite

OpacityPanel

(滑塊可用於設置面板的不透明度)

雖然這種解決方案很簡單,通用的,應該基本上是與所有的子組件工作,有一兩件事我不喜歡它:有必要調整RepaintManager。爲了確保應用面板的不透明性(並且子組件不是獨立繪製的,並且具有完全不透明度),重繪管理器必須在子組件重新繪製時觸發重新繪製整個組件。我想認爲應該有沒有這種解決方法的解決方案(例如,這可能是在面板上重寫getGaphics可能是適當的罕見情況之一),但無濟於事。也許通常的嫌疑人(camickr,Hovercraft等)找到更優雅和簡潔的解決方案。

在那之前,這裏是代碼作爲MCVE:

import java.awt.AlphaComposite; 
import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Component; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.image.BufferedImage; 

import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JSlider; 
import javax.swing.JTree; 
import javax.swing.RepaintManager; 
import javax.swing.SwingUtilities; 

public class TransparencyPanelTest 
{ 
    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(() -> createAndShowGui()); 
    } 

    private static void createAndShowGui() 
    { 
     JFrame f = new JFrame(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.getContentPane().setLayout(new BorderLayout()); 

     OpacityPanel opacityPanel = new OpacityPanel(); 

     opacityPanel.setLayout(new BorderLayout()); 
     opacityPanel.add(new JLabel("Label"), BorderLayout.NORTH); 
     opacityPanel.add(new JTree(), BorderLayout.CENTER); 
     opacityPanel.add(new JButton("Button"), BorderLayout.SOUTH); 

     f.getContentPane().add(opacityPanel, BorderLayout.CENTER); 

     JSlider slider = new JSlider(0, 100, 50); 
     slider.addChangeListener(e -> 
      opacityPanel.setOpacity(slider.getValue()/100.0f)); 
     f.getContentPane().add(slider, BorderLayout.SOUTH); 

     f.setSize(500,500); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

} 

class OpacityPanel extends JPanel 
{ 
    static 
    { 
     RepaintManager.setCurrentManager(new RepaintManager() 
     { 
      @Override 
      public void addDirtyRegion(
       JComponent c, int x, int y, int w, int h) 
      { 
       Component cc = c; 
       while (cc != null) 
       { 
        if (cc instanceof OpacityPanel) 
        { 
         OpacityPanel p = (OpacityPanel)cc; 
         super.addDirtyRegion(
          p, 0, 0, p.getWidth(), p.getHeight()); 
        } 
        cc = cc.getParent(); 
       } 
       super.addDirtyRegion(c, x, y, w, h); 
      } 
     }); 
    } 
    private float opacity = 0.5f; 
    private BufferedImage image; 

    public OpacityPanel() 
    { 
     setOpaque(false); 
    } 

    public void setOpacity(float opacity) 
    { 
     this.opacity = Math.max(0.0f, Math.min(1.0f, opacity)); 
     repaint(); 
    } 

    private void updateImage() 
    { 
     int w = Math.min(1, getWidth()); 
     int h = Math.min(1, getHeight()); 
     if (image == null || image.getWidth() != w || image.getHeight() != h) 
     { 
      image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 
     } 
     Graphics2D g = image.createGraphics(); 
     g.setColor(new Color(0,0,0,0)); 
     g.setComposite(AlphaComposite.SrcOver); 
     g.fillRect(0, 0, w, h); 
     g.dispose(); 
    } 

    @Override 
    protected void paintComponent(Graphics gr) 
    { 
     updateImage(); 
     Graphics2D imageGraphics = image.createGraphics(); 
     super.paintComponent(imageGraphics); 
     imageGraphics.dispose(); 

     Graphics2D g = (Graphics2D) gr; 
     g.setComposite(AlphaComposite.getInstance(
      AlphaComposite.SRC_OVER, opacity)); 
     g.drawImage(image, 0, 0, null); 
    } 

} 
+0

很酷,感謝您的快速回復。 我認爲完全掌握這個解決方案對我而言已經有點太晚了,但我想我會明白你在做什麼。我會在明天嘗試將其實施到我的代碼中。 我也將更多地關注RepaintManager的細節,因爲我現在對它的工作原理感興趣。 但是,再次,謝謝,你幫了我很多! – Uebertreiberman

+0

@Uebertreiberman不要übertreiben與接受答案的速度;-)你可能想等一會兒,也許別人想出了一個更好的解決方案。我仍然認爲沒有重繪管理器應該有一個更簡單的方法,但Swing繪圖機制有時在引擎蓋下相當複雜,而且這看起來像是實現預期目標的簡單方法。 – Marco13