我有2个班级:TestingPanel
和SnipIt
。SnipIt
用于选择屏幕上的区域。TestingPanel
是主框架,包含用于运行方法Snip()并接收返回值的按钮。
如果我单独测试SnipIt类,它将起作用。但是,如果我创建一个SnipIt对象并从TestingPanel
类运行方法Snip(),它将无法正常工作。 GUI只是冻结,并且不响应鼠标单击或拖动事件。我猜有什么阻止线程处理鼠标事件,但是我不确定。
我已经被困了几个小时,但仍然不知道是什么引起了问题。请帮忙。
测试面板
package Testing;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class TestingPanel {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TestingPanel window = new TestingPanel();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public TestingPanel() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 200, 160);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JButton btnSnip = new JButton("Snip");
btnSnip.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
getSelectionSize();
}
});
btnSnip.setBounds(47, 87, 89, 23);
frame.getContentPane().add(btnSnip);
}
private void getSelectionSize() {
int[] size = new int[4];
Thread worker = new Thread(new Runnable() {
public void run() {
SnipIt sn = new SnipIt();
sn.snip();
while(!sn.complete) {
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
size[0] = sn.returnSize()[0];
size[1] = sn.returnSize()[1];
size[2] = sn.returnSize()[2];
size[3] = sn.returnSize()[3];
}
});
worker.start();
try {
worker.join();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println(size[0] + " " + size[1] + " " + size[2] + " " + size[3]);
}
}
狙击
package Testing;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Area;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class SnipIt {
private int recX = 0;
private int recY = 0;
private int recWidth = 0;
private int recHeight = 0;
public boolean complete = false;
/*
public static void main(String [] args)
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
SnipIt s = new SnipIt();
s.snip();
}
});
}
*/
public void snip() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame();
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new SnipItPane());
frame.setBounds(getVirtualBounds());
frame.setVisible(true);
}
@SuppressWarnings("serial")
public class SnipItPane extends JPanel {
private Point mouseAnchor;
private Point dragPoint;
private SelectionPane selectionPane;
private ControlPane controlPane;
public SnipItPane() {
setOpaque(false);
setLayout(null);
selectionPane = new SelectionPane();
controlPane = new ControlPane();
add(selectionPane);
add(controlPane);
MouseAdapter adapter = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
mouseAnchor = e.getPoint();
dragPoint = null;
selectionPane.setLocation(mouseAnchor);
selectionPane.setSize(0, 0);
controlPane.setLocation(mouseAnchor);
controlPane.setSize(0, 0);
}
@Override
public void mouseDragged(MouseEvent e) {
dragPoint = e.getPoint();
int width = dragPoint.x - mouseAnchor.x;
int height = dragPoint.y - mouseAnchor.y;
int x = mouseAnchor.x;
int y = mouseAnchor.y;
if (width < 0) {
x = dragPoint.x;
width *= -1;
}
if (height < 0) {
y = dragPoint.y;
height *= -1;
}
selectionPane.setBounds(x, y, width, height);
selectionPane.revalidate();
int controlY = y + height + 5;
controlPane.setBounds(x, controlY, width, 25);
controlPane.revalidate();
repaint();
}
};
addMouseListener(adapter);
addMouseMotionListener(adapter);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Rectangle bounds = new Rectangle(0, 0, getWidth(), getHeight());
Area area = new Area(bounds);
area.subtract(new Area(selectionPane.getBounds()));
g2d.setColor(new Color(102, 102, 102, 80));
g2d.fill(area);
}
}
@SuppressWarnings("serial")
public class ControlPane extends JPanel {
private JButton btnClose;
public ControlPane() {
setOpaque(false);
btnClose = new JButton("Save");
setLayout(new BorderLayout());
this.add(btnClose, BorderLayout.NORTH);
btnClose.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
complete = true;
SwingUtilities.getWindowAncestor(ControlPane.this).dispose();
}
});
}
}
@SuppressWarnings("serial")
public class SelectionPane extends JPanel {
public SelectionPane() {
setOpaque(false);
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
recX = getX();
recY = getY();
recWidth = getWidth();
recHeight = getHeight();
}
});
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
float strokeWidth = 1.0f;
float dash1[] = {10.0f};
BasicStroke dashed =
new BasicStroke(strokeWidth,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER,
10.0f, dash1, 0.0f);
g2d.setColor(Color.BLACK);
g2d.setStroke(dashed);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g2d.dispose();
}
}
public static Rectangle getVirtualBounds() {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice lstGDs[] = ge.getScreenDevices();
for (GraphicsDevice gd : lstGDs) {
bounds.add(gd.getDefaultConfiguration().getBounds());
}
return bounds;
}
public int[] returnSize() {
int[] size = new int[4];
size[0] = recX;
size[1] = recY;
size[2] = recWidth;
size[3] = recHeight;
return size;
}
}
最佳答案
您正在后台线程中运行Snipit应用程序,然后使用Thread.sleep和while true块冻结该线程,这肯定会冻结GUI。阅读Lesson: Concurrency in Swing,然后确保始终在单个Swing事件线程上运行Swing应用程序,并在后台线程中执行所有长时间运行或休眠的代码。
您问题的可能解决方案:
使Snipit窗口成为未修饰的模式对话框。这样,当对话框可见时,来自调用代码的程序流将停止,并在不再可见时恢复。
或将Snipit窗口JFrame设置为该类的实例字段,并允许外部类向其添加侦听器,以便在关闭它们时得到通知。
例如。,
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dialog.ModalityType;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Area;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class TestSnipit {
private static void createAndShowGui() {
boolean runTest = true;
if (runTest) {
TestingPanel.main(null);
} else {
SnipIt.main(null);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class TestingPanel {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TestingPanel window = new TestingPanel();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public TestingPanel() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 200, 160);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JButton btnSnip = new JButton("Snip");
btnSnip.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
getSelectionSize();
}
});
btnSnip.setBounds(47, 87, 89, 23);
frame.getContentPane().add(btnSnip);
}
private void getSelectionSize() {
int[] size = new int[4];
// !!
SnipIt sn = new SnipIt();
sn.snip(frame);
// Thread worker = new Thread(new Runnable() {
// public void run() {
// SnipIt sn = new SnipIt();
// sn.snip();
//
// while (!sn.complete) {
// try {
// Thread.sleep(800);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
//
size[0] = sn.returnSize()[0];
size[1] = sn.returnSize()[1];
size[2] = sn.returnSize()[2];
size[3] = sn.returnSize()[3];
// }
// });
//
// worker.start();
//
// try {
// worker.join();
// } catch (InterruptedException e1) {
// e1.printStackTrace();
// }
System.out.println(size[0] + " " + size[1] + " " + size[2] + " " + size[3]);
}
}
class SnipIt {
private int recX = 0;
private int recY = 0;
private int recWidth = 0;
private int recHeight = 0;
public boolean complete = false;
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
SnipIt s = new SnipIt();
s.snip(null); // !!
}
});
}
public void snip(Window owner) { // !!
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
// JFrame frame = new JFrame();
JDialog frame = new JDialog(owner, null, ModalityType.APPLICATION_MODAL); // !!
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); // !!
frame.setLayout(new BorderLayout());
frame.add(new SnipItPane());
frame.setBounds(getVirtualBounds());
frame.setVisible(true);
}
@SuppressWarnings("serial")
public class SnipItPane extends JPanel {
private Point mouseAnchor;
private Point dragPoint;
private SelectionPane selectionPane;
private ControlPane controlPane;
public SnipItPane() {
setOpaque(false);
setLayout(null);
selectionPane = new SelectionPane();
controlPane = new ControlPane();
add(selectionPane);
add(controlPane);
MouseAdapter adapter = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
mouseAnchor = e.getPoint();
dragPoint = null;
selectionPane.setLocation(mouseAnchor);
selectionPane.setSize(0, 0);
controlPane.setLocation(mouseAnchor);
controlPane.setSize(0, 0);
}
@Override
public void mouseDragged(MouseEvent e) {
dragPoint = e.getPoint();
int width = dragPoint.x - mouseAnchor.x;
int height = dragPoint.y - mouseAnchor.y;
int x = mouseAnchor.x;
int y = mouseAnchor.y;
if (width < 0) {
x = dragPoint.x;
width *= -1;
}
if (height < 0) {
y = dragPoint.y;
height *= -1;
}
selectionPane.setBounds(x, y, width, height);
selectionPane.revalidate();
int controlY = y + height + 5;
controlPane.setBounds(x, controlY, width, 25);
controlPane.revalidate();
repaint();
}
};
addMouseListener(adapter);
addMouseMotionListener(adapter);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Rectangle bounds = new Rectangle(0, 0, getWidth(), getHeight());
Area area = new Area(bounds);
area.subtract(new Area(selectionPane.getBounds()));
g2d.setColor(new Color(102, 102, 102, 80));
g2d.fill(area);
}
}
@SuppressWarnings("serial")
public class ControlPane extends JPanel {
private JButton btnClose;
public ControlPane() {
setOpaque(false);
btnClose = new JButton("Save");
setLayout(new BorderLayout());
this.add(btnClose, BorderLayout.NORTH);
btnClose.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
complete = true;
SwingUtilities.getWindowAncestor(ControlPane.this).dispose();
}
});
}
}
@SuppressWarnings("serial")
public class SelectionPane extends JPanel {
public SelectionPane() {
setOpaque(false);
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
recX = getX();
recY = getY();
recWidth = getWidth();
recHeight = getHeight();
}
});
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
float strokeWidth = 1.0f;
float dash1[] = { 10.0f };
BasicStroke dashed = new BasicStroke(strokeWidth, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
g2d.setColor(Color.BLACK);
g2d.setStroke(dashed);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g2d.dispose();
}
}
public static Rectangle getVirtualBounds() {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice lstGDs[] = ge.getScreenDevices();
for (GraphicsDevice gd : lstGDs) {
bounds.add(gd.getDefaultConfiguration().getBounds());
}
return bounds;
}
public int[] returnSize() {
int[] size = new int[4];
size[0] = recX;
size[1] = recY;
size[2] = recWidth;
size[3] = recHeight;
return size;
}
}
与您的最初问题无关的一个附带问题是您使用了空layoug。虽然null布局和
setBounds()
似乎是Swing新手喜欢的创建复杂GUI的最简单和最佳方法,但是您创建的Swing GUI越多,使用它们时就会遇到的困难就越大。当GUI调整大小时,它们不会调整您的组件大小;它们是要增强或维护的皇家女巫;放置在滚动窗格中时,它们会完全失败;在所有平台或与原始分辨率不同的屏幕分辨率下,它们看起来都令人作呕。