设计3D标签为什么要有一个字符间隙tracking?为什么要重写getPrefferedSize()?画三遍的顺序有讲究
java自带的Label太枯燥了,真是拿不出手啊。 所以,我们要设计3D标签!! 看看下面这张图
原理
看看这图,可以看到哈哈有三种颜色:白色、黑色和灰色 实现的时候并不像PS那样,按几个按钮就O了 其实实际是画出3个“哈哈”,一种白色,一种黑色,一种灰色 然后想象一下,如果三种颜色的”哈哈“,重叠了起来,只留下了很小的一部分,那么就形成了阴影。 既然有三种颜色的”哈哈“,那么就需要画三次。 下面开始,我们将左上角的阴影(白色的哈哈)称为左阴影,将右下角的阴影称为由右阴影 此时阴影的位置就显得格外重要了,需要自定义左右阴影的偏移量 总所周知,对于位置的表示是坐标即横纵坐标,这时就需要设置4个偏移量——左阴影x、左阴影y、右阴影x、右阴影y 然后覆盖JLabel类中的paintComponent方法,原本这个方法只是花一次,现在我们让他画3次!!
代码实现
import java.awt.*;
import javax.swing.*;
public class ThreeDLabel extends JLabel{
private int tracking;//这是字符空隙
private int left_x,left_y,right_x,right_y;//四个阴影偏移量
private Color left_color,right_color;// 左右阴影的颜色
public ThreeDLabel(String text,int tracking){//参数为文本内容和字符空隙
super(text);
this.tracking=tracking;
}
//设置左阴影
public void setLeftShadow(int left_x,int left_y,Color left_color){
this.left_x=left_x;
this.left_y=left_y;
this.left_color=left_color;
}
//设置右阴影
public void setRightShadow(int right_x,int right_y,Color right_color){
this.right_x=right_x;
this.right_y=right_y;
this.right_color=right_color;
}
//重写getPreferredSize()方法,如果在通过setSize来设置尺寸的话,可以不覆写这个方法
public Dimension getPreferredSize(){
int x,y;
FontMetrics font=this.getFontMetrics(this.getFont());
x=(getText().length()-1)*tracking+left_x+right_x+font.stringWidth(getText());//宽=字符串所有字符空隙之和+左阴影x值+右阴影x值+字符串的宽度
y=font.getHeight()+left_y+right_y;
return new Dimension(x,y);
}
//重点!!覆写paintComponent,以达到画3次就能画出阴影效果
public void paintComponent(Graphics g){
//这句感觉是可有可无的,目的是让字体圆润柔和些,就像PS的饱和效果
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
char[] chars=getText().toCharArray();
FontMetrics fm=this.getFontMetrics(getFont());
int h=fm.getAscent();
int x=0;
for(char c:chars){
int w=fm.charWidth(c)+tracking;//w=字符c的宽度+字符间隙
//画作阴影
g.setColor(left_color);
g.drawString(c+"",x-left_x,h-left_y);
//画右阴影
g.setColor(right_color);
g.drawString(c+"",x+right_x,h+right_y);
//画正文
g.setColor(getForeground());
g.drawString(c+"",x,h);
x+=w;
}
//这句话感觉也没什么用,目的是把anti-alising状态恢复到默认值
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
}
}
下面是实例代码
class Demo{
public static void main(String[] args){
DIYLabel label=new DIYLabel("小柒再出发",40);
label.setLeftShadow(2,1,Color.white);//设置左阴影属性
label.setRightShadow(4,5,Color.gray);//设置右阴影属性
label.setForeground(Color.black);//设置正文颜色
label.setFont(label.getFont().deriveFont(140f));//设置字体大小为140像素
JFrame frame=new JFrame("title");
frame.getContentPane().add(label);
frame.pack();//窗口自动调节大小
frame.setVisible(true);
}
}
结果如图
几个解释的地方
为什么要有一个字符间隙tracking?
因为:当右阴影的偏移量过大时,右阴影可能就会跑到下一个字符所在的地方,这样看起来就很难看的 上图看看有字符间隙和没有字符间隙的区别 这个图的字符间隙是0,右阴影的偏移量right_x=60,right_y=40 可以看到,前一个字的右阴影和下一个字都挤到了一起了
这张图的字符间隙为80,阴影的偏移量和上一个字一样 有了字符间隙,就可以避免前一个字的阴影和下一个字挤到了一起 所以字符间隙至少是left_x+right_x
为什么要重写getPrefferedSize()?
因为pack()这个方法,可以自动调节窗口的尺寸(前提是有布局管理器,也就是不是绝对布局) 然后pack()这个方法的原理是根据每个组件的最适尺寸来安排窗体的尺寸的,也就是每个组件的getPrefferedSize()方法 现在已经知道了getPrefferedSize()的用处了,然后我们来讲讲如果不重写getPrefferedSize()会怎么样? 原始的getPrefferedSize()方法的实现是根据Label的文本信息、图标、文本信息与图标之间的距离来安排最佳尺寸的 然而原始的文本信息是没有阴影的,所以最佳尺寸也就没有加上阴影的尺寸和字符间距 这会使得,最佳尺寸偏小,甚至右边或左边的字有一部分显示不出来(超出了组件的尺寸)
画三遍的顺序有讲究
画阴影和正文的顺序有讲究,因为画画的时候,当下一次画画的时候与上一次画画有重复的部分,那么下一次画画就会覆盖上一次的部分 所以,应该先画左右阴影(左右阴影的顺序没有讲究),最后再画正文,要确保正文不被覆盖,阴影一定要被覆盖
- 10g,11g数据泵的导入问题及解决(19天)
- ORACLE 11g导入9i dump的问题及解决
- 服务器增加内存后无法重启数据库的问题及解决 (36天)
- 分区表放入keep pool,recycle pool的问题及解析(34天)
- 临时表空间故障处理 (33天)
- 关于物化视图疑问(32天)
- ORACLE 10g 升级 11g问题汇总(31天)
- 数据库11g升级中一次奇怪的问题 (30天)
- 10g升级至11g需要考虑的参数优化(29天)
- 关于oracle invalid components问题的解决(28天)
- 11g升级性能问题之一 重建user_synonyms (笔记27天)
- 数据库shutdown之后无法启动的问题 (46天)
- 关于oracle里的process总结(45天)
- 通过top命令抓取cpu高消耗的sql (44天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 金九银十要来了?不要慌,这些Android BAT高级面试题刷一刷
- 【SpringBoot DB 系列】Jooq 初体验
- Android轻量级APM性能监测方案
- 保持 Go 模块兼容
- Go 模块:v2 及更高版本
- 发布 Go Modules
- SRA toolkit下载数据
- 【测试开发-1】基于Springboot+layui实现接口自动化平台
- 【SpringBoot-2】SLF4J+logback进行日志记录
- 【JMeter-3】JMeter参数化4种实现方式
- 【JMeter-1】JMeter安装与接口测试入门
- 【JMeter-2】JMeter接口测试之断言实现
- 【UI自动化-1】UI自动化环境搭建与简单示例
- 【UI自动化-2】UI自动化元素定位专题
- 【UI自动化-3】UI自动化元素操作专题