zoukankan      html  css  js  c++  java
  • AS3.0 BitmapData类介绍

    注:文中的Bitmapdata和BMD均为同一意思BitmapData,BMD为其缩写
    一,概括:

    Bitmapdata继承Object对象,实现IBitmapDrawable接口,这个接口有什么用,你可以理解为Drawable,能被画。官方介绍是:IBitmapDrawable 接口由可作为 BitmapData 类draw()方法的source参数传递的对象来实现。 这些对象的类型为 BitmapData 或 DisplayObject。 其实就是能被“画”,这点我在一会的公共方法中会详细介绍。个人理解来说,BitmapData主要提供的是对图像的“像素级”的操作,如果你想切实感受一下,有个挺好的办法,打开FLASH IDE(其实就是Flash),然后CTRL+R导入一张图片,然后再按CTRL+B打散,这时得到的图片状态就有点BitmapData的味道了···而其他用FLASH矢量工具画出来的都可以理解为BitmapData的一种···

    刚刚说只是想大家对BitmapData有模糊的了解,下面再深一步说,BitmapData的名字可以拆开来看,就是Bitmap+Data,翻译成中文就是:位图数据,所以它可以看作数据储存的一种,而不是真正的显示对象,要想看到BitmapData,我们需要把Bitmapdata赋到一个Bitmap对象中,然后addChild(Bitmap),那么就能看到具体的画面了···

    那么BitmapData的像素级操作作用在哪呢?比较大家喜欢津津乐道的就是粒子效果,作为一个需要大量计算的应用来说,1像素长宽的粒子无疑是能存在的最小的粒子;另外一个是作为数据传输,大家如果想实现上传图片或者下载图片的效果,基本的理念就是将Bitmapdata使用JPEGEncoder编码成二进制数据,把二进制发送给服务器端;第三种是滤镜视觉特效,例如一些水波划动特效;第四种是视频摄像头的视频检测;当然还有很多有趣的玩法,例如通过Bitmapdata压缩数据之类的,这些可以等大家熟悉了再慢慢研究···

    二,公共属性

    BitmapData的公共属性很少,只有4种,而且都属于Read-Only(只读),只读的意思就是“只能读”(好废话),所以我们可以取出BitmapData的属性来做运算,但是却不能赋值给它们,跟只读区别的就是Read-Write(读写)。

    有时程序有莫名其妙的问题,可以查看帮助文档,是不是因为你尝试对只读属性进行了赋值导致的。

    1,height

    就是Bitmapdata存储像素数据的高度

    2,width

    同理,就是Bitmapdata存储数据的宽度,这里扯多一句,一般保存长宽的都是Number属性,因为长宽可能存在小数点,而有些其他的属性可能是int的,把带有小数点的值赋值给int的属性的话,会自动把小数点后面的数值去掉,造成一些莫名其妙的错误,所以写代码的时候要多注意看代码提示里的属性说明。

    3,transparent

    是一个Boolen值,表示此Bitmapdata是否支持透明像素,一般的颜色分为16位颜色0xRRGGBB和32位颜色0xAARRGGBB。其中0x是16进制数字的意思,后面的每两位都代表着0~F,16个范围,所以每个颜色通道都有16*16=256位的数值,其中32位颜色就是多了一个AA(透明度)通道。

    4,rect

    返回BiamapData所占的矩形对象(Rectangle),你可以暂时理解为一个对象,这个对象储存了x,y,width,height等数值。

    三,公共方法

    BitmapData一共有32个公共方法,当然一部分是成对出现的get/set方法,让我们来一一介绍。

    1,构造方法

    BitmapData(int, height:int, transparent:Boolean = true, fillColor:uint = 0xFFFFFFFF)

    构造方法有4个参数,其中两个必填,就是长宽,这两个值的输入保持“用多少填多少”的原则,因为Bitmapdata也是一种形式的内存开销,所以能省就省。第三个是transparent,就是是否允许透明像素,原则同上,如果能确定不用的话,最好关掉,默认为允许,第四个为填充颜色,bitmapdata既然是data,那肯定要有初始数据的存在,一开始是一些纯色的填充,默认为白色。

    2,应用滤镜

    applyFilter(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, filter:BitmapFilter):void

    这个函数很有意思,在我的印象里,bitmapdata.applyFilter就是直接对bitmapdata进行一次滤镜算法,然后把其中的像素进行从新赋值,那为什么会有这么四个参数呢。

    我印象中的处理过程是:BMD--->滤镜算法--->得到的新BMD

    而实际上确是:

    Step1:

    sourceBitmapData--->(sourceRect滤镜的作用矩形区域)--->filter(滤镜)--->新的BMD(长宽为作用矩形区域sourceRect的长宽)

    Step2:

    原来的BitmapData--->在destPoint的x,y位置上--->画上新的BMD

    这样一来,除了可以实现对自己实施滤镜,还有了更多的可操作性。

     

    3,复制

     

    clone():BitmapData

     

    返回一个新的 BitmapData 对象,它是对原始实例的克隆,包含与原始实例所含位图完全相同的副本。

    4,变色

    colorTransform(rect:Rectangle, colorTransform:ColorTransform):void

    对位图数据进行颜色变化

     

    5,与其他BitmapData进行像素值的"比较",其实就是求差异(或者叫各像素相减得的差)

     

    compare(otherBitmapData:BitmapData):Object

     

    首先这两个BMD的比较分为几种情况:

     

    (1)如果宽度不相同,函数返回-3。

     

    (2)如果高度不相同,函数返回-4;

     

    (3)如果宽高都不相同,先算宽,即函数返回-3;

     

    (4)如果两个BMD完全相同,函数返回0;

     

    (5)如果两个BMD长宽相同,颜色不同,则返回一个新的Bitmapdata对象,新BMD对象特征如下:

     

    bmd1.compare(bmd2);

     

    新BMD的每一点像素值为bmd1减bmd2所得,由于有Alpha存在,当RRGGBB不相同时,忽略Alpha的比较,新值为0xFF(RRGGBB差);当RRGGBB相同时,则返回Alpha的差,新值则为0xZZ(Alpha差)XXXXX(RGB值)。

     

    总的来说就是先比较颜色,颜色不同的情况下就不考虑透明度。颜色相同就看透明度的差异。不修改原对象,只返回一个新的BitmapData对象。

     

    6,复制通道

     

    copyChannel(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, sourceChannel:uint, destChannel:uint):void

     

    这个就是对某一区域内所有像素的颜色通道的替换。sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point这三个参数分别对应作用BMD,作用区域,和生成图在原BMD的位置。sourceChannel:uint, destChannel:uint这两个参数就是分别对应用哪个通道的值,去替换哪个通道。具体的通道保存在BitmapDataChannel类中。

     

    注意,这类替换过程并不影响sourceBitmapData的像素信息,他只是将计算的结果重新赋值到原BMD的对应位置上。

     

    7,复制像素

     

    copyPixels(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, alphaBitmapData:BitmapData = null, alphaPoint:Point = null, mergeAlpha:Boolean = false):void

     

    为没有拉伸、旋转或色彩效果的图像之间的像素处理提供一个快速例程。 此方法在目标 BitmapData 对象的目标点将源图像的矩形区域复制为同样大小的矩形区域。

     

    如果包括 alphaBitmap 参数和 alphaPoint 参数,则可以将另一个图像用作源图像的 Alpha 源。 如果源图像具有 Alpha 数据,则这两组 Alpha 数据都用于将源图像中的像素组合到目标图像中。 alphaPoint 参数是 Alpha 图像中与源矩形左上角对应的点。 源图像和 Alpha 图像交叉区域之外的任何像素都不会被复制到目标图像。

     

    mergeAlpha 属性控制在将透明图像复制到另一透明图像时是否使用 Alpha 通道。 若要复制含有 Alpha 通道数据的像素,请将 mergeAlpha 属性设置为 true。 默认情况下,mergeAlpha 属性为 false。

     


    参数  sourceBitmapData:BitmapData — 要从中复制像素的输入位图图像。 源图像可以是另一个 BitmapData 实例,也可以指当前 BitmapData 实例。 
     
     sourceRect:Rectangle — 定义要用作输入的源图像区域的矩形。 
     
     destPoint:Point — 目标点,它表示将在其中放置新像素的矩形区域的左上角。 
     
     alphaBitmapData:BitmapData (default = null) — 第二个 Alpha BitmapData 对象源。 
     
     alphaPoint:Point (default = null) — Alpha BitmapData 对象源中与 sourceRect 参数的左上角对应的点。 
     
     mergeAlpha:Boolean (default = false) — 若要使用 Alpha 通道,请将该值设置为 true。 若要复制不含 Alpha 通道的像素,请将该值设置为 false。

    8,释放内存

    dispose():void

    这个主要作用是释放掉分配给BitmapData的内存,并将宽高设置为0,此后的所有对BitmapData的操作都将不生效。

     

    9,draw方法,显示对象BitmapData化

     

    draw(source:IBitmapDrawable, matrix:Matrix = null, colorTransform:ColorTransform = null, blendMode:String = null, clipRect:Rectangle = null, smoothing:Boolean = false):void

     

    这里的六个参数,除了第一个是必选外,其余的都是可选:

     

    source:要被“画”的对象。

     

    matrix:一个变型矩阵,作用于BitmapData。

     

    colorTransform:一个颜色变换,作用于BitmapData。

     

    blendMode:图层叠加模式。具体的模式可以在BlendMode 类中找到。将BitmapData与source进行图层叠加。

     

    clipRect:定义了draw source的区域。

     

    smoothing:定义是否进行图像平滑。只对source是BitmapData时起作用。

     

    这个绝对是BitmapData的重头戏,非常常用的方法。画一切可以“画”的对象,就是文章开头提到的实现了IBitmapDrawable接口的对象都可被“画”。BitmapData和DisplayObject都实现了这个接口。

     

    这样做的好处是可以在显示对象不需要被使用的时候Draw一个假的放在舞台上,或者有很多元件在舞台上运动的时候,统一把结果Draw在一张BitmapData上,节省CPU的开销,实现用内存换取CPU性能。

     

    注意,如果跨域没有安全文件的话,draw方法是无法draw到内容的,不过这种情况在一般的内容里不会出现。

    10,填充矩形

    fillRect(rect:Rectangle, color:uint):void

    这个应该很好理解,就是输入一个矩形对象,然后用对应的颜色填充这块矩形对象的区域就OK了。

    11,颜料桶填充

    floodFill(x:int, y:int, color:uint):void

    这个也是另外的一种填充,模拟的是我们平常在IDE里进行的颜料桶填充方式(选中颜色,选中填充的点,就会将所有附近相同颜色的像素一起填充)。对应的x,y就是点的坐标,color自然就是颜色啦。

    12,计算滤镜作用区域

    generateFilterRect(sourceRect:Rectangle, filter:BitmapFilter):Rectangle

    因为滤镜的作用区域不一定总等于输入的作用区域,所以这个函数是用来计算滤镜的实际作用区域的,输入的是一个矩形区域sourceRect和需要作用的滤镜filter,返回的是实际滤镜会影响到的矩形。

    13,获取颜色区域

    getColorBoundsRect(mask:uint, color:uint, findColor:Boolean = true):Rectangle

    这个在做摄像头应用的常用来检测颜色的区域。返回的是由所有符合条件的像素组成的最大矩形。

    color:就是要查找的颜色

    findColor:为true时,是查找与color相同的颜色;为false则是查找与color不相同的颜色。

    mask:是一个与输入color的掩码操作,作用是例如我只想进行某个通道的颜色比对时,可以不必管其他通道的的具体值。具体的运算方法是&(按位 AND),即逻辑与或非中的“与”操作,具体的结果是1&1=1,1&0=0&1=0&0=0,是二进制下的运算。

    至于怎么比对?其实0xF = 二进制下的1111,类似的转化而已。

    14,取得某点颜色(16位版)

    getPixel(x:int, y:int):uint

    很简单,就是取得x,y点的颜色(不包含Alpha通道)。

    15,取得某点颜色,(32位版)

    getPixel32(x:int, y:int):uint

    同上,不过这次包含了Alpha通道

    16,取得区域的像素二进制信息

    getPixels(rect:Rectangle):ByteArray

    这个函数是将一片区域rect内的所有图形信息,打包成一个二进制数组类ByteArray,作用是可以在头像上传时上传用户选择的部分。

     

    17,获取区域内的像素矢量数组Vector

     

    getVector(rect:Rectangle):Vector.<uint>

     

    Vector这种数据结构是FP10以后新加的,那么这个方法对应的也只能在FP10或以上版本里使用。学过Java的同学可能很熟悉,其实Vector是一种固定数据类型的数组。即这个数组里的所有内容都必须是某种数据类型的。这样做的好处是因为事先规定好了数组的类型,那么在使用时不用花时间去判断弱类型,大大提高了运行效率,其他的使用方法大概跟Array一样。

     

    那么这个函数其实没有太多的难点,就是返回一个Vector,里面包含的都是每一个像素的颜色信息而已。

     

    18,获取区域内通道信息矢量数组Vector

     

    histogram(hRect:Rectangle = null):Vector.<Vector>

     

    这个也是FP10的新API,具体作用跟getVector很像,只是将getVector的结果继续拆分了而已。

     

    返回的Vector里面有4个Vector,4个Vector里面装的是4个通道(Alpha,Red Green,Blue)的值0~255。再巩固一下Vector是有类型的数组,所以返回的是Vector.<Vector>,而4个Vector则是Vector.<Number>。

    19,不规则碰撞检测(高级碰撞检测)

    hitTest(firstPoint:Point, firstAlphaThreshold:uint, secondObject:Object, secondBitmapDataPoint:Point = null, secondAlphaThreshold:uint = 1):Boolean

     

    注意到这5个参数被分成了两组:一个和另一个。每组都需要一个点来确定位图的左上角起点。

     

    接着每组都还有一个透明阈值。之前提到过,支持透明的位图对象,每个像素的透明度取值范围在0(完全透明)到255(完全不透明)。参数透明阈值即指定, 透明度在多少的时候就算碰撞。

     

    最后还剩一个参数,另一个对象。注意它的类型是Object。允许传递的可以是一个点(Point),一个矩形(Rectangle)或者另一个位图对象 (BitmapData)。如果传一个点或者一个矩形,那么后面的两个参数可以忽略。

     

    到此,测试都是围绕着Bitmap对象。而大多情况下的MovieClip,Sprite和Shape对象是没法用hitTest的。有个办法就是暗中准备一些BitmapData,不把它们加入到显示列表。当要对两个显示对象进行碰撞检测时,先把它们分别绘制到一个准备好的位图对象中,然后如法炮制。要知道,这不是唯一的办法,却是个不错的办法。

     

    20,锁定变化

     

    lock():void

     

    因为对像素的操作涉及很多中间步骤,如果每操作一次都更新一次,那么如此大的计算量会把CPU拖垮的,这个函数的作用就是把BMD锁住,只保存更新步骤,而不更新实际像素。在做粒子效果时如果没有这一步绝对卡死人。

     

    21,图像合并

     

    merge(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, redMultiplier:uint, greenMultiplier:uint, blueMultiplier:uint, alphaMultiplier:uint):void

     

    头三个参数又是老三样,不多说。

     

    后面的4个参数分别是AARRGGBB通道Multiplier

     

    计算方法为新值=Source通道*Multiplier;

     

    22,生成噪点

     

    noise(randomSeed:int, low:uint = 0, high:uint = 255, channelOptions:uint = 7, grayScale:Boolean = false):void

     

    生成一堆杂乱无章的图像填充BMD,意义何在??一般是做贴图的MAP映射吧···创造出凹凸不平的效果,一般很少人会直接用吧···

     

    randomSeed:随机的一个种子,就是从这个数字生成一大堆噪点图

     

    low,high各通道在0~255区间取的最低和最高值

     

    channelOptions:uint (default =7) — 一个数字,可以是四个颜色通道值的任意组合。 您可以使用逻辑 OR 运算符(|)来组合通道值。 (谁看的懂谁告诉我···我是不知道他想怎样了)

     

    grayScale:这个如果设为true,则生成像素的RGB值将相等,即生成“灰度图”。如果是false则是为有色彩的。

     

    23,调色板

     

    paletteMap(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, redArray:Array = null, greenArray:Array = null, blueArray:Array = null, alphaArray:Array = null):void

    这个API在摄像头检测中有很重要的应用,

    paletteMap函数的作用就是重新映射各个通道的范围,例如你可以把Red通道的颜色区间从原来的256种红映射成16种红,大大提高了你的检测成功率。

     

    头三个参数还是老三样(我发现这句都成我口头禅了,哈)。不多说。

     

    后面4个参数其实是一类的,四个通道AARRGGBB。

     

    那么我们应该输入什么进这些数组呢·?答案是256长度的内容,对应各个通道的256个值,但是这个值是我们来定义的。

     

    这里注意的是,由于最后的颜色是四个通道相加出来的,所以redArray的值应该是0x00000000~0x00FF0000,要将具体的值移位到正确的位置上。这里介绍两个大家平常很少用的二进制位操作符<<和>>,作用就是将二进制数全部向左或者向右移一位。

     

    只要按你想要的把4个数组的映射保存好,作为参数传入就可以了。

    24,柏林噪声函数

     

    perlinNoise(baseX:Number, baseY:Number, numOctaves:uint, randomSeed:int, stitch:Boolean, fractalNoise:Boolean, channelOptions:uint = 7, grayScale:Boolean = false, offsets:Array = null):void

     

    上网查了一下··这个柏林噪声函数好像是蛮出名的一个函数···同样是产生噪点,从视觉效果来说,柏林函数的效果更漂亮,蒙胧很多(很像PS里的云彩滤镜),而noise的话就很想电视机的杂点。

     

    说说这里的九个参数:

     

    baseX,baseY:帮助里说的是X和Y轴上的频率,可以理解为噪声的区域的长和宽···注意,这里的长和宽不是总的长宽,总的长宽由bitmapdata的长宽决定,这里说的噪声区域的长宽说的是单个噪声区域的长宽,总的图像由很多个这样的噪声区域组成

     

    numOctaves:uint — 要组合以创建此杂点的 octave 函数或各个杂点函数的数目。 octave 的数目越多,创建的图像越细腻。 octave 的数目越多,需要的处理时间也会越长。 (专业术语我也看不太懂··好像是用来控制生成杂点函数octave的数量的 )

     

    randomSeed:随机种子,通过这个生成不同的分布

     

    stitch:中文意思是缝合,当设为true时将对不同的噪声区域进行无缝拼合。但是老实说,我设了一下false,也没看出什么区别嘛………

     

    fractalNoise:另外一个参数,这个蛮明显的,设为true时图像将显得有种烟雾的效果,渐变比较连续。而为false时,则显得有些锐利,帮助说可以用来制作火焰和海浪效果··这个,怎么做呢???

     

    channelOptions:跟之前的noise一样,都是把几个通道的数值进行与或非之类的操作吧···

     

    grayScale:与之前的noise一样,设为true将生成灰度图。

     

    offsets:一个数组,长度对应之前设置的numOctaves,定义了每个点的x,y偏移量。

     

    25,像素溶解(听名字不懂,看解释吧)

     

    pixelDissolve(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, randomSeed:int = 0, numPixels:int = 0, fillColor:uint = 0):int

     

    这个函数很迷糊,但是很有意思。如果你打开帮助看看他的例子就会发现了。动画效果还是蛮Cool的(其实Cool在哪??汗··可能只有我们程序员觉得Cool吧··)

     

    总的来说就是每次随机取几个点,然后填充过去,然后再取几个点,继续填充,一直到完全填充完成为止。因此需要不停的调用。

     

    解释解释参数和返回值,还有两种情况的运作方式。

     

    6个参数,头3个还是老三样(又来了,汗),那我们从第四个开始说起吧

     

    randomSeed:产生随机数的随机种子

     

    numPixels:每次变化的像素数目

     

    fillColor:要填充的颜色

     

    返回的是后续调用需要用的新的随机种子,这个可用可不用了

     

    这个函数分两种情况,当sourceBitmapData就是原BMD时,用fillColor定义的颜色进行填充,不考虑destPoint的偏移。当sourceBitmapData不是原BMD时,用sourceBitmapData对原BMD进行填充。

     

    26,滚动Bitmapdata

     

    scroll(x:int, y:int):void

     

    对BMD水平和垂直移动,这个很好理解。

     

    注意!!滚动的只是原来定义的Bitmapdata,对于由于X,Y移出区域的Bitmapdata的位置,将按边缘像素进行填充。但是新填充的区域,不会参与同一次的X,Y滚动。

     

    即scroll(40,40)和scroll(40,0);scroll(0,40)得到的结果不同。

     

    27,设置某点颜色(16位)

     

    setPixel(x:int, y:int, color:uint):void

     

    像素级的操作来了(其实之前也有的··),这个函数可以单独设置BMD某个点的颜色,三个参数分别是x,y,颜色。对应位置和颜色,很好理解吧,不多说了。

     

    28,设置某点颜色(32位)

     

    setPixel32(x:int, y:int, color:uint):void

     

    跟上面的setPixel非常类似,只是设置的颜色是32位(包含Alpha通道)而已。

     

    29,二进制数组(ByteArray)填充

     

    setPixels(rect:Rectangle, inputByteArray:ByteArray):void

     

    这个函数跟setPixel的区别在于多了一个“s”,这个s嘛,在英语里就是复数的意思,所以此函数的作用是同时设置多个像素。其中一个作用可以是在接收到服务器传来的图像的二进制数据并将其转化为BitmapData数据。当然这个目前就无法做DEMO了,但是我们可以用自带的API自娱自乐一把。还记得set的好兄弟get吗?我们之前就介绍过setPixels函数,这两个可以配套使用。

     

    输入的参数:

     

    rect:输入数据填充的区域。至于是从左到右还是从右到左还是从上往下还是从下往上,我也不太清楚。其实我还是清楚一点的,应该是从左往右,从上往下填(做了实验的),如果有错请高手指出。注:如果二进制数值不足以填充矩型区域,会引发错误。所以记得用try,catch包好。

     

    inputByteArray:输入的二进制数组。

    30,Vector数组填充

     

    setVector(rect:Rectangle, inputVector:Vector.<uint>):void

     

    跟ByteArray填充差不多,不过这次用的是Vector数组。测试也可以用set的好搭档:getVector。

     

    注:Vector是FP10的新数据结构,使用要用FlashPlayer10或以上版本。

     


    31,颜色阈值函数(比较函数)

     

    threshold(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, operation:String, threshold:uint, color:uint = 0, mask:uint = 0xFFFFFFFF, copySource:Boolean = false):uint

     

    这个也是个功能很强大的函数,在摄像头应用中会用到,用来简化颜色。

     

    作用概括来说,就是设定比较的条件,对符合条件的像素颜色,统统设置为一个新的值。

     

    有8个参数,头3个老三样(我又来了),让我们来说后五个:

     

    operation:比较条件,“<”、“<=”、“>”、“>=”、“==”“!=”

     

    threshold:这个单词大家不是很熟,是阙值,就是我们要用来进行比较的颜色值。

     

    color:比较结果为true之后,像素颜色设置的新值。

     

    mask:掩码。可以把你不想比较的通道屏蔽掉。

     

    copySource:当sourceBitmapData不等于原BMD的时候有用。设置为true时,当比较失败时仍将sourceBitmapData的数据Copy过去原BMD。而false时就不Copy。

     

    返回值是已改变像素的数目,也可以用来做判断结果,有多少像素达到了某某要求。

     


    32,解锁

     

    unlock(changeRect:Rectangle = null):void

     

    配合之前的lock()来用,目的是为了在多次操作过程中停止更新,节省CPU效率。附带了一个参数changeRect,是可以设定解锁的区域,可以只将变化了的区域解锁,这样就不用更新整张BMD,进一步节省了CPU。

     

    总结: 如果你看完后还有不明白的,那就在看一遍,如果你对某个方法不够理解或想看看用此方法的例子你可以直接看帮助文档。

  • 相关阅读:
    【网络流24题】魔术球问题(最小不相交路径覆盖)
    【网络流24题】搭配飞行员(太空飞行计划问题)(最大闭合图)
    【网络流24题】搭配飞行员(飞行员配对方案问题)(网络流)
    bzoj 1664 (贪心)
    关于正方形类问题
    就代码格式化问题
    提高组2017游记
    线程同步
    线程的优先级
    线程的常用方法
  • 原文地址:https://www.cnblogs.com/atong/p/2878640.html
Copyright © 2011-2022 走看看