2013-11-27 2 views
-1

Я пытаюсь создать настраиваемый JProgressBar, который использует класс JLayer, чтобы его можно было покрасить по-разному в зависимости от ситуации, a la this solution. Дело в том, что я хочу его обернуть как JComponent, потому что он делает его более управляемым. Я бы выставил его как настраиваемый JLayer, но этот класс запечатан, поэтому ничего не делать.Создание пользовательского JComponent с JLayer над JProgressBar

Я пробовал просто сделать его JComponent, но на экране ничего не рисуется (возможно, потому, что я понятия не имею, как создать пользовательский JComponent, который содержит другие компоненты внутри него?). Я пробовал JFrame, который работает, но размер не прав, вероятно, потому, что индикатор выполнения использует диспетчер компоновки созданного мной JFrame вместо диспетчера компоновки, содержащего JFrame. Я пробовал JProgressBar, который рисует, но тогда у меня нет возможности вернуть JLayer и сохранить правильную иерархию без дополнительных вызовов методов после конструктора, который просто не кажется элегантным.

Вот мой пример кода, в значительной степени на основе кода от вопроса я связан выше:

public class Test { 
    public JComponent makeUI() { 
     final BoundedRangeModel model = new DefaultBoundedRangeModel(); 
     model.setValue(20); 

     final JPanel p = new JPanel(new GridLayout(4, 1, 12, 12)); 
     p.setBorder(BorderFactory.createEmptyBorder(24,24,24,24)); 

     // This does not draw 
     final ColorProgressBar pb4 = new ColorProgressBar(model); 
     p.add(pb4); 

     JPanel panel = new JPanel(new BorderLayout()); 
     panel.add(p, BorderLayout.NORTH); 
     return panel; 
    } 
    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 
    public static void createAndShowGUI() { 
     try { 
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
     JFrame f = new JFrame(); 
     f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     f.getContentPane().add(new Test().makeUI()); 
     f.setSize(320, 240); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 
} 

class ColorProgressBar extends JComponent { 
    private static final long serialVersionUID = -1265489165072929352L; 

    private BlockedColorLayerUI colorUI = new BlockedColorLayerUI(); 
    private JLayer<JProgressBar> layer; 
    private JProgressBar bar; 
    private PropertyChangeSupport supporter = new PropertyChangeSupport(new WeakReference<ColorProgressBar>(this)); 

    public ColorProgressBar(BoundedRangeModel model) { 
     bar = new JProgressBar(model); 
     layer = new JLayer<JProgressBar>(bar, colorUI); 
     this.add(layer); 
    } 

    public Color getColor() { 
     if (colorUI == null) 
      return null; 

     return colorUI.color; 
    } 

    public void setColor(Color color) { 
     Color oldColor = colorUI.color; 
     colorUI.color = color; 
     supporter.firePropertyChange("color", oldColor, color); 
    } 

    @Override 
    public void paintComponents(Graphics g) { 
     layer.paintComponents(g); 
    } 

    class BlockedColorLayerUI extends LayerUI<JProgressBar> { 
     public Color color = null; 
     private BufferedImage bi; 
     private int prevw = -1; 
     private int prevh = -1; 
     @Override public void paint(Graphics g, JComponent c) { 
      if(color != null) { 
       JLayer<?> jlayer = (JLayer<?>)c; 
       JProgressBar progress = (JProgressBar)jlayer.getView(); 
       int w = progress.getSize().width; 
       int h = progress.getSize().height; 

       if(bi==null || w!=prevw || h!=prevh) { 
        bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 
       } 
       prevw = w; 
       prevh = h; 

       Graphics2D g2 = bi.createGraphics(); 
       super.paint(g2, c); 
       g2.dispose(); 

       Image image = c.createImage(
         new FilteredImageSource(bi.getSource(), 
           new ColorFilter(color))); 
       g.drawImage(image, 0, 0, c); 
      } else { 
       super.paint(g, c); 
      } 
     } 
    } 
    class ColorFilter extends RGBImageFilter { 
     Color color; 

     public ColorFilter(Color color) { 
      this.color = color; 
     } 

     @Override public int filterRGB(int x, int y, int argb) { 
      int r = (int)((argb >> 16) & 0xff); 
      int g = (int)((argb >> 8) & 0xff); 
      int b = (int)((argb  ) & 0xff); 
      return (argb & color.getRGB()) | (g<<16) | (r<<8) | (b); 
     } 
    } 
} 

Кто-нибудь знает, где я неправильно? Благодаря!

EDIT: Я немного подрезал пример и изменил его, чтобы лучше выразить свою проблему. Извините за путаницу.

+0

Для лучшей помощи раньше, опубликовать [SSCCE] (http://sscce.org/). –

+0

Я не был уверен, как сделать его короче и сделать его поведение диагностическим. Если у вас есть какие-либо рекомендации, не стесняйтесь делиться ими; в противном случае это, безусловно, самодостаточно и компилируемо. – Jesse

+0

* «Я был не совсем уверен, как сделать его короче» * В SSCCE есть больше, чем «короткий». Вернитесь назад и прочитайте его снова. Также WTF делает 'UIManager.setLookAndFeel (UIManager.getSystemLookAndFeelClassName());' имеет отношение к проблеме?!? Вы должны были поэкспериментировать с его удалением. –

ответ

1

Вам может понадобиться позвонить super(model); и p.add(pb4.layer);

import java.awt.*; 
import java.awt.event.*; 
import java.awt.image.*; 
import java.beans.*; 
import java.lang.ref.WeakReference; 
import javax.swing.*; 
import javax.swing.plaf.LayerUI; 

public class Test2 { 
    public JComponent makeUI() { 
     final BoundedRangeModel model = new DefaultBoundedRangeModel(); 
     final JPanel p = new JPanel(new GridLayout(4, 1, 12, 12)); 
     p.setBorder(BorderFactory.createEmptyBorder(24,24,24,24)); 

     final JProgressBar pb1 = new JProgressBar(model); 
     pb1.setStringPainted(true); 
     p.add(pb1); 
     final JProgressBar pb2 = new JProgressBar(model); 
     pb2.setStringPainted(true); 
     p.add(pb2); 

     p.add(new JProgressBar(model)); 
     final ColorProgressBar pb4 = new ColorProgressBar(model); 
     p.add(pb4.layer); 

     JPanel box = new JPanel(); 
     box.add(new JButton(new AbstractAction("+10") { 
      private int i = 0; 
      @Override public void actionPerformed(ActionEvent e) { 
       model.setValue(i = (i>=100) ? 0 : i + 10); 
      } 
     })); 
     //http://msdn.microsoft.com/en-us/library/windows/desktop/aa511486.aspx 
     box.add(new JCheckBox(new AbstractAction(
       "<html>Turn the progress bar red<br />"+ 
         " when there is a user recoverable condition<br />"+ 
       " that prevents making further progress.") { 
      @Override public void actionPerformed(ActionEvent e) { 
       boolean b = ((JCheckBox)e.getSource()).isSelected(); 
       pb2.setForeground(b? new Color(255,0,0,100) : new Color(255,255,0,100)); 
       if (b) 
        pb4.setColor(Color.RED); 
       else 
        pb4.setColor(Color.YELLOW); 
       p.repaint(); 
      } 
     })); 

     JPanel panel = new JPanel(new BorderLayout()); 
     panel.add(p, BorderLayout.NORTH); 
     panel.add(box, BorderLayout.SOUTH); 
     return panel; 
    } 
    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 
    public static void createAndShowGUI() { 
     try { 
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
     JFrame f = new JFrame(); 
     f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     f.getContentPane().add(new Test2().makeUI()); 
     f.setSize(320, 240); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 
} 

class ColorProgressBar extends JProgressBar { 
    private static final long serialVersionUID = -1265489165072929352L; 

    private BlockedColorLayerUI colorUI = new BlockedColorLayerUI(); 
    public JLayer<JProgressBar> layer; 
    private PropertyChangeSupport supporter = new PropertyChangeSupport(new WeakReference<ColorProgressBar>(this)); 

    public ColorProgressBar(BoundedRangeModel model) { 
     super(model); 
     layer = new JLayer<JProgressBar>(this, colorUI); 
    } 

    public Color getColor() { 
     if (colorUI == null) 
      return null; 

     return colorUI.color; 
    } 

    public void setColor(Color color) { 
     Color oldColor = colorUI.color; 
     colorUI.color = color; 
     supporter.firePropertyChange("color", oldColor, color); 
    } 

//  @Override 
//  public void paintComponents(Graphics g) { 
//   layer.paintComponents(g); 
//  } 

    class BlockedColorLayerUI extends LayerUI<JProgressBar> { 
     public Color color = null; 
     private BufferedImage bi; 
     private int prevw = -1; 
     private int prevh = -1; 
     @Override public void paint(Graphics g, JComponent c) { 
      if(color != null) { 
       JLayer<?> jlayer = (JLayer<?>)c; 
       JProgressBar progress = (JProgressBar)jlayer.getView(); 
       int w = progress.getSize().width; 
       int h = progress.getSize().height; 

       if(bi==null || w!=prevw || h!=prevh) { 
        bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 
       } 
       prevw = w; 
       prevh = h; 

       Graphics2D g2 = bi.createGraphics(); 
       super.paint(g2, c); 
       g2.dispose(); 

       Image image = c.createImage(
         new FilteredImageSource(bi.getSource(), 
           new ColorFilter(color))); 
       g.drawImage(image, 0, 0, c); 
      } else { 
       super.paint(g, c); 
      } 
     } 
    } 
    class ColorFilter extends RGBImageFilter { 
     Color color; 

     public ColorFilter(Color color) { 
      this.color = color; 
     } 

     @Override public int filterRGB(int x, int y, int argb) { 
      int r = (int)((argb >> 16) & 0xff); 
      int g = (int)((argb >> 8) & 0xff); 
      int b = (int)((argb  ) & 0xff); 
      return (argb & color.getRGB()) | (g<<16) | (r<<8) | (b); 
     } 
    } 
} 
+0

Есть ли способ написать его так, t нужно ссылаться на поле .layer? Я чувствую, что даже если я зарегистрировал этот метод, есть очень хороший шанс, что кто-то из членов организации может подключить его неправильно, поскольку Swing более или менее сконструирован таким образом, что вы добавляете сами JComponents, а не поле внутри них. – Jesse

+0

Интересный SSCCE! –