java中的重绘

三种重绘总结: 

Q:为什么要重绘? 
A:因为在画板上作画的时候图形是保存在缓存里面而不是保存在内存里面的。因此当我们把画板最小化的时候,缓存中储存的图形内容就会被释放清空,但是 
     内存里面并没有存储数据,所以再恢复窗体的时候只有窗体上的组件会被重绘,图形的内容已经消失。 
How to dispose it?? 
       上面说了窗体或者面板会在恢复时自动重绘窗体或者面板上已经添加的组件,这是JPanel里面有一个public void paint(Graphic g){} 
  方法,所以我们在画图的时候把图形内容(或者数据)保存以后,在JPanel调用paint方法是顺便把图形重绘出来,这就达到我们的目的。 



No、1  直接存储 
     我们在绘图的时,每画一个图,就创建一个图形对象,把绘图时的数据(坐标、颜色、绘图动作命令等)保存起来,存入一个队列中,在重绘遍历这个队列 
,把存储的图形内容输出,在绘制一遍。 
   缺点:存储的内容繁多,比如存储多边形的时候那个纠结。还有在重绘的是哦户还要把存储的瘦取出来再绘制一遍,那么原来绘制的方法得再写一遍,繁杂! 
     //**********************代码略************//     
   

No、2   存储图像像素 
   我们重绘的目的,只要求重绘的画图面板上的内容,那么我们只需把画图面板上的图像(由很多像素点组成)内容用数组存储起来,重绘时,在paint()中 
又把数组中的内容遍历出来,这样就行了。 
      优点:存储的内容单一,只是像素点对应的颜色而已,到时候把像素颜色遍历一遍放在面板上就OK了~~~ 
      //**************重绘操作****************// 
     
      //需要重写继承了JPanel类的MyPanel类的paint()方法,在MyPanel面板对象调用paint()方法时完成重绘操作 
      //写一个类继承JPanel,重写JPanel的paint方法 
class MyPanel extends JPanel{ 

// 重写绘制组件的方法 
//当然这面板主要是取得画布绘画,没有添加其他组件 
//因为JPanel里面的paint方法只会重绘组件,所以我们在“画图”的同时存储画布图像,"它"重绘组件时我们就顺便把图形再画出来 
public void paint(Graphics g) { 
// 调用父类的绘制方法来正确的绘制组件本身 
super.paint(g); 
// 当需要重新绘制的时候就将二维数组中的数据绘制一次\ 
//System.out.println("listener="+listener); 
if (listener != null) { 
// 获取监听器中的二维数组 
int[][] data = listener.data; 
//System.out.println("data="+data); 
if (data != null) {// 如果已经保存了数据,才需要绘制 
for (int i = 0; i < data.length; i++) { 
for (int j = 0; j < data[i].length; j++) { 
int cNum = data[i][j]; 
// 创建颜色对象 
Color color = new Color(cNum); 
g.setColor(color); 
// 绘制点 
g.drawLine(j, i, j, i); 







      
      //******************截屏存储操作******************// 
      
    Object object = e.getSource(); 
    JPanel drawpanel = (JPanel)(object); 
    //获取到drawpanel的左上角相对于屏幕的坐标点 
    Point point = drawpanel.getLocationOnScreen(); 
    //获取到drawpanel的面积大小 
    Dimension dimension = drawpanel.getPreferredSize(); 
    //创建一个要截取的区域,相当于是一个屏幕裁剪模具 
    Rectangle rect = new Rectangle(point,dimension); 
    //画完一个图形之后就把图像截取下来 
    BufferedImage cut_image = robot.createScreenCapture(rect); 
    
    data = new int[cut_image.getHeight()][cut_image.getWidth()]; 
    
    for (int i=0;i<data.length;i++) 
    for (int j=0;j<data[i].length;j++){ 
    int RGB = cut_image.getRGB(j, i); 
    data[i][j] = RGB;     
    } 
      
      
No、3    存储图像          
      方法2的改进:为何在去图像是不直接把图像存储起来,重绘时直接把图像“贴”在面板上上呢?

<think>我们正在讨论Java Swing中的组件问题。用户询问如何正确组件以及最佳实践。根据引用内容,我们有一些示例代码展示了Swing组件的创建和方法。 首先,在Swing中,组件通常意味着更新组件的显示外观。当组件的状态改变且需要反映在界面上时,我们需要请求。Swing是单线程的,所有UI操作都应在事件调度线程(EDT)上执行。 组件的基本步骤: 1. 修改组件的状态(例如,改变文本、颜色、位置等)。 2. 调用组件的`repaint()`方法,该方法会异步请求。它会将请求加入事件队列,由EDT在适当的时候执行`paint()`方法。 3. 如果需要立即,可以在调用`repaint()`后调用`revalidate()`(当组件大小或布局变化时),然后调用`paintImmediately()`(不常用,通常让Swing自动处理)。 注意:不要直接调用`paint()`方法,而应使用`repaint()`。 最佳实践: - 始终在EDT上修改UI组件。 - 使用`repaint()`来触发,而不是直接调用`paint()`。 - 当组件的布局发生变化(例如添加或移除子组件,改变大小)时,调用`revalidate()`(对于容器)来触发新的布局。 引用[2]和[3]中提到了时没有清除之前制的内容的问题。这通常是因为我们没有在`paintComponent`方法中先调用`super.paintComponent(g)`来清除背景。在自定义制时,我们应该这样写: ```java @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 先调用父类方法清除背景 // 然后进行自定义制 } ``` 另外,引用[4]提到了动态添加控件并刷新界面,这通常需要调用`revalidate()`和`repaint()`。 示例:自定义一个制圆的组件 ```java import javax.swing.*; import java.awt.*; public class CircleComponent extends JComponent { private Color circleColor = Color.RED; private int diameter = 50; public void setCircleColor(Color color) { circleColor = color; repaint(); // 请求 } public void setDiameter(int diameter) { this.diameter = diameter; repaint(); // 请求 } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 清除背景 g.setColor(circleColor); g.fillOval(0, 0, diameter, diameter); } } ``` 使用这个组件时,改变颜色或直径后调用`setCircleColor`或`setDiameter`就会触发。 总结: 1. 修改组件状态后,调用`repaint()`。 2. 自定义制时,在`paintComponent`中先调用`super.paintComponent(g)`。 3. 当组件结构变化(如添加/移除子组件)时,调用`revalidate()`(然后会自动触发)。 相关问题: 1. 如何在Java Swing中实现自定义制? 2. 为什么在Swing中修改UI必须在事件调度线程(EDT)上? 3. `repaint()`和`revalidate()`有什么区别?</think>### Java Swing 组件方法与最佳实践 在 Java Swing 中正确组件需要理解其 **机制** 和 **线程安全规则**。核心原则是:所有 UI 修改必须在 **事件调度线程 (EDT)** 中执行,并通过 `repaint()` 或 `revalidate()` 触发系统级请求。 #### 一、基本方法 1. **`repaint()` 方法**(最常用) - 请求异步整个组件或其指定区域 - 自动触发 `paintComponent()` 调用 ```java // 修改组件状态后调用 myComponent.setBackground(Color.BLUE); myComponent.repaint(); // 触发 ``` 2. **`revalidate()` 方法** - 当组件**布局结构变化**时使用(如添加/删除子组件) - 自动调用 `repaint()` ```java panel.remove(oldButton); panel.add(newButton); panel.revalidate(); // 更新布局+ ``` 3. **自定义制**(覆盖 `paintComponent()`) ```java class CustomPanel extends JPanel { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 必须先调用!清除背景[^3] g.setColor(Color.RED); g.drawOval(10, 10, 50, 50); // 自定义制 } } ``` #### 二、最佳实践 1. **EDT 规则** - 所有 UI 操作必须在 EDT 中执行: ```java SwingUtilities.invokeLater(() -> { component.repaint(); // 其他UI操作 }); ``` 2. **局部优化** - 指定区域提升性能: ```java // 只 (x,y,width,height) 矩形区域 component.repaint(10, 10, 100, 100); ``` 3. **双缓冲启用**(默认开启) - 减少闪烁,在组件构造器中启用: ```java setDoubleBuffered(true); // 平滑制[^2] ``` 4. **避免直接调用 `paint()`** - 始终通过 `repaint()` 间接触发,保持制流程可控 #### 三、常见问题解决 1. **残留制内容** → 检查是否遗漏 `super.paintComponent(g)`[^3] 2. **动态添加控件不显示** → 组合使用 `revalidate() + repaint()`[^4] 3. **性能瓶颈** → 使用局部 + 双缓冲 > **关键点**:Swing 采用 **被动制模型**。开发者修改状态后请求(`repaint`),系统在适当时机自动调用 `paintComponent`。直接操作 Graphics 对象会导致未定义行为[^2]。 #### 四、操作流程示例 ```java // 动态更新界面 SwingUtilities.invokeLater(() -> { customPanel.setNewData(data); // 更新数据 customPanel.repaint(); // 请求 }); // 自定义组件模板 class ValidComponent extends JComponent { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 关键! // 自定义制逻辑 } } ``` [^1]: 分割面板示例说明Swing组件结构 [^2]: 时未清除背景导致残留 [^3]: 正确覆盖paintComponent的模板 [^4]: 动态控件需revalidate刷新布局
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值