开发项目时,编写公共类可以减少重复代码的编写,有利于代码的重用及维护。在图片处理工坊中,有三个公共类:功能面板类、面板工厂类和图片类。其中:功能面板类用于为窗体中的其他面板提供父类模板;面板工厂类用于为主窗体注册各个功能面板并刷新这些面板;图片类是一个自定义的类,该类用于保存从本地读取的图片以及被修改过的图片,同时提供了一些常用方法。下面将详细介绍这三个类。
ImagePanel类是项目中的功能面板类,这个类是抽象的,作为程序中所有功能面板的父类。ImagePanel类中仅定义了一个抽象的flush()方法,该方法允许面板重新读取待操作的图片,从而实现如“恢复”“将修改后的图片应用到所有面板中”的功能。
ImagePanel类继承自JPanel面板类,代码如下所示:
PanelFactory类是项目中的面板工厂类。所有窗体中的功能面板都需要在这个工厂类中进行注册,而主窗体想要加载功能面板时,也必须通过工厂类提供的方法,这种低耦合的开发模式可以让程序在添加、删除功能时更加灵活。接下来,我们将分别介绍PanelFactory类中的属性和方法。
(1)PANELS属性是一个静态的键值对常量,用于存储所有已注册的面板。该键值对的泛型被定义为<功能面板对象类型, 字符串类型>,其中功能面板对象类型对应实际的功能面板对象,而字符串类型则代表每个功能面板对象所对应的唯一卡片标签。由于主窗体采用了卡片布局,因此需要为每个功能面板提供一个唯一的字符串标签。属性代码如下:
private static final Map<ImagePanel, String> PANELS = new HashMap<>();
每个功能面板的标签都被定义为静态的字符串常量,这些字符串的内容取自相应面板的类名称。属性代码如下:
public static final String GRAY_PANEL = GrayPanel.class.getName(); public static final String TURN_PANEL = TurnPanel.class.getName(); public static final String CUT_PANEL = CutPanel.class.getName(); public static final String ROTATE_PANEL = RotatePanel.class.getName(); public static final String MOSAIC_PANEL = MosaicPanel.class.getName(); public static final String STRING_WATERMARK_PANEL = StringWatermarkPanel.class.getName(); public static final String IMAGE_WATERMARK_PANEL = ImageWatermarkPanel.class.getName(); public static final String TRANSPARENT_PANEL = TransparentPanel.class.getName();
说明
在Java语言中,要声明一个常量,除了需要指定数据类型,还需要使用final关键字进行限定,以确保该常量在初始化后不可再被修改。常量名通常采用大写字母,并用下画线分隔单词。
(2)由于静态常量不可以在构造方法中进行初始化操作,因此本类使用静态代码块注册所有功能面板,代码如下:
(3)因为功能面板键值对是私有属性,所以需要提供获取键值对的静态的getter方法,方法代码如下:
(4)当用户处理完一张图片并单击“应用”按钮后,所有功能面板都应该重新加载这张修改后的图片。因此,需要提供一个让所有面板都立刻刷新的方法。allFlush()方法就用来刷新所有已注册面板的方法,该方法会遍历所有功能面板,并依次对每个功能面板执行flush()方法。该方法的代码如下:
虽然Java API中Image图片类可以保存图片对象,但图片处理程序必须具备备份图片的功能,以防止用户操作失误就会导致图片数据丢失。在项目中,MyImage图片类封装了程序导入的图片数据,并提供了一套完善的备份机制和常用功能。下面分别介绍MyImage类中的属性和方法。
(1)MyImage类包含一个图片对象属性image,这个图片对象的类型是BufferedImage缓冲图片类,BufferedImage是Image的子类,它提供了比父类更多的实用方法。image属性的代码如下:
private static BufferedImage image;
(2)在程序导入图片文件之前,用户无法访问功能面板。因此,在用户使用功能面板之前,程序需要检查是否已导入图片。isNull()方法用于判断是否存在待处理的图片。如果程序尚未导入任何图片文件,image属性将为null。isNull()方法的代码如下:
(3)由于类对象是引用类型,引用类型变量之间的赋值可能会导致一个对象的属性被另一个对象同步修改。为了确保图片处理程序能够有效地备份原始图片,程序提供了一个clone()方法,用于克隆图片对象。这样,用户的所有操作都不会影响到原始图片对象的完整性。
clone()方法的参数是被克隆的图片对象。此方法会创建一个新图片,其宽度、高度和类型都与原图片相同。然后,通过setData()方法,新图片使用原图片的数据。因此,新图片是一个独立的图片对象,其画面与原图片完全一致。
clone()方法的代码如下:
(4)为了确保程序在修改图片后能够恢复原始图片,image属性的getter方法不会直接返回image对象本身,而是返回该对象的一个克隆对象。这样,无论用户对通过getter方法获取到的图片进行何种修改,该方法都始终返回原始图片的克隆对象,从而不会影响到原始图片。getter方法的代码如下:
(5)若用户在修改图片后决定保存修改,那么程序需要将原始图片替换为修改后的图片,也就是替换image对象的值。为此,image属性提供了一个标准的setter方法。在替换原图的过程中,程序还会调用面板工厂类的allFlush()方法,以刷新所有面板,确保它们都显示用户修改后的图片。setter方法的代码如下:
(6)由于PNG格式的图片可能包含透明区域,在程序对图片进行旋转、翻转或透明化处理时,需要保留原图的透明区域。然而,BufferedImage的默认背景是黑色的,这可能会导致透明区域被错误地填充为黑色。为了避免这个问题,MyImage类提供了一个名为createTransparentImage()的方法,用于创建一个具有全透明背景的图片。该方法接收三个参数:图片的宽度、高度和图片类型。该方法利用GraphicsConfiguration设备类来创建一个全透明的图片,并返回这个新创建的图片对象。
说明
Graphics2D是推荐使用的绘图类,但是程序设计中提供的绘图对象大多是Graphics类的实例对象,这时应该使用强制类型转换将其转换为Graphics2D类型。