這裏有一些非常簡單的例子,展示瞭如何在paintComponent
之外繪畫。
繪圖實際上發生在java.awt.image.BufferedImage
上,只要我們在「事件調度線程」上,我們就可以在任何地方執行此操作。 (有關Swing多線程的討論,請參見here和here。)
然後,我重寫了paintComponent
,但只是將圖像繪製到面板上。 (我也在角落裏畫了一個小樣本)。
這樣,圖形實際上是永久性的,Swing能夠重新繪製面板,如果需要的話不會給我們造成問題。如果我們願意,我們也可以做一些像保存圖像到文件一樣容易。
![PaintAnyTime screenshot](https://i.stack.imgur.com/8oY2e.png)
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);
}
}
基本上你不應該使用'getGraphics'。從它返回的Graphics上下文與交給paintComponent的Graphics上下文不一樣。在你的情況下,可能這是行不通的,因爲調用repaint會擦除你繪製的任何東西。你能解釋你想達到的目標嗎?事實上,這似乎是[XY問題](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)。 – Radiodef
例如[這裏是一個類似的問題](http://stackoverflow.com/questions/15986677/drawing-an-object-using-getgraphics-without-extending-jframe),但你已經明確表示你不想要擴展JPanel並覆蓋paintComponent。解釋你在做什麼以及爲什麼可以建議解決方案會很有幫助。 – Radiodef
這不是[XY問題](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem),因爲我已經知道我的問題的解決方案。我只想知道如何使用上述方法。 – Mushy