本人Java菜鸟一只,刚学不久,有写的不好的地方,大佬们轻喷
本文的主要内容为使用Java进行开发一个带有图形界面的小程序,能够对鼠标事件进行响应并绘制多边形,绘制方法类似与ArcGIS编辑功能中生成多边形。在完成绘制多边形后,可以判断鼠标在屏幕上随机点击的点是否在面内,并显示这个点,若点在面内,则以红色显示;若点在面外,则以蓝色显示。
开发环境:JDK 10
、VS code
;
GUI设计
根据题目要求,该程序需要有一个图形界面,因此需要对该界面有一个初步的设计。图形界面如图下图所示。
在该图形化界面中,总共需要5个控件,一个绘图面板,提供用户一个绘图区域;两个Label用于显示当前鼠标所在位置的坐标 ( x , y ) (x,y) (x,y);两个按钮控件,用于确定当前绘图面板的功能,是绘制多边形还是判断多边形是否在面内,其中多边形绘制按钮能够清空当前面板上的所有已有图形,“点在面内”功能选择按钮能够对绘图面板中是否存在多边形进行判断。
具体实现
主界面设计
class mainFrame extends JFrame {//主界面设计
private static final long serialVersionUID = 1L;
private JButton jb1, jb2;// 分别为多边形绘制按钮,点是否在面内判断按钮,缓冲区分析按钮
private static int counts = 0;
private JTextArea jta;// 软件说明
private JTextField jtfx, jtfy;// 用于显示鼠标所指位置的当前坐标
private JPanel jpanel;// 用来放置文本框
private JPanel jpanelworkspace;
private JPanel jbtpanel;// 用来放置按钮控件
private DrawPanel board;// 绘图区域
public mainFrame() {
this.setSize(800, 600);
this.setTitle("homework3");
InitComponent();
addComponent();
addMyAction();
this.setLayout(null);
this.setBounds((Toolkit.getDefaultToolkit().getScreenSize().width - 800) / 2,
(Toolkit.getDefaultToolkit().getScreenSize().height - 600) / 2, 800, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
private void InitComponent() {//初始化所有控件
jtfx = new JTextField(15);
jtfx.setEditable(false);
jtfx.setText("X坐标");
jtfy = new JTextField(15);
jtfy.setEditable(false);
jtfy.setText("Y坐标");
jpanel = new JPanel();
jpanel.setLayout(new FlowLayout(FlowLayout.CENTER));
jpanel.setBounds(0, 10, 800, 30);
jb1 = new JButton("多边形绘制");
jb1.setPreferredSize(new Dimension(100, 30));
jb2 = new JButton("点在面内?");
jb2.setPreferredSize(new Dimension(100, 30));
jta = new JTextArea();
jta.setBackground(new Color(238, 238, 238));
jta.setBounds(10, 70, 100, 450);
jta.setEditable(false);
jta.setLineWrap(true);
jta.setText("按下\"多边形绘制\"按钮开始绘制(重复点按可以刷新绘图面板进行多次绘制),通过多次单击绘制折线段,以双击事件结束并生成多边形。");
jpanelworkspace = new JPanel();
jpanelworkspace.setLayout(null);
jpanelworkspace.setBounds(0, 40, 800, 560);
jbtpanel = new JPanel();
jbtpanel.setBounds(10, 10, 120, 540);
board = new DrawPanel(jtfx, jtfy);
board.setLayout(null);
board.setBorder(new LineBorder(Color.black));
board.setBounds(140, 10, 630, 500);
board.setBackground(Color.WHITE);
board.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
}
private void addComponent() {//绝对布局方式添加控件到窗口
jpanel.add(jtfx);
jpanel.add(jtfy);
jbtpanel.add(jb1);
jbtpanel.add(jb2);
jbtpanel.add(jta);
jpanelworkspace.add(jbtpanel);
jpanelworkspace.add(board);
this.add(jpanel);
this.add(jpanelworkspace);
}
private void addMyAction() {//添加事件响应
DrawListen DrawListener = new DrawListen(board, jtfx, jtfy);
jb1.addActionListener(DrawListener);
jb2.addActionListener(DrawListener);
jb1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DrawListener.setButtonType(e.getActionCommand());
if(counts > 0){
DrawListener.refresh();
DrawListener.reset();
}
counts ++;
}
});
jb2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DrawListener.setButtonType(e.getActionCommand());
DrawListener.refresh();
if (DrawListener.isEmpty()) {//判断是否已经绘制了多边形
JOptionPane.showMessageDialog(null, "还未绘制多边形", "警告", JOptionPane.WARNING_MESSAGE);
}
}
});
}
}
设计继承与JPanel
类的类,作为绘图面板,并添加函数能够实时获取鼠标在该面板中的坐标。
class DrawPanel extends JPanel {// 绘图面板
private static final long serialVersionUID = 1L;
Timer timer;
public DrawPanel(JTextField jtfx, JTextField jtfy) {
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
double x = 0, y = 0;
java.awt.Point point = java.awt.MouseInfo.getPointerInfo().getLocation();
x = point.getX() - ((Toolkit.getDefaultToolkit().getScreenSize().width - 800) / 2 + 150);
y = point.getY() - ((Toolkit.getDefaultToolkit().getScreenSize().height - 800) / 2 + 184);
if (x >= 0 && y >= 0 && x <= 630 && y <= 500) {
jtfx.setText(String.valueOf(x));
jtfy.setText(String.valueOf(y));
} else {
jtfx.setText("null");
jtfy.setText("null");
}
}
}, 100, 100);
}
}
为绘图面板添加事件响应函数,同时需要判断当前按下的按钮是哪一个,并做出相应的响应。由于Java中并不提供对鼠标双击事件的响应,因此需要实现一个继承于MouseInputAdapter
类的鼠标响应类。
@Override
public void actionPerformed(ActionEvent e) {
board.addMouseListener(new MyMouseListener(){
Graphics g = board.getGraphics();
Color c = g.getColor();
@Override
public void mouseDoubleClicked(java.awt.event.MouseEvent e) {
System.out.println("DoubleClicked!");
if(ButtonType.equals("多边形绘制")){
g.drawPolygon(p);
existflag = true;
}
}
@Override
public void mouseSingleClicked(MouseEvent e){
System.out.println("Single Clicked!");
endx = e.getX();
endy = e.getY();
if(ButtonType.equals("多边形绘制")){
p.addPoint(endx, endy);
if (p.npoints == 1) {
g.setColor(Color.green);
g.fillOval(endx, endy, 2, 2);
g.setColor(c);
} else if (p.npoints > 1) {
board.getGraphics().drawLine(startx, starty, endx, endy);
g.setColor(Color.green);
g.fillOval(endx, endy, 2, 2);
g.setColor(c);
}
}else if (ButtonType.equals("点在面内?")){
if(!existflag){
JOptionPane.showMessageDialog(null, "还未生成多边形", "警告", JOptionPane.WARNING_MESSAGE);
}else{
Graphics g = board.getGraphics();
if ((((myPolygon) p).mycontains(endx, endy))) {// 使用自己的判别点在多边形内的函数
g.setColor(Color.BLUE);
g.fillOval(endx, endy, 5, 5);
} else {
g.setColor(Color.RED);
g.fillOval(endx, endy, 5, 5);
}
}
}
}
@Override
public void mouseReleased(java.awt.event.MouseEvent e) {
startx = endx;
starty = endy;
}
@Override
public void mouseExited(java.awt.event.MouseEvent e) {
}
});
}
为了实现重复绘制,需要在用户点击绘制多边形按钮时,清空面板中原有内容。
。。。一开始总是在第二次绘制多边形是会出现多个鼠标响应,并且没办法双击由折线生成多边形,通过查找原因发现需要把原本添加到绘图面板中的鼠标监听事件清除掉,才能保证出现正确的鼠标相应。
public void reset(){//重置多边形和画板
this.board.removeAll();
this.board.updateUI();
p.reset();
existflag = false;
System.out.println(p.npoints);
System.out.println(existflag);
}
public void refresh(){//移除现有鼠标监听器
MouseListener[] mlarray = board.getMouseListeners();
for(MouseListener ml : mlarray){
board.removeMouseListener(ml);
}
}
点是否在面内的判断
在java.awt.Polygon
中提供了成员函数contains()
进行判断,直接使用即可。