2014-01-24 62 views
4

因爲Java只支持single inheritance,我希望paint直接在JPanel的實例上,該實例是類Panel的成員。我從成員中獲取Graphics的實例,然後將任何我想要的東西繪製到它上面。Java JPanel getGraphics()

我能不從JComponentJPanel繼承和中仍使用getGraphics()this繪畫沒有覆蓋public void paintComponent(Graphics g)

private class Panel 
{ 
     private JPanel panel; 
     private Grahics g; 

     public Panel() 
     { 
      panel = new JPanel(); 
     } 

     public void draw() 
     { 
      g = panel.getGraphics(); 
      g.setColor(Color.CYAN); 
      g.draw(Some Component); 
      panel.repaint(); 
     } 
} 

面板添加到JFrame正在調用panel.draw()之前可見。這種方法對我不起作用,儘管我已經知道如何從JPanel繼承並重寫public void paintComponent(Graphics g)來繪製自定義組件,但我不想從JPanel繼承。

+0

基本上你不應該使用'getGraphics'。從它返回的Graphics上下文與交給paintComponent的Graphics上下文不一樣。在你的情況下,可能這是行不通的,因爲調用repaint會擦除你繪製的任何東西。你能解釋你想達到的目標嗎?事實上,這似乎是[XY問題](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)。 – Radiodef

+0

例如[這裏是一個類似的問題](http://stackoverflow.com/questions/15986677/drawing-an-object-using-getgraphics-without-extending-jframe),但你已經明確表示你不想要擴展JPanel並覆蓋paintComponent。解釋你在做什麼以及爲什麼可以建議解決方案會很有幫助。 – Radiodef

+0

這不是[XY問題](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem),因爲我已經知道我的問題的解決方案。我只想知道如何使用上述方法。 – Mushy

回答

5

這裏有一些非常簡單的例子,展示瞭如何在paintComponent之外繪畫。

繪圖實際上發生在java.awt.image.BufferedImage上,只要我們在「事件調度線程」上,我們就可以在任何地方執行此操作。 (有關Swing多線程的討論,請參見herehere。)

然後,我重寫了paintComponent,但只是將圖像繪製到面板上。 (我也在角落裏畫了一個小樣本)。

這樣,圖形實際上是永久性的,Swing能夠重新繪製面板,如果需要的話不會給我們造成問題。如果我們願意,我們也可以做一些像保存圖像到文件一樣容易。

PaintAnyTime screenshot

import javax.swing.*; 
import java.awt.*; 
import java.awt.image.*; 
import java.awt.event.*; 

/** 
* Holding left-click draws, and 
* right-clicking cycles the color. 
*/ 
class PaintAnyTime { 
    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new PaintAnyTime(); 
      } 
     }); 
    } 

    Color[] colors = {Color.red, Color.blue, Color.black}; 
    int currentColor = 0; 
    BufferedImage img = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB); 
    Graphics2D imgG2 = img.createGraphics(); 

    JFrame frame = new JFrame("Paint Any Time"); 
    JPanel panel = new JPanel() { 
     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      // Creating a copy of the Graphics 
      // so any reconfiguration we do on 
      // it doesn't interfere with what 
      // Swing is doing. 
      Graphics2D g2 = (Graphics2D) g.create(); 
      // Drawing the image. 
      int w = img.getWidth(); 
      int h = img.getHeight(); 
      g2.drawImage(img, 0, 0, w, h, null); 
      // Drawing a swatch. 
      Color color = colors[currentColor]; 
      g2.setColor(color); 
      g2.fillRect(0, 0, 16, 16); 
      g2.setColor(Color.black); 
      g2.drawRect(-1, -1, 17, 17); 
      // At the end, we dispose the 
      // Graphics copy we've created 
      g2.dispose(); 
     } 
     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(img.getWidth(), img.getHeight()); 
     } 
    }; 

    MouseAdapter drawer = new MouseAdapter() { 
     boolean rButtonDown; 
     Point prev; 

     @Override 
     public void mousePressed(MouseEvent e) { 
      if (SwingUtilities.isLeftMouseButton(e)) { 
       prev = e.getPoint(); 
      } 
      if (SwingUtilities.isRightMouseButton(e) && !rButtonDown) { 
       // (This just behaves a little better 
       // than using the mouseClicked event.) 
       rButtonDown = true; 
       currentColor = (currentColor + 1) % colors.length; 
       panel.repaint(); 
      } 
     } 

     @Override 
     public void mouseDragged(MouseEvent e) { 
      if (prev != null) { 
       Point next = e.getPoint(); 
       Color color = colors[currentColor]; 
       // We can safely paint to the 
       // image any time we want to. 
       imgG2.setColor(color); 
       imgG2.drawLine(prev.x, prev.y, next.x, next.y); 
       // We just need to repaint the 
       // panel to make sure the 
       // changes are visible 
       // immediately. 
       panel.repaint(); 
       prev = next; 
      } 
     } 

     @Override 
     public void mouseReleased(MouseEvent e) { 
      if (SwingUtilities.isLeftMouseButton(e)) { 
       prev = null; 
      } 
      if (SwingUtilities.isRightMouseButton(e)) { 
       rButtonDown = false; 
      } 
     } 
    }; 

    PaintAnyTime() { 
     // RenderingHints let you specify 
     // options such as antialiasing. 
     imgG2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
          RenderingHints.VALUE_ANTIALIAS_ON); 
     imgG2.setStroke(new BasicStroke(3)); 
     // 
     panel.setBackground(Color.white); 
     panel.addMouseListener(drawer); 
     panel.addMouseMotionListener(drawer); 
     Cursor cursor = 
      Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); 
     panel.setCursor(cursor); 
     frame.setContentPane(panel); 
     frame.pack(); 
     frame.setResizable(false); 
     frame.setLocationRelativeTo(null); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 
} 

它也有可能建立與ImageIcon一個JLabel,雖然我個人不喜歡這種方法。我不認爲JLabelImageIcon是他們的規範所要求的,以便在我們將它傳遞給構造函數之後查看對圖像所做的更改。

這種方式也不會讓我們做像繪畫色板的東西。 (對於稍微複雜一點的繪畫程序,例如MSPaint,我們希望能夠選擇一個區域並在其周圍畫一個邊框,這是我們希望能夠直接繪製的另一個地方面板,除了繪製圖像。)

import javax.swing.*; 
import java.awt.*; 
import java.awt.image.*; 
import java.awt.event.*; 

/** 
* Holding left-click draws, and 
* right-clicking cycles the color. 
*/ 
class PaintAnyTime { 
    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new PaintAnyTime(); 
      } 
     }); 
    } 

    Color[] colors = {Color.red, Color.blue, Color.black}; 
    int currentColor = 0; 
    BufferedImage img = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB); 
    Graphics2D imgG2 = img.createGraphics(); 

    JFrame frame = new JFrame("Paint Any Time"); 
    JLabel label = new JLabel(new ImageIcon(img)); 

    MouseAdapter drawer = new MouseAdapter() { 
     boolean rButtonDown; 
     Point prev; 

     @Override 
     public void mousePressed(MouseEvent e) { 
      if (SwingUtilities.isLeftMouseButton(e)) { 
       prev = e.getPoint(); 
      } 
      if (SwingUtilities.isRightMouseButton(e) && !rButtonDown) { 
       // (This just behaves a little better 
       // than using the mouseClicked event.) 
       rButtonDown = true; 
       currentColor = (currentColor + 1) % colors.length; 
       label.repaint(); 
      } 
     } 

     @Override 
     public void mouseDragged(MouseEvent e) { 
      if (prev != null) { 
       Point next = e.getPoint(); 
       Color color = colors[currentColor]; 
       // We can safely paint to the 
       // image any time we want to. 
       imgG2.setColor(color); 
       imgG2.drawLine(prev.x, prev.y, next.x, next.y); 
       // We just need to repaint the 
       // label to make sure the 
       // changes are visible 
       // immediately. 
       label.repaint(); 
       prev = next; 
      } 
     } 

     @Override 
     public void mouseReleased(MouseEvent e) { 
      if (SwingUtilities.isLeftMouseButton(e)) { 
       prev = null; 
      } 
      if (SwingUtilities.isRightMouseButton(e)) { 
       rButtonDown = false; 
      } 
     } 
    }; 

    PaintAnyTime() { 
     // RenderingHints let you specify 
     // options such as antialiasing. 
     imgG2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
          RenderingHints.VALUE_ANTIALIAS_ON); 
     imgG2.setStroke(new BasicStroke(3)); 
     // 
     label.setPreferredSize(new Dimension(img.getWidth(), img.getHeight())); 
     label.setBackground(Color.white); 
     label.setOpaque(true); 
     label.addMouseListener(drawer); 
     label.addMouseMotionListener(drawer); 
     Cursor cursor = 
      Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); 
     label.setCursor(cursor); 
     frame.add(label, BorderLayout.CENTER); 
     frame.pack(); 
     frame.setResizable(false); 
     frame.setLocationRelativeTo(null); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 
} 
0
class SomeComponent extends JComponent { 

    private Graphics2D g2d; 

    public void paintComponent(Graphics g) { 
     g2d = (Graphics2D) g.create(); 
     g2d.setColor(Color.BLACK); 
     g2d.scale(scale, scale); 
     g2d.drawOval(0, 0, importance, importance); 

    } 

    public Graphics2D getG2d() { 
     return g2d; 
    } 
    public void setG2d(Graphics2D g2d) { 
     this.g2d = g2d; 
    } 
} 

那麼你可以做以下 得到SomeComponent例如在面板和修改它

Graphics2D x= v.getPanel().get(i).getG2d; 
x.setColor(Color.BLUE); 
v.getPanel().get(i).setG2d(x); 
v.getPanel().repaint(); 
v.getPanel().revalidate(); 

V的擴展JFrame的,幷包含在它的面板,並 一類我是實例SomeComponent

+0

我不想從'JComponent'或'JPanel'同時繼承在位於我的班級Panel中的'JPanel'的本地實例上繪製。 – Mushy

+0

以前我有過你的問題,這是我發現啓用編輯paintComponent()方法的唯一方法,在這裏你不從JPanel繼承,你做自己的paint class –

+0

看起來好像沒有辦法它沒有使用繼承和重寫paintComponent()。 – Mushy