我已经看过许多与此类似的问题的答案,但是他们似乎都说要画到我正在做的JPanel上,所以我不明白如何让我的矩形不闪烁。
我正在制作一个截图制作工具,就像Mac上的CMD + SHIFT + 4功能一样。我有一切正常工作,即拖动矩形时会拍照,但是你选择的矩形会一直闪烁。
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.BufferStrategy;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.File;
import java.io.PrintWriter;
import javax.swing.*;
import javax.swing.event.*;
import javax.imageio.ImageIO;
import java.text.SimpleDateFormat;
import java.util.*;
import java.awt.geom.Area;
public class ScreenShotter extends JPanel implements MouseListener {
static JPanel contentPane;
private static JPanel picture1;
static int startX, startY, endX, endY;
static int width;
static int height;
int x, y;
int radius = 2;
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd kk.mm.ss");
static File f = new File("ScreenShotter.txt");
static String filePath = f.getPath();
static String screenshotPath = "";
JFileChooser chooser;
String chooserTitle = "Select the folder to store your screenshots";
static Point currentPoint;
static Point startPoint;
static boolean clicked = false;
static BufferStrategy bs;
public ScreenShotter() {
setLayout(new BorderLayout());
contentPane = new JPanel(new BorderLayout());
contentPane.requestFocus();
picture1 = new JPanel();
picture1.addMouseListener(this);
picture1.setPreferredSize(new Dimension(width, height));
contentPane.add(picture1);
}
public ScreenShotter(boolean bool){
final String[] labels = {"Screen width: ", "Screen Height: "};
int labelsLength = labels.length;
final JTextField[] textField = new JTextField[labelsLength];
final JPanel p = new JPanel(new SpringLayout());
for(int i = 0; i < labelsLength; i++){
JLabel l = new JLabel(labels[i], JLabel.TRAILING);
p.add(l);
textField[i] = new JTextField(10);
l.setLabelFor(textField[i]);
p.add(textField[i]);
}
final JButton button = new JButton("Submit");
p.add(new JLabel());
p.add(button);
SpringUtilities.makeCompactGrid(p,
labelsLength + 1, 2,
7, 7,
7, 7);
final JFrame frame = new JFrame("File Maker");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//for(int i = 0; i < labels.length; i++){
//System.out.println(labels[i]+"->"+textField[i].getText());
//screenshotPath = textField[0].getText();
width = Integer.parseInt(textField[0].getText());
height = Integer.parseInt(textField[1].getText());
//}
chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("."));
chooser.setDialogTitle(chooserTitle);
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if(chooser.showOpenDialog(button) == JFileChooser.APPROVE_OPTION){
System.out.println("getCurrentDirectory(): " + chooser.getCurrentDirectory());
System.out.println("getSelectedFile(): " + chooser.getSelectedFile());
screenshotPath = slashConverter(chooser.getSelectedFile().toString());
} else {
System.out.println("No selection.");
}
frame.dispose();
createFile();
}
});
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
p.setOpaque(true);
frame.setContentPane(p);
frame.pack();
frame.setSize(210, 123);
frame.setResizable(false);
frame.setVisible(true);
}
@Override
public Dimension getPreferredSize(){
return new Dimension(210, 123);
}
public static void main(String[] args){
try {UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName());}
catch (UnsupportedLookAndFeelException e) {}
catch (ClassNotFoundException e) {}
catch (InstantiationException e) {}
catch (IllegalAccessException e) {}
if(f.exists()){
width = getWidthFromFile(filePath);
height = getHeightFromFile(filePath);
startScreenShotter();
}
if(!f.exists()){
JFrame fileMaker = new JFrame("File Maker");
fileMaker.add(new ScreenShotter(true));
}
}
public static void startScreenShotter(){
JFrame frame = new JFrame("ScreenShotter");
frame.add(new ScreenShotter());
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
frame.setOpacity(0.33f);
frame.setContentPane(contentPane);
frame.setVisible(true);
frame.addKeyListener(new KeyListener(){
public void keyPressed(KeyEvent ke) {
if(ke.getKeyCode() == ke.VK_ESCAPE){
System.exit(0);
}
}
public void keyReleased(KeyEvent ke) {}
public void keyTyped(KeyEvent ke) {}
});
while(true){
currentPoint = MouseInfo.getPointerInfo().getLocation();
if(currentPoint != startPoint && clicked){
drawRectangle(startPoint, currentPoint, picture1);
}
//System.out.println(currentPoint);
//delay(1);
}
}
public static void drawRectangle(Point start, Point current, Object source){
if(source instanceof JPanel){
picture1.repaint();
//delay(1);
Rectangle r = new Rectangle(rectChecker(start.x, start.y, current.x, current.y));
Graphics g = ((JComponent) source).getGraphics();
g.fillRect((int)r.getX(), (int)r.getY(), (int)r.getWidth(), (int)r.getHeight());
g.setColor(new Color(255, 255, 255, 50));
//delay(1);
}
}
public static void delay(int time){
try{
Thread.sleep(time);
} catch(InterruptedException e){
System.out.println("wot");
}
}
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
//drawCircle(e.getX()-(radius/2), e.getY()-(radius/2), e.getSource(), true);
//repaint();
startX = x;
startY = y;
startPoint = new Point(startX, startY);
clicked = true;
//System.out.println("(" + startX + ", " + startY + ")");
}
public void mouseReleased(MouseEvent e) {
x = e.getX();
y = e.getY();
//drawCircle(e.getX()-(radius/2), e.getY()-(radius/2), e.getSource(), true);
//repaint();
endX = x;
endY = y;
//System.out.println("(" + endX + ", " + endY + ")");
Frame[] f = Frame.getFrames();
for(int i = 0; i < f.length; i++){
f[i].dispose();
}
try {
robo(rectChecker(startX, startY, endX, endY));
System.exit(0);
} catch(Exception ex){
System.exit(1);
}
}/*
public void drawCircle(int x, int y, Object source, boolean fill) {
if(source instanceof JPanel) {
Graphics g = ((JComponent) source).getGraphics();
g.drawOval(x - radius, y - radius, 2 * radius, 2 * radius);
g.setColor(Color.RED);
if (fill) {
g.fillOval(x - radius, y - radius, 2 * radius, 2 * radius);
}
} // else ignore
}*/
public void robo(Rectangle r) throws Exception{
Calendar now = Calendar.getInstance();
Robot robot = new Robot();
BufferedImage screenshot = robot.createScreenCapture(r);
ImageIO.write(screenshot, "PNG", new File(getPath(filePath) + "Screenshot "+formatter.format(now.getTime())+".png"));
}
public static String getPath(String file){
if(f.exists()){
try(BufferedReader br = new BufferedReader(new FileReader(file))){
String sCurrentLine;
while((sCurrentLine = br.readLine()) != null){
return sCurrentLine;
}
} catch(IOException e){
e.printStackTrace();
}
return null;
}
return null;
}
public static int getWidthFromFile(String file){
if(f.exists()){
try(BufferedReader br = new BufferedReader(new FileReader(file))){
br.readLine();
int width = Integer.parseInt(br.readLine());
return width;
} catch(IOException e){
e.printStackTrace();
}
}
return 0;
}
public static int getHeightFromFile(String file){
if(f.exists()){
try(BufferedReader br = new BufferedReader(new FileReader(file))){
br.readLine();
br.readLine();
int height = Integer.parseInt(br.readLine());
return height;
} catch(IOException e){
e.printStackTrace();
}
}
return 0;
}
public static Rectangle rectChecker(int x0, int y0, int x1, int y1){
if(x0 > x1 && y0 < y1){
int x = x1;
int y = y0;
int width = x0 - x1;
int height = y1 - y0;
Rectangle r = new Rectangle(x, y, width, height);
return r;
}
if(x0 < x1 && y0 > y1){
int x = x0;
int y = y1;
int width = x1 - x0;
int height = y0 - y1;
Rectangle r = new Rectangle(x, y, width, height);
return r;
}
if(x0 > x1 && y0 > y1){
int x = x1;
int y = y1;
int width = x0 - x1;
int height = y0 - y1;
Rectangle r = new Rectangle(x, y, width, height);
return r;
}
int x = x0;
int y = y0;
int width = x1 - x0;
int height = y1 - y0;
Rectangle r = new Rectangle(x, y, width, height);
return r;
}
public static void createFile(){
System.out.println(width + " " + height + " " + filePath);
try(PrintWriter writer = new PrintWriter(filePath, "UTF-8")){
writer.println(screenshotPath);
writer.println(width);
writer.println(height);
writer.close();
} catch(IOException ioe){
System.out.println("Call a doctor!");
}
startScreenShotter();
}
public static String slashConverter(String str){
if(str.contains("\\")){
str = str.replace("\\", "/");
if(str.charAt(str.length()-1) != '/'){
str = str + "/";
}
return str;
}
return str;
}
//public void mousePressed(MouseEvent e) {}
//public void mouseReleased(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
答案 0 :(得分:2)
Swing中的绘画通常是从paintComponent
继承的JComponent
方法的上下文中完成的。这样可以确保在油漆循环发生时,涂漆的内容是双缓冲的,这样可以防止油漆过程中的闪烁。
Swing中的绘画是由RepaintManager
控制的,它决定何时和应该绘制什么是它的责任。您可以通过调用其中一种RepaintManager
方法向repaint
发出请求以执行绘画更新,并且可能会在将来的某个时间安排更新
使用...
Graphics g = ((JComponent) source).getGraphics();
这是一个非常糟糕的主意。它能够返回null
并且只是Graphics
上下文的快照,并且在正确的绘制周期发生时会擦干净。
请查看Performing custom painting和Painting in AWT and Swing了解详情
此...
while (true) {
currentPoint = MouseInfo.getPointerInfo().getLocation();
if (currentPoint != startPoint && clicked) {
drawRectangle(startPoint, currentPoint, picture1);
}
//System.out.println(currentPoint);
//delay(1);
}
让我感到害怕,原因有二,首先,它不是推荐的监控鼠标更新的方式,而是两个,在你创建UI的同一个上下文中调用它,这使它有可能“挂起”你的程序
我还建议您查看使用KeyListener
的{{3}},它将解决与焦点相关的问题......
您还可以找到key bindings API的帮助......