Java JPanel getGraphics()

由于Java仅支持single inheritance ,因此我希望直接在作为类Panel成员的JPanel实例上paint 。 我从成员那里获取了一个Graphics实例,然后将我想要的任何东西绘制成它。

我怎么能不inheritanceJComponentJPanel并仍然使用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 ,该JFrame在调用panel.draw()之前可见。 这种方法对我不起作用,虽然我已经知道如何通过inheritanceJPanel并重写public void paintComponent(Graphics g)来绘制自定义组件,但我不想从JPanelinheritance。

以下是一些非常简单的示例,展示了如何在paintComponent外部进行绘制。

绘图实际上发生在java.awt.image.BufferedImage ,我们可以在任何地方进行,只要我们在事件调度线程上。 (有关使用Swing进行multithreading处理的讨论,请参阅此处和此处 。)

然后,我重写了paintComponent ,但只是将图像绘制到面板上。 (我也在角落里涂了一点色板。)

这样绘图实际上是永久性的,如果需要,Swing能够重新绘制面板,而不会给我们带来问题。 如果我们愿意的话,我们也可以做一些像将文件轻松保存到文件中的操作。

PaintAnyTime截图

 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); } } 
 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的实例