`
wubin123456
  • 浏览: 5790 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
文章分类
社区版块
存档分类
最新评论

JAVA中的控件重绘

    博客分类:
  • JAVA
 
阅读更多

众所周知,使用 JAVA 开发出来的应用程序在各种平台上有着相同的用户界面,这一切得归功于 SWING 良好的跨平台性(少数 AWT 控件在不同的平台上有着极为细小的差别)。并且, JAVA 还提供了 Look&Feel 和 Theme 让开发者对用户界面上的控件进行观感上的改变,这样可以做出更多更漂亮的用户界面。然而,当你仅仅是需要对某个控件进行特别的观感设置时,使用 L&F 或 Theme 可能过于复杂,也使得程序变得比较“庞大”,因此,我们可以通过控件重绘来完成这部分特殊的要求。

javax.swing.JComponent 是所有 SWING 控件的“祖宗”,在 JComponent 中, paintComponent(Graphics g) 方法是用来进行绘制控件的,因此,如果想要重绘 SWING 控件,只需要覆盖 paintComponent(Graphics g) 方法就可以了。如:

public class CubeMenuBar extends JMenuBar {

void paintComponent(Graphics g) {

// 这里写重绘代码

}

}

下面,我们将以例子来实现控件的重绘,最终结果如下图:

首先,我们按照上图制作一个简单的小程序,相信这个不是一件太难的事情:

//TestMenu.java

public class TestMenu extends JFrame {

JMenuBar cmbMenu = new JMenuBar();

JMenu mFile = new JMenu();

JMenu mEdit = new JMenu();

JMenu mSource = new JMenu();

JMenuItem miNew = new JMenuItem();

JMenuItem miOpen = new JMenuItem();

JMenuItem miSave = new JMenuItem();

JMenuItem miClose = new JMenuItem();

JTextArea taEditor = new JTextArea();

 

public TestMenu() {

// 创建布局

this.getContentPane().setLayout(new BorderLayout());

 

// 添加菜单

this.setJMenuBar(cmbMenu);

mFile.setText("File");

cmbMenu.add(mFile);

miNew.setText("New");

mFile.add(miNew);

miOpen.setText("Open");

mFile.add(miOpen);

miSave.setText("Save");

mFile.add(miSave);

miClose.setText("Close");

mFile.add(miClose);

 

miClose.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

dispose();

System.exit(0);

}

});

 

mEdit.setText("Edit");

cmbMenu.add(mEdit);

 

mSource.setText("Source");

cmbMenu.add(mSource);

 

// 添加编辑区域

JScrollPane sp = new JScrollPane(taEditor);

this.getContentPane().add(sp, BorderLayout.CENTER);

 

this.setTitle("Notepad - JAVA");

this.setSize(new Dimension(400, 300));

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

this.show();

}

 

public static void main(String[] args) {

//JFrame.setDefaultLookAndFeelDecorated(true);

TestMenu testmenu = new TestMenu();

}

}

( 程序运行如上图 )

为了实现特殊的菜单栏,我们需要自己重写 JMenu 类,假设我们的类叫作 CubeMenuBar ,那么,我们只需要将 TestMenu.java 中的

JMenuBar cmbMenu = new JMenuBar();

改为

CubeMenuBar cmbMenu = new CubeMenuBar();

现在,我们看一看最简单的 CubeMenuBar 应该怎么写:

// CubeMenuBar.java

public class CubeMenuBar extends JMenuBar {

protected final void paintComponent(Graphics g) {

super.paintComponent(g);

}

}

我们将 paintComponent(Graphics g) 申明为 protected final 是不愿继承的类再次改写重绘方法, super.paintComponent(g); 调用的父类的方法来进行重绘 MenuBar ,如果你写掉了这一句,呵呵,自己看看运行结果。

 

由于我们在这里只是研究如何重绘控件,因此,我提供一个现成的类,这个类负责生成带有过度色块的图像,具体不多说,只帖出代码:

// ImageCreator.java

public class ImageCreator {

// 定义颜色

public static final Color mainMidColor = new Color(0, 64, 196);

public static final Color mainUltraDarkColor = new Color(0, 0, 64);

// 定义色块数量 ( 高度 )

public static final int CUBE_DIMENSION = 5;

 

public ImageCreator() {

}

 

/**

* 产生过度色块图像

* @param width 图像的宽

* @param height 图像的高

* @param leftColor 色块左侧颜色

* @param rightColor 色块结束的颜色

* @param transitionStart 过度色块开始位置

* @param transitionEnd 过度色块结束位置

* @return 创建好的图像

*/

public static BufferedImage getGradientCubesImage(int width, int height,

Color leftColor, Color rightColor, int transitionStart,

int transitionEnd) {

BufferedImage image = new BufferedImage(width, height,

BufferedImage.TYPE_INT_ARGB);

 

Graphics2D graphics = (Graphics2D) image.getGraphics();

graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON);

 

GradientPaint gradient = new GradientPaint(transitionStart, 0,

leftColor, transitionEnd, 0, rightColor);

graphics.setPaint(gradient);

graphics.fillRect(transitionStart, 0, transitionEnd - transitionStart,

height);

 

graphics.setColor(leftColor);

graphics.fillRect(0, 0, transitionStart, height);

 

graphics.setColor(rightColor);

graphics.fillRect(transitionEnd, 0, width - transitionEnd, height);

 

int cubeCountY = height / ImageCreator.CUBE_DIMENSION;

int cubeCountX = 1 + (transitionEnd - transitionStart)

/ ImageCreator.CUBE_DIMENSION;

int cubeStartY = (height % ImageCreator.CUBE_DIMENSION) / 2;

int cubeStartX = transitionStart

- (ImageCreator.CUBE_DIMENSION - ((transitionEnd - transitionStart) % ImageCreator.CUBE_DIMENSION));

 

for (int col = 0; col < cubeCountX; col++) {

for (int row = 0; row < cubeCountY; row++) {

// 随机放置色块

if (Math.random() < 0.5) {

continue;

}

 

// 使用插值方法产生颜色,结果看起来和随机产生的差不多

double coef = 1.0 - (((double) col / (double) cubeCountX) + 0.9 * (Math

.random() - 0.5));

coef = Math.max(0.0, coef);

coef = Math.min(1.0, coef);

// 计算 RGB

int r = (int) (coef * leftColor.getRed() + (1.0 - coef)

* rightColor.getRed());

int g = (int) (coef * leftColor.getGreen() + (1.0 - coef)

* rightColor.getGreen());

int b = (int) (coef * leftColor.getBlue() + (1.0 - coef)

* rightColor.getBlue());

// 填充色块

graphics.setColor(new Color(r, g, b));

graphics.fillRect(cubeStartX + col

* ImageCreator.CUBE_DIMENSION, cubeStartY + row

* ImageCreator.CUBE_DIMENSION,

ImageCreator.CUBE_DIMENSION,

ImageCreator.CUBE_DIMENSION);

// 绘置色块边框

graphics.setColor(new Color(255 - (int) (0.95 * (255 - r)),

255 - (int) (0.9 * (255 - g)),

255 - (int) (0.9 * (255 - b))));

graphics.drawRect(cubeStartX + col

* ImageCreator.CUBE_DIMENSION, cubeStartY + row

* ImageCreator.CUBE_DIMENSION,

ImageCreator.CUBE_DIMENSION,

ImageCreator.CUBE_DIMENSION);

}

}

 

return image;

}

}

现在,我们的 CubeMenuBar.java 应该写为如下:

public class CubeMenuBar extends JMenuBar {

 

protected final void paintComponent(Graphics g) {

super.paintComponent(g);

g.drawImage(ImageCreator.getGradientCubesImage(this.getWidth(),

this.getHeight(), ImageCreator.mainMidColor,

ImageCreator.mainUltraDarkColor, (int) (0.6 * this.getWidth()),

(int) (0.9 * this.getWidth())), 0, 0, null);

}

}

只通过如此简单的几句代码,我们就可以得到了带和过度色块的菜单栏,是不是很有意思呢?

 

同样,我们在这个小程序中对 JMenu 和 JMenuItem 进行重绘,就可以得到最终的结果,然而,这个程序还有一点点小缺陷,当重绘的文字过大的时候,文字的边缘出现的锯齿,这是 Graphics 类的通病,为以,我们可以再做修改:

// CubeMenu.ajva

public class CubeMenu extends JMenu {

 

protected final void paintComponent(Graphics g) {

Graphics2D graphics = (Graphics2D) g;

Object oldHint = graphics

.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING);

graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,

RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

super.paintComponent(graphics);

graphics

.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, oldHint);

 

graphics.setColor(ImageCreator.mainMidColor);

graphics.setBackground(ImageCreator.mainMidColor);

graphics.fillRect(0, 0, this.getWidth(), this.getHeight());

 

int x = (this.getWidth() - graphics.getFontMetrics().stringWidth(

this.getText())) / 4;

int y = (int) (graphics.getFontMetrics().getLineMetrics(this.getText(),

graphics).getHeight());

 

graphics.setColor(Color.black);

graphics.drawString(this.getText(), x + 1, y + 1);

graphics.setColor(Color.white);

graphics.drawString(this.getText(), x, y);

}

}

在上述代码中,我们首先将 Graphics 对象转换为了 Graphics2D 对象,这样可以充分利用 Graphics2D 带来的更多特性。然后使用

Object oldHint = graphics.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING);

将控件原来绘制的渲染方式进行了保存,通过

graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

来为文字添加反锯齿绘制方式,最后再使用

graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, oldHint);

恢复控件原来的绘制方式。

分享到:
评论

相关推荐

    java源码包---java 源码 大量 实例

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    按钮重绘制作产生波形图的示波器

    利用了按钮重绘的原理,没有用DrawItem(),而是利用Timer,每次间隔时间段的来绘制,程序利用了缓冲绘图技术,先在内存中绘制好,然后再将这张图贴上去,避免了我们经常遇到绘图闪烁的问题,控件产生了向左移动的...

    JAVA上百实例源码以及开源项目

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    JAVA上百实例源码以及开源项目源代码

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    java源码包2

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...

    java源码包4

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...

    java源码包3

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...

    java开源包4

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包101

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包11

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包6

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包9

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Java右键弹出菜单源码 简单 Java圆形按钮实例代码,含注释 两个目标文件,自绘button。 Java圆形电子时钟源代码 1个目标文件 内容索引:JAVA源码,系统相关,电子钟 用JAVA编写的指针式圆形电子钟,效果图如下所示,...

    java开源包5

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包8

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包10

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包3

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包1

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

Global site tag (gtag.js) - Google Analytics