中级实训全面总结

中级实训全面总结

阶段一

本阶段除了Gridworld的开启任务之外,比较重用的是使用java实现一个带有GUI的计算器小程序,并且使用Ant、Junit、Sonarqube等进行辅助开发。

Java的GUI

Java拥有比较完善的API,实现GUI可以直接调用,十分方便。实现GUI的是Java Swing包,在代码开头添加:

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

从而导入相关的GUI类和方法。

JFrame

JFrame是一个窗口对象,简单实现后就可以直接生成一个可拉动的视窗了:

在这里插入图片描述

JFrame frame = new JFrame("window");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);

其中有两个几乎是必须运行的方法:

  1. setDefaultCloseOperation:只有设置后才能通过右上角或左上角点击关闭窗口;

在这里插入图片描述

  1. setVisible:只有设置后才能展现窗口在系统上,建议在实现GUI代码的最后设置。
JLabel

JLabel是一个标签对象,用于显示一块无法直接键盘更改的文本块。

在这里插入图片描述

在初始化的时候直接传入字符串参数作为文本:

JLabel label = new JLabel("Hello World");

或者使用setText改变显示的文本:

label.setText("Hello");

这个方法是控制改变JLabel的常用方法,基本是唯一途径。

JButton

按钮对象,实现一个简单的按钮,用于触发事件。

在这里插入图片描述

同样在初始化时传入字符串参数,作为显示的文本:

JButton plus = new JButton("+");

只是简单初始化一个按钮对象是不够的,它本身并不拥有任何功能,需要再点击后触发特定的事件需要我们自己设定:

plus.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent arg0) {
        operator.setText("+");
    }
});

实现ActionListener接口,并且重写actionPerformed方法,在方法内部编写在点击按钮后产生的事件。

JTextField

文本框对象,实现一个可以通过键盘更改的文本编辑框,当然我们也可以设置禁止键盘更改:

在这里插入图片描述

同样在初始化时传入字符串作为初始文本内容:

JTextField first = new JTextField("2");

有时我们可能会需要文本框中的字符居中或靠右显示,则需要通过特定的方法设置:

first.setHorizontalAlignment(JTextField.CENTER);

当然setHorizontalAlignment对JLabel对象同样使用,鉴于我们并不是每次都希望他们的文本都靠左。

Layout

GUI中窗口内组件的布局是一件令人头疼的事,这里我们可以使用一些常用的简单的布局对象:

frame.setLayout(new GridLayout(2, 5));

没错,在java中,布局策略本身也是一种对象。这里我们使用的是网格布局,它可以按照矩阵网格的模式依此排布组件。在设置后布局后,我们就可以添加组建了:

frame.add(first);
frame.add(operator);
frame.add(second);
frame.add(equal);

Ant

如果你知道用于构建C/C++程序的Make的话,那么可以很好的理解Ant就是Java的Make。Ant用于构建Java程序,它的主要功能是将所有程序操作自动化,包括创建文件,删除文件,进行编译,运行程序等等。只要写好一个Ant文件,那么所有事情都会有条不紊的按照你想要的顺序自动完成。

project

Ant生成文件的根元素。为了初始化整个构建程序,我们必须先定义project元素:

<project default="run" name="Helloworld">

</project>

可以看到除了元素标签之外,我们还需要定义元素的属性。在project中主要的属性有:

  1. default:默认运行的target,稍后解释
  2. name:project的名称
  3. basedir:指定基准目录,一般为.
property

有了根元素project声明整个项目,我们就可以添加property来定义属性了。可以理解它为一个变量,声明后可以被方便的使用其保存的值:

	<property name="src" value="src/"></property>
	<property name="classes" value="bin/"></property>

它的属性非常直观:

  1. name:属性名称
  2. value:保存的值

之后我们可以通过${src}的形式取得它的值,稍后会有例子。在这里,我们定义了两个用于保存.java文件目录的属性src,和编译后.class所在目录的属性classes,以便后续使用。

target

project的子元素,表示一个单独执行的任务。可以理解为java中的一个函数,ant通过执行target来完成构建任务。看到下面的例子,我们知道target主要有以下属性:

  1. name:名称,用于被调用
  2. depends:依赖,在执行此target前会先执行的target
	<target name="compile" depends="clean">
		<mkdir dir="${classes}"/>
		<javac srcdir="${src}" destdir="${classes}" excludes="TestRunner.java, TestHelloworld.java"></javac>
	</target>
Task

task是一类元素,表示用于执行一项具体任务的语句。包括, , 等等,我们通过观察标签就能直观知道他们的作用。本项目中会用到的有:

  1. mkdir:用于创建文件夹

    <mkdir dir="${classes}"/>
    

    dir为创建的目录路径,这里我们使用了一个property进行赋值

  2. javac:用于java编译

    <javac srcdir="${src}" destdir="${classes}"></javac>
    

    其中srcdir和destdir分别指定了源代码和目标目录的路径。

  3. java:运行java程序

    		<java classname="Helloworld" fork="yes">
    			<classpath path="${classes}"></classpath>
    		</java>
    

    classname指定了运行的Main class,而fork一般必须选为yes,表示会新创建一个进程运行java程序,防止当前build中断。并且还必须包括一个classpath子元素,用于指定运行的.class文件的目录。

  4. delete:删除目录

    <delete dir="${classes}"></delete>
    

Junit

Junit是用于对java程序进行单元测试的工具,它和正常的java代码一样,通过调用需要测试的函数,然后使用断言判断返回的结果是否正确,以进行测试。

格式规范

一个规范的测试函数和文件必须满足一下要求:

  1. 文件名和类名为:TestXXX.java,其中XXX为被测试的文件和类
  2. 函数名为:testXXXX,其中XXXX为被测试函数的名称
  3. 在测试函数前添加:@Test
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class TestHelloworld {
	private String obj = "world";
	private Helloworld hello = new Helloworld(obj);
	
	@Test
	public void testSayHello() {
		assertEquals("Hello, world", hello.sayHello());
	}
}
断言

我们可以看到代码中使用到了assertEquals函数,这是一个Junit提供的断言。断言判断参数是否满足条件,不满足则使测试失败,说明程序不达标。这里assertEquals表示后者sayHello函数返回值,必须与前者“Hello, world”相等,否则测试失败。常用的断言有:

//Check that two objects are equal
assertEquals(str1, str2);

//Check that a condition is true
assertTrue (val1 < val2);

//Check that a condition is false
assertFalse(val1 > val2);

等等。我们就使用这些断言,判断被测试函数的返回值是否与预期相符,以达到测试的目的。

阶段二

本阶段主要专注于Gridworld任务,并无新的技术学习,暂且略过。

阶段三

本阶段重点是学习实现了对bmp图片文件的读取工具类,并且学习了广度优先搜索和A*启发式算法。

读取bmp

由于bmp文件的复杂多样性,Java的api中被没有能很好的直接读取的方法。所以这里我们实现的方法是比较使用的。

FileInputStream

为了打开指定的bmp文件,我们需要使用此对象对特定的目录进行跟踪。此对象可以将文件构建成一个字节串管道,我们可以通过方法不断从管道中读取数据。

FileInputStream input = new FileInputStream(filePath);

在初始化时传入路径字符串参数,指定相应的文件。

当然这里我们为了方便,一次性从管道内读取了所有的字节:

byte[] bytes = input.readAllBytes();

由于bmp中不是所有字节都对读取图像信息有用,所以我们直接操作字节串而不是管道会更加合理便捷。

注意在开启使用完FileInputStream之后,需要及时关闭:

input.close();
ByteBuffer

ByteBuffer是一个封装字节数组的对象,通过此对象实现的方法,我们可以更加便捷的对字节串进行操作。

ByteBuffer buffer = ByteBuffer.wrap(bytes);

使用静态方法wrap,传入需要封装的字节串,返回封装好的对象。

createImage

为了通过像素数组创建一个Image对象,我们使用:

Toolkit.getDefaultToolkit().createImage((ImageProducer)new MemoryImageSource(width, height, pix, 0, width));

这里的createImage方法可以实现我们所需要的功能,当然中间我们需要先实现一个MemoryImageSource对象,能够将我们之间从bmp文件中读取到的包含像素数组,高宽数值的字节串信息封装。

其中前两个参数分别是宽和高,第三个参数是保存像素数值的数值,注意其中的排列顺序是有规定的,它是一个int数组,每个int代表一个像素值,其高8位需要设置为全1,也就是0xff,其余三个8位分别就是红蓝绿三个通道的数值。

写入bmp

BufferedImage

实际上Image只是一个抽象类,当我们需要创建一个实例时,必须创建其子类BufferedImage类对象:

BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);

在这里,它可以将Image的抽象类重新cast为一个可以操作的子类。

ImageIO

读写image的io对象,实现大部分格式图片的读取和写入。

ImageIO.write(bufferedImage, "bmp", file);

这里我们可以使用write方法将一个Image对象保存为一个特定的格式对象。

过滤通道

private static Image showChanel(Image sourceImage, int chanel) {
    RGBImageFilter filter = new RGBImageFilter() {
        @Override
        public int filterRGB(int x, int y, int rgb) {
            this.canFilterIndexColorModel = true;
            return (rgb & chanel);
        }
    };
    return Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(sourceImage.getSource(), filter));
}

有时候我们需要对一个图像进行特定形式的滤镜操作,这时候就需要api中的ImageFilter了。比如这里我们是对色彩通道进行过滤,使用的是:RGBImageFilter。

创建一个对象,并且重写其filterRGB方法,里面对每个像素进行数值处理,并返回最终的像素值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值