本文章用于记录和特定AWT学习中出现的关键和特殊的程序,用以详细记录和解答来加深记忆和掌握!
当然前面有几张也附属了特殊的文章,但是内容都偏少,在AWT和Swing的附属文章的内容会较多
右键菜单实现程序
父级菜单并且触发了监听器,该监听器为:
AcitonLister
触发监听器 该监听器为:
MouseAdapter
关闭了窗体结束运行,该监听器为:
WindowListener
AWT实现简单绘制形状
生成的位置是随机的
添加了窗体监听器
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Random;
public class SimpleDraw{
private final String RECT_SHAPE = "rect";//创建一个常量代表 矩形
private final String OVAL_SHAPE = "oval";//创建一个常量代表 圆形
private Frame f = new Frame("SimpleDraw");//创建一个窗体
private Button rect = new Button("Draw Rect");//用于指定矩形的按钮
private Button oval = new Button("Draw Oval");//用于指定圆形的按钮
private MyCanvas drawArea = new MyCanvas();//实例化自己的画布
//用于保存需要绘制什么图形的变量
//这个变量控制着重画时,会展现出什么形态
private String shape = "";//这个变量也是一个核心的标志变量 相当于之前 while循环那些实力的 flag变量 boolean falg = true;...
public void init(){
opened();
var p = new Panel();//创建一个面板
rect.addActionListener(e->{
//设置 shape 变量为RECT_SHAPE
shape = RECT_SHAPE;
//重画MyCanvas对象,即调用它的repaint()方法
drawArea.repaint();
});
oval.addActionListener(e -> {
//设置 shape 变量为OVAL_SHAPE
shape = OVAL_SHAPE;
//重画MyCanvas对象,即调用它的repaint()方法
drawArea.repaint();
});
p.add(rect);//向 p 面板添加 rect按钮 代表选择矩形
p.add(oval);//向 p 面板添加 oval按钮 代表选择圆形
drawArea.setPreferredSize(new Dimension(250,180));//设置画板大小
f.add(drawArea);//向 p 面板添加 drawArea 画板
f.add(p,BorderLayout.SOUTH);//窗体添加 p 面板
f.pack();//调整合适大小
f.setVisible(true);//显式指定窗体显示
f.addWindowListener(new WindowAdapter() {//适配器
@Override
public void windowClosing(WindowEvent e) {//点击窗体关闭按钮时
System.out.print("-----Frame Eixt-----");
System.exit(0);//结束程序
}
});
//验证此容器及其所有子组件
//这行代码可以确保程序不会出现组件显示异常或丢失的现象,也是一项确定和保证 建议写上
f.validate();//这个方法比较特殊
}
public static void main(String[] args) {
new SimpleDraw().init();//创建SimpleDraw类对象并调用 init() 方法
}
public static void opened(){
System.out.println("Frame Run");
}
class MyCanvas extends Canvas{//自己创建的画板类,关于详细看 第十一章 AWT
//重新Canvas的paint()方法 实现绘画
@Override
public void paint(Graphics g) {
var rand = new Random();//创建了一个随机数
if(shape.equals(RECT_SHAPE)){//如果我们的 shape变量和常量 RECT_SHAPE 字符序列相等
//设置画笔颜色
g.setColor(new Color(200,100,80));//关于颜色的编码我不细说,因为我也不清楚 但是IDEA会有个颜色小方块预览
//绘制一个矩形框
//这里给出的 bound有点抽象 大概意思就是边界
//API的描述是 x y width height 也就是 坐标和大小的意思 这里通过随机数生成一个区间
g.drawRect(rand.nextInt(200),rand.nextInt(120),40,60);
}
if(shape.equals(OVAL_SHAPE)){//如果我们的 shape变量和常量 OVAL_SHAPE 字符序列相等
//设置画笔颜色
g.setColor(new Color(80,100,200));
//随机地填充一个实心圆形
g.fillOval(rand.nextInt(200),rand.nextInt(120),50,40);//同上矩形绘制
}
}
}
}
本程序的思路还是非常简单的,通过变量来进行判断也可以说使用变量作为标识来进行流程控制,其实这个程序不难,很多AWT实例或Swing实例的细节功能实现大多都是使用一个普通的成员变量甚至局部变量来实现的
关于这里变量的灵活使用也可以回想一下前面的文章 使用Swing的JFrame实现简易登入中的账号密码判断逻辑就是使用了变量作为标识,所以一定要学会灵活运用变量,这也是对基础知识掌握程度的考验。
简单的弹球小游戏
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
public class PinBall{
//设置桌面的宽度
private final int TABLE_WIDTH = 300;//table桌面的宽度
//设置桌面的高度
private final int TABLE_HEIGHT = 400;//table桌面的高度
//球拍的垂直位置
private final int RACKET_Y = 340;//矩形的Y轴
//下面定义球拍的高度和宽度
private final int RACKET_HEIGHT = 20;// 矩形的高
private final int RACKET_WIDTH = 60;//矩形的宽
//小球的大小
private final int BALL_SIZE = 16;//球大小
private Frame f = new Frame("PinBallGameFrame");//弹球游戏
Random rand = new Random();//创建一个随机数对象
//小球的纵向运行速度
private int ySpeed = 10;//上下移动速度
//返回一个 -0.5~0.5的比率,用于控制小球的运行方向
public double xyRate = rand.nextDouble()-0.5;
//这里可能对 xyRate 变量的数值会产生疑惑, -0.5 ~0.5比率是什么意思?
//这里我们先看 Random类的初始值是 0-1 这里如果使用 整形 只有 0和1 如果使用Double或Float
//则会右很多小数以及出现 0.1 0.2 0.8等等
//相当于最大值 -1 必 -0.5 相当于最大值是 0.5 就会出现 0~0.5的值减去0.5 可能出现 0.5-0.5 也可能出现 0.1- 0.5
//这里自然就会出现 -0.5或0.5的可能,所有数字皆有可能都是随机的可不预测的值
//小球横向的运行速度
private int xSpeed = (int)(ySpeed*xyRate*2);
//这里先会前面两个数相乘然后再乘2 例如 10* (-0.5~0.5) * 2; 10*0.23... = 23 23*2 = 46 46的横向运行速度
//其实就是和随机速度向匹配 防止出现过快或过慢的速度 维护一个速度平衡
//ballX和ballY代表小球的坐标 X是横坐标 相当于 左和右 Y是纵坐标 相当于 上和下
private int ballX = rand.nextInt(200)+20;//这里相当于小球的初始位置
private int ballY = rand.nextInt(10)+20;
//racketX 代表球拍的水平位置
private int racketX = rand.nextInt(200);
private MyCanvas tableArea = new MyCanvas();//自己的画布类
Timer timer;//时间计数类 一定要导入包为 Swing而不是util
//游戏是否结束的旗帜
private boolean isLose = false;
public void init(){
//设置桌面区域的最佳大小
tableArea.setPreferredSize(new Dimension(TABLE_WIDTH,TABLE_HEIGHT));
f.add(tableArea);
//定义键盘监听器
var keyProcessor = new KeyAdapter(){
@Override
public void keyPressed(KeyEvent ke) {
if(ke.getKeyCode()==KeyEvent.VK_LEFT){
if(racketX>0){ //racket是球拍的水平位置 纵轴位置 如果大于 0 则向右左移动 意为只要不是窗体边缘就向左移动
racketX-=10;//千万不要 racketX = 10 两者区别很大
}
}
if(ke.getKeyCode()==KeyEvent.VK_RIGHT){
//这里的判断逻辑意义是判断球拍位置是否大于窗体最大横轴
// racketX<TABLE_WIDTH-RACKET_WIDTH(20<300-60) 不能大于窗体宽度减去矩形宽度的值 否则会移除屏幕
if(racketX<TABLE_WIDTH-RACKET_WIDTH){
racketX+=10;//千万不要 racketX = 10 两者区别很大
}
}
}
};
//为窗口和tableArea对象分别添加键盘监听器
f.addKeyListener(keyProcessor);
tableArea.addKeyListener(keyProcessor);
//定义每0.1秒执行一次的事件监听器
var taskPerformer = (ActionListener) evt ->{
//如果小球碰到左边边框
//球的 SIZE 是16
if(ballX<=0||ballX>=TABLE_WIDTH-BALL_SIZE){
xSpeed = -xSpeed;//相当于往上走
}
//如果小球高度超出了球拍位置,且横向不在球拍范围之内,游戏结束
if(ballY>=RACKET_Y-BALL_SIZE&&(ballX<racketX||ballX>racketX+RACKET_WIDTH)){
timer.stop();
//设置游戏是否结束的旗帜为true
isLose=true;
tableArea.repaint();
}
//如果小球位于球拍之内,且到达球拍位置,小球反弹
else if(ballY<=0||(ballY>=RACKET_Y-BALL_SIZE
&& ballX>racketX&&ballX<=racketX+RACKET_WIDTH
)){
ySpeed = -ySpeed;
}
//小球坐标增加
ballY += ySpeed;
ballX += xSpeed;//因为是 0.5~-0.5的区间 可能向左走右或向右走
tableArea.repaint();
};
timer = new Timer(100,taskPerformer);//每0.1秒便调用该监听器的事件处理
//如果这里调用构造器报错了那一定是你的 ,号写成了. 或者 你导的包是util而不是Swing!
timer.start();//启动
f.pack();
f.setVisible(true);
f.validate();
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args) {
new PinBall().init();
}
class MyCanvas extends Canvas{
@Override
public void paint(Graphics g) {
/*
这里的内容将是每次程序首次刷新执行的内容相当于迭代语句的判断体
*/
//如果游戏已经结束
if(isLose){//如果isLose变成了true (if语句默认布尔值true) 我们的isLose初始是 false
g.setColor(new Color(255,0,0));
g.setFont(new Font("Tmes",Font.BOLD,30));
g.drawString("Game Over",50,200);//游戏结束
}else{//游戏没有结束
//设置颜色并绘制小球
g.setColor(new Color(240,240,80));
g.fillOval(ballX,ballY,BALL_SIZE,BALL_SIZE);
//设置颜色并绘制球拍
g.setColor(new Color(80,80,200));
g.fillRect(racketX,RACKET_Y,RACKET_WIDTH,RACKET_HEIGHT);
}
}
}
}
看程序注释,这里不多解释,这里难的也是逻辑判断思路,逻辑判断思路都是慢慢学会的,没有说刚认识到就能掌握的。
实现简易手绘板
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
public class Demo{
//画图区的宽度
private final int AREA_WIDTH = 500;
//画图区的高度
private final int AREA_HEIGHT = 400;
//下面的preX、preY保存了上一次鼠标拖动事件的鼠标坐标
private int preX = -1;//约等于无值
private int preY = -1;//约等于无值
//定义一个右键菜单用于设置画笔颜色
PopupMenu pop = new PopupMenu();
MenuItem redItem = new MenuItem("Red");
MenuItem greenItem = new MenuItem("Green");
MenuItem blueItem = new MenuItem("Blue");
//定义一个BufferedImage对象
BufferedImage image = new BufferedImage(AREA_WIDTH,AREA_HEIGHT
,BufferedImage.TYPE_INT_RGB);
//获取image对象的GRAPHICS
Graphics g = image.getGraphics();
private Frame f = new Frame("SimpleSAI");
private DrawCanvas drawArea = new DrawCanvas();
//用于保存画笔的颜色
private Color foreColor = new Color(255,0,0);
public void init(){
//定义右键菜单的事件监听器
ActionListener menuListener = e->{
if(e.getActionCommand().equals("Green")){
foreColor = new Color(0,255,0);
}
if(e.getActionCommand().equals("Red")){
foreColor = new Color(255,0,0);
}
if(e.getActionCommand().equals("Blue")){
foreColor = new Color(0,0,255);
}
};
//为三个菜单添加事件监听器
redItem.addActionListener(menuListener);
greenItem.addActionListener(menuListener);
blueItem.addActionListener(menuListener);
//将菜单组合成右键菜单
pop.add(redItem);
pop.add(greenItem);
pop.add(blueItem);
//将右键菜单添加到drawArea对象中
drawArea.add(pop);
//将image对象的背景色填充成白色
g.fillRect(0,0,AREA_WIDTH,AREA_HEIGHT);
drawArea.setPreferredSize(new Dimension(AREA_WIDTH,AREA_HEIGHT));
drawArea.addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
//如果preX和preY大于0
if(preX>0&&preY>0){
//设置当前颜色
g.setColor(foreColor);
//绘制从上一次鼠标拖动事件点到本次鼠标拖动事件点的线段
g.drawLine(preX,preY,e.getX(),e.getY());
}
preX = e.getX();
preY = e.getY();
//重绘drawArea对象
drawArea.repaint();
}
});
drawArea.addMouseListener(new MouseAdapter() {
//弹出右键菜单
@Override
public void mouseReleased(MouseEvent e) {
if(e.isPopupTrigger()){
pop.show(drawArea,e.getX(),e.getY());
}
//松开鼠标是,把上一次鼠标拖动事件的X、Y坐标设为 -1
preX = -1;
preY = -1;
//约等于归零
}
});
f.add(drawArea);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args) {
new Demo().init();
}
class DrawCanvas extends Canvas{
//重写Canvas的paint方法,实现绘画
@Override
public void paint(Graphics g) {
//将image绘制到该组件上
g.drawImage(image,0,0,null);
}
}
}
此程序无特殊处,不作详细介绍。
剪贴板简单程序
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Demo{
private Frame f = new Frame("SimpleCopy");
//获取系统剪切板
private Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
//下面是创建本地剪贴板的代码
//Clipboard clipboard = new Clipboard("cb");
//用于复制文本的文本框
private TextArea jtaCopyTo = new TextArea(5,20);
//用于粘贴文本的文本框
private TextArea jtaPaste = new TextArea(5,20);
private Button btCopy = new Button("Copy");//复制按钮
private Button btPaste = new Button("Paste");//粘贴按钮
public void init(){
var p = new Panel();
p.add(btCopy);
p.add(btPaste);
btCopy.addActionListener(event ->{
//将一个多行文本域里的字符串封装成StringSelection对象
var contents = new StringSelection(jtaCopyTo.getText());
//将StringSelection对象放入剪贴板
clipboard.setContents(contents,null);
});
btPaste.addActionListener(e -> {
if(clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)){
try{
//取出剪贴板中的StringFlavor内容
var content = (String)clipboard.getData(DataFlavor.stringFlavor);
jtaPaste.append(content);
}catch (Exception et){
et.printStackTrace();
}
}
});
//创建一个水平排列的Box容器
var box = new Box(BoxLayout.X_AXIS);
//将两行多行文本域放在Box容器中
box.add(jtaCopyTo);
box.add(jtaPaste);
//将按钮所在的Panel、Box容器添加到Frame窗口中
f.add(p,BorderLayout.SOUTH);
f.add(box,BorderLayout.CENTER);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args) {
new Demo().init();
}
}
实现粘贴图像程序
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
public class CopyImage {
//系统剪贴板
private Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
//使用ArrayLsit来保存所有粘贴进来的Image——就是当成图层处理
java.util.List<Image>imageList = new ArrayList<>();
//下面代码与前面HanDraw程序中控制绘图的代码一样
//画图区的宽度
private final int AREA_WIDTH = 500;
//画图区的高度
private final int AREA_HEIGHT = 400;
//下面的preX、preY保存了上一次鼠标拖动事件的鼠标坐标
private int preX = -1;//约等于无值
private int preY = -1;//约等于无值
//定义一个右键菜单用于设置画笔颜色
PopupMenu pop = new PopupMenu();
MenuItem redItem = new MenuItem("Red");
MenuItem greenItem = new MenuItem("Green");
MenuItem blueItem = new MenuItem("Blue");
//定义一个BufferedImage对象
BufferedImage image = new BufferedImage(AREA_WIDTH,AREA_HEIGHT
, BufferedImage.TYPE_INT_RGB);
//获取image对象的GRAPHICS
Graphics g = image.getGraphics();
private Frame f = new Frame("SimpleSAI");
private DrawCanvas drawArea = new DrawCanvas();
//用于保存画笔的颜色
private Color foreColor = new Color(255,0,0);
public void init() {
//定义右键菜单的事件监听器
ActionListener menuListener = e -> {
if (e.getActionCommand().equals("Green")) {
foreColor = new Color(0, 255, 0);
}
if (e.getActionCommand().equals("Red")) {
foreColor = new Color(255, 0, 0);
}
if (e.getActionCommand().equals("Blue")) {
foreColor = new Color(0, 0, 255);
}
};
//为三个菜单添加事件监听器
redItem.addActionListener(menuListener);
greenItem.addActionListener(menuListener);
blueItem.addActionListener(menuListener);
//将菜单组合成右键菜单
pop.add(redItem);
pop.add(greenItem);
pop.add(blueItem);
//将右键菜单添加到drawArea对象中
drawArea.add(pop);
//将image对象的背景色填充成白色
g.fillRect(0, 0, AREA_WIDTH, AREA_HEIGHT);
drawArea.setPreferredSize(new Dimension(AREA_WIDTH, AREA_HEIGHT));
drawArea.addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
//如果preX和preY大于0
if (preX > 0 && preY > 0) {
//设置当前颜色
g.setColor(foreColor);
//绘制从上一次鼠标拖动事件点到本次鼠标拖动事件点的线段
g.drawLine(preX, preY, e.getX(), e.getY());
}
preX = e.getX();
preY = e.getY();
//重绘drawArea对象
drawArea.repaint();
}
});
drawArea.addMouseListener(new MouseAdapter() {
//弹出右键菜单
@Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
pop.show(drawArea, e.getX(), e.getY());
}
//松开鼠标是,把上一次鼠标拖动事件的X、Y坐标设为 -1
preX = -1;
preY = -1;
//约等于归零
}
});
f.add(drawArea);
var p =new Panel();
var copy = new Button("Copy");
var paste = new Button("Paste");
copy.addActionListener(event->{
//将image对象封装成ImageSelection对象
var contents = new ImageSelection(image);
//将ImageSelection对象放入剪贴板
clipboard.setContents(contents,null);
});
paste.addActionListener(event->{
//如果剪贴板中包含imageFlavor内容
if(clipboard.isDataFlavorAvailable(DataFlavor.imageFlavor)){
try{
//取出剪贴板中的imageFlavor内容,并将其添加到List几何中
imageList.add((Image)clipboard.getData(DataFlavor.imageFlavor));
drawArea.repaint();
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
p.add(copy);
p.add(paste);
f.add(p,BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
f.validate();
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args) {
new CopyImage().init();
}
class DrawCanvas extends Canvas{
@Override
public void paint(Graphics g) {
g.drawImage(image,0,0,null);
//将List里所有Image对象都绘制出来
for(var img:imageList){
g.drawImage(img,0,0,null);
}
}
}
}
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
public class ImageSelection implements Transferable {
private Image image;
public ImageSelection(Image image){
this.image = image;
}
//返回该Transferable对象所支持的所有DataFlavor
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{DataFlavor.imageFlavor};
}
//返回该Transferable对象是否支持指定的DataFlavor
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(DataFlavor.imageFlavor);
}
//取出该Transferable对象里实际的数组
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if(flavor.equals(DataFlavor.imageFlavor)){
return image;
}else {
throw new UnsupportedFlavorException(flavor);
}
}
}
这是封装StringSelection类也是必须有的
版权声明:本文为qq_55868059原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。