2016-02-04 39 views
3

我使用基於this answer中代碼的自定義類來繪製形狀像對話框的背景。無論何時我調整應用程序的窗口大小以使組件的頂部或底部突出,所述組件的輪廓在其他組件的頂部被繪製在JScrollPane之外;在這種情況下是JPanelpaintComponent()繪製在其他組件上

在左側圖像中,由於組件仍然可見,繪製了JScrollPane底部組件的邊框;而在右側圖像中,所提到的組件不再可見,並且一切看起來都如預期的那樣。

我認爲這與我使用JScrollPane來包含組件並因此允許組件在JPanel下滑動的事實有關。我如何防止這種情況?

Image

主營:

public class Main { 
    public static void main(String[] args) { 
     JPanel panel = new JPanel(), panelbar = new JPanel(); 
     panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 
     panelbar.setLayout(new FlowLayout()); 

     JScrollPane scroll = new JScrollPane(panel, 
       JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
       JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 

     JFrame frame = new JFrame(""); 
     frame.setLayout(new BorderLayout()); 
     frame.setSize(200, 223); 

     for (int i = 0; i < 6; i++) { 
      JLabel label = new JLabel("JLabel"); 
      label.setBorder(new CustomBorder()); 
      label.setOpaque(true); 
      label.setBackground(Color.ORANGE); 
      panel.add(label); 
     } 

     panelbar.add(new JLabel("JPanel")); 

     frame.add(scroll, BorderLayout.CENTER); 
     frame.add(panelbar, BorderLayout.SOUTH); 

     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 
} 

自定義類:

public class CustomBorder extends AbstractBorder { 
    private static final long serialVersionUID = 1L; 
    Insets i; 

    CustomBorder() { 
     i = new Insets(10, 20, 10, 20); 
    } 

    @Override 
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { 
     super.paintBorder(c, g, x, y, width, height); 

     Polygon bubble = new Polygon(); 
     bubble.addPoint(x + 10, y + 5); 
     bubble.addPoint(x + width - 10, y + 5); 
     bubble.addPoint(x + width - 10, y + height/3); 
     bubble.addPoint(x + width, y + height/2); 
     bubble.addPoint(x + width - 10, y + height * 2/3); 
     bubble.addPoint(x + width - 10, y - 5 + height); 
     bubble.addPoint(x + 10, y - 5 + height); 

     Graphics2D g2d = (Graphics2D) g; 
     Area rect = new Area(new Rectangle(x, y, width, height)); 
     rect.subtract(new Area(bubble)); 
     g2d.setClip(rect); 
     g2d.setColor(c.getParent().getBackground()); 
     g2d.fillRect(0, 0, width, height); 
     g2d.setClip(null); 
     g2d.setColor(Color.BLACK); 
     g2d.draw(bubble); 
    } 

    @Override 
    public Insets getBorderInsets(Component c) { 
     return i; 
    } 

    @Override 
    public Insets getBorderInsets(Component c, Insets insets) { 
     return i; 
    } 
} 
+2

這個'g2d.setClip(rect);'會給你提出問題,因爲你已經改變了原來的'Graphics'上下文的剪輯,現在允許你在你不應該的地方繪畫,這就是爲什麼我不玩'剪輯'。取而代之的是,創建一個符合你想要生成的形狀的'形狀'和'繪製'/'填充',這個形狀是 – MadProgrammer

+1

FYI:調用'paintComponent'之後繪製'邊框',這意味着它們在內容上繪製。 。意思是如果你填充邊框,你在內容上繪畫... – MadProgrammer

+0

@MadProgrammer'draw/fill'將在文本的頂部繪製而不是在文本的後面,使得JLabel內的文本不可讀。 – Spitz

回答

7

有兩個問題與裁剪代碼:

  1. 減去泡沫,當你不與原來的剪輯開始(導致組件到滾動外畫)
  2. 你不」噸畫的氣泡之前恢復原始剪輯:

的變化將是:

@Override 
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { 
    super.paintBorder(c, g, x, y, width, height); 

    Polygon bubble = new Polygon(); 
    bubble.addPoint(x + 10, y + 5); 
    bubble.addPoint(x + width - 10, y + 5); 
    bubble.addPoint(x + width - 10, y + height/3); 
    bubble.addPoint(x + width, y + height/2); 
    bubble.addPoint(x + width - 10, y + height * 2/3); 
    bubble.addPoint(x + width - 10, y - 5 + height); 
    bubble.addPoint(x + 10, y - 5 + height); 

    Graphics2D g2d = (Graphics2D) g; 
    //Area rect = new Area(new Rectangle(x, y, width, height)); 
    Shape clip = g2d.getClip(); 
    Area rect = new Area(clip); 
    rect.subtract(new Area(bubble)); 
    g2d.setClip(rect); 
    g2d.setColor(c.getParent().getBackground()); 
    g2d.fillRect(0, 0, width, height); 
    //g2d.setClip(null); 
    g2d.setClip(clip); 
    g2d.setColor(Color.BLACK); 
    g2d.draw(bubble); 
} 
+0

不錯的一個!我會將我的答案鏈接到這一個。 :) –

5

您的基本問題是,你改變剪切區域,這是該組件被漆成之前設置,以某種方式,其他,這是讓你畫在組件的界限之外......

隨着討論herehere,邊界並不意味着填寫,也不會影響由paintComponent

充滿如果您在A Closer Look at the Paint Mechanism看看你會看到paintComponentpaintBorder之前稱爲區域...

javax.swing.JComponent中這個類和進一步因素 paint方法延伸到三種不同的方法,這是在 調用順序如下:

  • 保護無效paintComponent(圖形G)
  • 保護無效的paintBorder(圖形G)
  • 保護無效paintChildren(圖形G)

那麼,有什麼解決辦法?假裝!

Fake it

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.EventQueue; 
import java.awt.FlowLayout; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GridBagLayout; 
import java.awt.Insets; 
import java.awt.Polygon; 
import javax.swing.BoxLayout; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.border.EmptyBorder; 

public class BorderCheat { 

    public static void main(String[] args) { 
     new BorderCheat(); 
    } 

    public BorderCheat() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JPanel panel = new JPanel(), panelbar = new JPanel(); 
       panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 
       panelbar.setLayout(new FlowLayout()); 

       JScrollPane scroll = new JScrollPane(panel, 
         JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
         JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 

       for (int i = 0; i < 6; i++) { 
        BubblePane bp = new BubblePane(); 
        bp.setBackground(Color.ORANGE); 
        JLabel label = new JLabel("JLabel"); 
        bp.add(label); 
        panel.add(bp); 
       } 

       panelbar.add(new JLabel("JPanel")); 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(scroll); 
       frame.add(panelbar, BorderLayout.SOUTH); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class BubblePane extends JPanel { 

     public BubblePane() { 
      setLayout(new GridBagLayout()); 
      setBorder(new EmptyBorder(10, 20, 10, 30)); 
      setOpaque(false); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      Insets insets = getInsets(); 
      int x = 0; 
      int y = 0; 
      int width = getWidth(); 
      int height = getHeight(); 
      Polygon bubble = new Polygon(); 
      bubble.addPoint(x, y); 
      bubble.addPoint(x + width - insets.right + 10, y); 
      bubble.addPoint(x + width - insets.right + 10, y + height/3); 
      bubble.addPoint(x + width, y + height/2); 
      bubble.addPoint(x + width - insets.right + 10, y + height * 2/3); 
      bubble.addPoint(x + width - insets.right + 10, y + height); 
      bubble.addPoint(x, y + height); 

      g2d.setColor(getBackground()); 
      g2d.fill(bubble); 
      g2d.setColor(Color.BLACK); 
      g2d.draw(bubble); 
      g2d.dispose(); 
     } 

    } 

} 

好 「但他們之間沒有差距」 你說。好的,請使用CompoundBorder或允許您指定組件之間的垂直或水平間距的佈局...

相關問題