Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 470|回复: 0

[Swing学习]JAVA中的控件重绘

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-29 23:55:49 | 显示全部楼层 |阅读模式
    众所周知,使用 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); 恢复控件原来的绘制方式。  

      
      
       
       

         
       

         
       
      



    源码下载:http://file.javaxxz.com/2014/10/29/235548812.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-26 01:24 , Processed in 0.400095 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表