Java JPanel getGraphics()
由于Java仅支持single inheritance
,因此我希望直接在作为类Panel
成员的JPanel
实例上paint
。 我从成员那里获取了一个Graphics
实例,然后将我想要的任何东西绘制成它。
我怎么能不inheritanceJComponent
或JPanel
并仍然使用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)
来绘制自定义组件,但我不想从JPanel
inheritance。
以下是一些非常简单的示例,展示了如何在paintComponent
外部进行绘制。
绘图实际上发生在java.awt.image.BufferedImage
,我们可以在任何地方进行,只要我们在事件调度线程上。 (有关使用Swing进行multithreading处理的讨论,请参阅此处和此处 。)
然后,我重写了paintComponent
,但只是将图像绘制到面板上。 (我也在角落里涂了一点色板。)
这样绘图实际上是永久性的,如果需要,Swing能够重新绘制面板,而不会给我们带来问题。 如果我们愿意的话,我们也可以做一些像将文件轻松保存到文件中的操作。
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
,虽然我个人不喜欢这种方法。 我不认为JLabel
和ImageIcon
是他们的规范所要求的,以便在我们将它传递给构造函数后看到我们对图像所做的更改。
这种方式也不会让我们做像绘制样本的东西。 (对于稍微复杂一点的绘图程序,在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的实例