所谓区域就是指,用CreateRectRgn等API建立起来的东东。
现在,PictureBox中有一幅图形,假如我想把其中红色的部分转为区域,该怎么办呢?红色的区域可能非常复杂,可能内外交错,也可能有内外圈。
总之,一般来说,不能用简单的多边形去一点点勾出(至少,大部分活(“懒”)人是不会去干的:)请问该怎么做呢?

解决方案 »

  1.   

    有一种笨的办法是一个个象素扫描过去,然后将符合要求的象素不停的creatergn和combinergn
      

  2.   

    建这样的区域对象来干什么呢?
    当用于图片透[镂]空操作时,是连续区域时还还办,互不相邻的就麻烦了。ExtFloodfill可以在对某一点及其周围与之相颜色相同的连片区域涂成某种颜色。
      

  3.   

    下面是wxj_lake(蔚蓝的风)以前写过的一篇文章,对你应该有帮助:    关于用VB制作不规则窗口的文章,在各种杂志、报纸、网站上面也不知提过几回了,我都有点不好意思再谈了。但是我们编程序不仅仅要实现功能,更要寻求最佳的实现方案,本着这样的原则,让我们再来回顾一下这个老命题,也向大家介绍一下我的心得。
      Windows提供了一个API函数SetWindowRgn,凭着这个函数,我们可以把窗口设置为任意形状。问题在于,我们如何来获取所需的区域形状。一般情况下,我们可以使用CreateEllipticRgn创建椭圆区域,CreateRectRgn创建矩形区域,CreateRoundRectRgn创建圆角矩形区域。(口干,喝一口水,继续……)如果我们需要不规则的形状呢?那就可以使用CreatePolygonRgn。可是这个函数需要的参数之一是包含整个不规则区域轮廓坐标点的数组,对于一个稍微复杂一点的形状就可能需要几百个坐标点,要获取和改动这些坐标点都是相当麻烦的。
    有没有更为方便的方法呢?答案是肯定的。(不然我在这儿瞎搞什么?)
      原理是用一张图片作为窗体的背景,图片中有一种颜色是我们不需要的,称为透明色。然后编程一行行地扫描图片,将透明色的点删去,而把有用的像素点合并成一块区域,如此便得到所需的形状了。
      但是行扫描的速度奇慢,我最初实现的程序起码用了5分钟才显示出窗体。咎其原因是我们选错了兵刃。一开始我使用GetPixel来获取每一点的颜色,这样每取一个点都需要通过设备上下文hdc从图片中读取信息,这就是造成龟速的罪魁祸首了。
      正确的方法是使用GetBitmapBits函数。它可以将位图中每一点颜色信息一下子读到一个数组中,以后只要扫描这个数组就行了,这将极大的提高运行速度。Public Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
    Public Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
    Public Declare Function SetWindowRgn Lib "user32" (ByVal hwnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long
    Public Declare Function CreateRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
    Public Declare Function CombineRgn Lib "gdi32" (ByVal hDestRgn As Long, ByVal hSrcRgn1 As Long, ByVal hSrcRgn2 As Long, ByVal nCombineMode As Long) As Long
    Public Const RGN_OR = 2
    Public Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
    Public Type BITMAP
            bmType As Long
            bmWidth As Long
            bmHeight As Long
            bmWidthBytes As Long
            bmPlanes As Integer
            bmBitsPixel As Integer
            bmBits As Long
    End Type
    Dim bmByte() As BytePublic Sub SetAutoRgn(hForm As Form, Optional transColor As Byte = vbNull)
      Dim X As Long, Y As Long
      Dim Rgn1 As Long, Rgn2 As Long
      Dim SPos As Long, EPos As Long
      Dim bm As BITMAP
      Dim hbm As Long
      Dim Wid As Long, Hgt As Long
     
      '获取窗体背景图片尺寸
      hbm = hForm.Picture
      GetObjectAPI hbm, Len(bm), bm
      Wid = bm.bmWidth
      Hgt = bm.bmHeight
     
      '改变窗体尺寸以符合背景图片大小
      hForm.Height = Hgt * Screen.TwipsPerPixelY
      hForm.Width = Wid * Screen.TwipsPerPixelX
     
      ReDim bmByte(1 To Wid, 1 To Hgt)
      GetBitmapBits hbm, Wid * Hgt, bmByte(1, 1) '获取图像数组
     
    '如果没有传入transColor参数,则用第一个像素作为透明色
      If transColor = vbNull Then transColor = bmByte(1, 1)
     
      Rgn1 = CreateRectRgn(0, 0, 0, 0)
      For Y = 1 To Hgt  '逐行扫描
        X = 0
        Do
        X = X + 1
       
        While (bmByte(X, Y) = transColor) And (X < Wid)
          X = X + 1 '跳过是透明色的点
        Wend
        SPos = X
       
        While (bmByte(X, Y) <> transColor) And (X < Wid)
          X = X + 1 '跳过不是透明色的点
        Wend
        EPos = X - 1
       
        '这一段是合并区域
        If SPos <= EPos Then
            Rgn2 = CreateRectRgn(SPos - 1, Y - 1, EPos, Y)
            CombineRgn Rgn1, Rgn1, Rgn2, RGN_OR
            DeleteObject Rgn2
        End If
        Loop Until X >= Wid
      Next Y
     
      SetWindowRgn hForm.hwnd, Rgn1, True '设定窗体形状区域
      DeleteObject Rgn1
    End Sub  以上这一大段程序列出了所有必需的API函数申明。自定义过程SetAutoRgn有两个参数,hForm是将要设置形状的窗体名称,transColor是透明颜色值。关于获取窗体背景图片尺寸的代码,相信各位一看就明白,我不再罗嗦。
      我想需要解释的是像素格式的概念。大家可能已经注意到程序中二维数组bmByte()的类型是Byte,而在后面的循环体中,我每次取数组的一项就代表一个像素点,这意味着窗体的背景图片只能是8位色深256色的图片(比如GIF格式)。如果是16位色深的图片(JPG格式),那么数组的行宽得翻一倍,并且两个数组项才代表一个像素,要不你就把bmByte()的类型改为Integer。同理,24位色深的像素点要用3个Byte表示,32位的要用4个Byte或者一个Long。transColor的值在不同的像素格式下的值也是不同的。比如在8位情况下,它的取值范围为0-255,代表颜色在图片调色板中的位置。好在程序默认以图片左上角第一个像素为透明色,这样你也就不必深究transColor的具体表示方法了。更为详细的关于像素格式的资料可以在MSDN的光盘中找到,限于篇幅,这里就不展开了。
      好,理解了程序,我们可以试着来运行一下了,大家可以先看看程序运行的效果(见图二)。在我的古董MMX200上,把图一这样一张图片变成图二那样的窗体,大约耗时0.4秒左右,这么一点延迟应该是可以忍受的。如果你不放心,可以这样来调用以了解精确的运行时间。Private Sub Form_Load()
    Dim t As Single
    t = Timer
    If Me.Picture <> 0 Then Call SetAutoRgn(Me)
    MsgBox Timer - t
    End Sub
      

  4.   

    Cool!!!To xinliangyu(yxl):
    建这样的区域一个重要的目的就像上面写的,建异型窗体。
    或许有人会说可以用一个现成的API,但事实上俺的程序是For 98专用的,那我原来首先想到的也是读象素(以下为大致过程):Public Function MakeRegion(pic As PictureBox) As Long
        Dim x As Long, y As Long, StartLineX As Long
        Dim FullRegion As Long, LineRegion As Long, KeyColor As Long
        Dim InLine As Boolean, InFirstRegion As Boolean
        Dim hdc As Long, PicWidth As Long, PicHeight As Long
        hdc = pic.hdc
        PicWidth = pic.ScaleWidth
        PicHeight = pic.ScaleHeight
        InFirstRegion = True: InLine = False
        x = y = StartLineX = 0
        KeyColor = GetPixel(hdc, 0, 0)
        For y = 0 To PicHeight - 1
            For x = 0 To PicWidth - 1
                If GetPixel(hdc, x, y) = KeyColor Or x = PicWidth Then
                    If InLine Then
                        InLine = False
                        LineRegion = CreateRectRgn(StartLineX, y, x, y + 1)
                        If InFirstRegion Then
                            FullRegion = LineRegion
                            InFirstRegion = False
                        Else
                            CombineRgn FullRegion, FullRegion, LineRegion, RGN_OR
                            DeleteObject LineRegion
                        End If
                    End If
                Else
                    If Not InLine Then
                        InLine = True
                        StartLineX = x
                    End If
                End If
            Next
        Next
        MakeRegion = FullRegion
    End Function但问题也明摆着——低下的效率,呵呵现在俺再试试wxj_lake(蔚蓝的风)的办法,也希望大家看了有所启发,共同进步!诶,难得看到这么好的中文资料啦,谢谢rainstormmaster(暴风雨 v2.0) 老大一个字——顶!收藏了