三分钟彻底搞懂paint,repaint,update!

news2024/11/15 17:33:12

最近总结了一下java中的paint,repaint和updata三者之间的关系,首先咱们都知道用paint方法来绘图,用repaint重绘,用update来写双缓冲。但是他们之间是怎么来调用的呢,咱们来分析一下(想直接看结果,请跳过分析过程):


1.首先咱们画在JFrame上面

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JFrame;
public class Jframe extends JFrame{
int x = 40,y=50;
Jframe(){
	this.setSize(800,700);
	this.setLocationRelativeTo(null);
	this.getContentPane().setBackground(Color.GREEN);
	this.setVisible(true);
	this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

public static void main(String[] args) {
	new Jframe();
}

public void paint(Graphics g){
	super.paint(g);//调用super.paint(g)去清除运动的痕迹
	g.setColor(Color.RED);
	g.fillOval(x, y, 20, 20);
	y++;
	repaint();//重画
	try {
		Thread.sleep(10);//在此处睡眠一会,要不运动太快
	} catch (InterruptedException e) {
	// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	}
}

运行之后的界面
在这里插入图片描述

但是你仔细观察一下,会发现有闪烁现象,怎么办呢?我第一时间想到的就是加个双缓冲。那么咱们来试一下!

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JFrame;
public class Jframe extends JFrame{
int x = 40,y=50;
Jframe(){
	this.setSize(800,700);
	this.setLocationRelativeTo(null);
	this.getContentPane().setBackground(Color.GREEN);
	this.setVisible(true);
	this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

public static void main(String[] args) {
	new Jframe();
}

Image offScreenImage = null;

public void update(Graphics g) { //双缓冲
	if(offScreenImage == null) {
		offScreenImage = this.createImage(800, 600);
	}
	Graphics gOffScreen = offScreenImage.getGraphics();
	Color c = gOffScreen.getColor();
	gOffScreen.setColor(Color.GREEN);
	gOffScreen.fillRect(0, 0, 800, 600);
	gOffScreen.setColor(c);
	paint(gOffScreen);
	g.drawImage(offScreenImage, 0, 0, null);
}

public void paint(Graphics g){
	super.paint(g);
	g.setColor(Color.RED);
	g.fillOval(x, y, 20, 20);
	y++;
	repaint();
	try {
		Thread.sleep(10);
	} catch (InterruptedException e) {
	// TODO 自动生成的 catch 块
		e.printStackTrace();
		}
	}
}

运行:仔细看一下,发现还是闪烁,这是什么鬼,难道双缓冲加错了么?咱们再用Frame试一下

import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JFrame;
public class Jframe extends Frame{
	int x = 40,y=50;
	Jframe(){
		this.setSize(800,700);
		this.setLocationRelativeTo(null);
		this.setBackground(Color.GREEN);
		this.setVisible(true);
// this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
public static void main(String[] args) {
	new Jframe();
}
Image offScreenImage = null;
public void update(Graphics g) { //双缓冲
	if(offScreenImage == null) {
		offScreenImage = this.createImage(800, 600);
	}
	Graphics gOffScreen = offScreenImage.getGraphics();
	Color c = gOffScreen.getColor();
	gOffScreen.setColor(Color.GREEN);
	gOffScreen.fillRect(0, 0, 800, 600);
	gOffScreen.setColor(c);
	paint(gOffScreen);
	g.drawImage(offScreenImage, 0, 0, null);
}

public void paint(Graphics g){
	super.paint(g);
	g.setColor(Color.RED);
	g.fillOval(x, y, 20, 20);
	y++;
	repaint();
	try {
		Thread.sleep(10);
	} catch (InterruptedException e) {
	// TODO 自动生成的 catch 块
		e.printStackTrace();
		}
	}
}

运行:发现不闪烁了,说明刚才加的双缓冲是没有问题的,然后我在JFrame的update方法里和Frame的update方法里都加个输出语句
结果发现,JFrame运行后并没有输出0,而Frame在不断输出0;
看来JFrame压根没有调用update方法!!!
然后咱们用JPanel再试一下,把小球画在JPanel上面

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Jpanel extends JPanel{
	int x=40,y=40;
	Jpanel(){
	JFrame frame = new JFrame();
	frame.setSize( 800, 600);
	frame.setLayout(null);
	this.setBounds(0, 0, 800, 700);
	frame.setLocationRelativeTo(null);
	frame.setVisible(true);
	this.setBackground(Color.GREEN);
	frame.add(this);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
	new Jpanel();
}

public void paint(Graphics g){
	super.paint(g);
	g.setColor(Color.red);
	g.fillOval(x, y, 20, 20);
	y++;
	repaint();
	try {
	Thread.sleep(10);
	} catch (InterruptedException e) {
	// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	}
}

运行后,竟然神奇的发现小球不闪烁了!!!并且没有加双缓冲!
为什么呢?


我查了API和其他资得出如下结果:
首先repaint()方法在重量级组件的时候会调用update方法,在轻量级组件的时候会调用paint方法,(重量级和轻量级的概念自查)
恰恰Frame是重量级组件,JFrame是轻量级组件,这样就能解释JFrame不运行update方法的原因了!
那JPanel为什么就不会闪烁呢?
其实是因为JPanel中的paint方法和JFrame中的paint方法不太一样
JFrame的paint方法是继承Container类中的,而JPanel的paint方法是继承JComponent类中的,看看他俩之间方法的差异:
这样就明白了吧,JFrame的paint方法与JPanel中的paint方法并不一样!JPanel的paint是按顺序画的,因为Frame已经过时了,以后咱们就可以把用paint方法把东西画在JPanel(或者JLabel)上面,这样不用加双缓冲就不闪烁!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/97211.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022卡塔尔世界杯感想

一、概述 说说我个人吧!在体育活动上面真是没什么兴趣,篮球,足球...等等竞技运动不敏感! 今年稍微关注了点世界杯比赛!什么原因呢?我有一个爱买彩票/赌球的一个同事!随着世界杯的进行&#xf…

风力发电机组机械功率Pm与转子转速Wm关系(Matlab实现)

目录 1 数学模型 2 代码 3 结果 1 数学模型 风力机空气动力学模型 风力涡轮机的动态输出机械扭矩表示为: 其中是空气密度 , A是叶片扫掠面积 , R是风力涡轮机的转子半径 (m), 是风速 (m/s)。是叶片的功率系数,它是叶片桨距…

linux内网渗透:docker逃逸

Docker逃逸 前言 Docker 逃逸在渗透测试中面向的场景大概是这样,渗透拿到shell后,发现主机是docker环境,要进一步渗透,就必须逃逸到“直接宿主机”。甚至还有物理机运行虚拟机,虚拟机运行Docker容器的情况。那就还要…

基于VUE.JS的招聘系统

开发工具(eclipse/idea/vscode等):idea 数据库(sqlite/mysql/sqlserver等):mysql 功能模块(请用文字描述,至少200字):本文是基于Vue.js对招聘系统的设计与实现,对招聘系统管理员、个人用户、企业用户三个模块功能的完善…

kubernetes学习之路--污点容忍度横向主节点

参考:K8s污点容忍度横向主节点-安全客 - 安全资讯平台 一.kube-scheduler调度 kube-scheduler是Kubernetes 集群的默认调度器,并且是集群控制面(master)的一部分。对每一个新创建的Pod或者是未被调度的Pod,kube-scheduler会选择一个最优的N…

[附源码]Nodejs计算机毕业设计基于图书管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置: Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分…

43_SDIO基础知识

目录 SDIO协议简介 SDIO设备分类 SD卡物理结构 SD卡寄存器列表 SDIO总线拓扑 SDIO总线 SDIO总线协议 SDIO命令 命令格式 命令类型 响应 SD卡的操作模式 卡识别模式 数据传输模式 STM32 SDIO功能框图 命令通道 命令状态机 数据通道 数据状态机 数据FIFO SDI…

自定义java注解案例

今天与大家分享java注解的基本使用,如有哪里有问题,望大家指教。 目录 1. 什么是java注解 2. java注解的分类 2.1 JDK基本注解 2.2 JDK元注解 3. 自定义注解 3.1 自定义注解语法 4. 注解示例 4.1 定义注解 4.2 拦截器 4.3 使用注解 4.4 测试 …

Kali Linux渗透测试演示——DNS欺骗

目录 一、DNS欺骗 1.介绍 2.原理 二、环境和工具 1.kali Linux和靶机(这里选择windows 7) 2.ettercap 三、攻击过程 1.首先确认一下Kali和靶机的IP地址以及网关 2.进入ettercap的配置文件 3.打开ettercap,进行主机发现 总结 一、DNS…

MR案例:计算学生成绩

计算学生成绩一、提出任务二、完成任务(一)准备数据1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录(二)实现步骤1、创建Maven项目2、添加相关依赖3、创建日志属性文件4、创建成绩映射器类5、创建成绩驱动器类6、启动成绩驱动…

adb常用命令(二)

adb:Android下面一个通用的调试工具管理设备或者手机模拟器的状态,进行手机操作:安装软件、卸载软件、系统升级、运行shell命令等adb命令:一、环境配置1,Java--JDK java -version2,SDK adb versionsdk版本管理(SDK与…

Spark-RDD(转换算子、行动算子、序列化、依赖关系、持久化、分区器、文件读取和保存、累加器、广播变量)

文章目录RDDRDD特点核心属性执行原理RDD创建RDD并行度与分区内存数据的分区文件数据的并行度和分区RDD转换算子Value类型mapmapPartitionsmapPartitionsWithIndexflatMapglom(获取分区数组)groupByfilterdistinctcoalesce(缩小/扩大分区)repartition(扩大分区)sortBysample双 V…

人工智能 之 机器学习(Machine Learning)

目录 一:机器学习概述 二:机器学习算法 三:机器学习模型 四:机器学习过程 五:机器学习模型验证 六:sklearn模块 一:机器学习概述 程序化处理和机器学习处理; 主观思维和客观思…

python利用read()、readline()、readlines()读取文件

目录 1.语法和用法 2.实例 1.语法和用法 with open(file,moder,encodingNone) as f:#①读取所有文本data1 f.read()#②读取第一行数据data2 f.readline() #③读取所有文本数据 data3 f.readlines() 说明: with …… as ……:用于命名&#xff0c…

2022年总结:打开新世界,踏上新征程

一、前言 于我而言,2022年是我的幸运年,人生发生转折的关键点。同时,也可能是互联网行业、社会经济状况开始扭转的一年。因此,打算在CSDN开始记录下我的第一篇年总结。当然除了是意义特殊外,也还有现实实在的意义&…

【ROS服务通信】服务端和客户端

本文记录下ROS服务通信的实现,首先明确,ROS中的服务通信主要适用于偶然的,有实时要求的场景。服务通信基于客户-服务的架构,在主节点下,由服务端和客户端组成,服务端负责对请求做出响应,客户端发…

SQL Server2019详细安装教程(含JDBC连接)

文章目录一、安装SQL Server引擎1.1、安装SQL Server1.2、SQL Server选项配置二、SQL Server Management Studio(SSMS,客户端)2.1、安装连接工具2.2、连接SQL Server三、JDBC连接SQLServer提前配置查看SQLSever的启动端口Java代码参考文章一、…

雷神五代笔记本U盘重装系统图文教程

雷神五代笔记本U盘重装系统图文教程分享。有用户使用的雷神五代笔记本开机之后会自动安装很多的软件,导致卡到无法正常使用。这个情况是电脑中了病毒程序导致的,一起来看看如何通过U盘来重新安装系统操作教程吧。 准备工作: 1、U盘一个&#…

蓝桥杯嵌入式串口uart

文章目录前言一、板子串口原理图2.cubeMx配置3.波特率的简单讲解4.代码编写一、发送数据函数二、开启接收中断函数三、中断回调函数四、具体使用总结前言 本篇文章将带大家了解串口的编程,串口在比赛当中和实际工程中都是非常重要的,串口的难度也比较大…

微信小程序自定义tabbar底部菜单

自定义 tabBar 可以让开发者更加灵活地设置 tabBar 样式,以满足更多个性化的场景。 在自定义 tabBar 模式下,为了保证低版本兼容以及区分哪些页面是 tab 页,tabBar 的相关配置项需完整声明,但这些字段不会作用于自定义 tabBar 的渲…