画流动虚线框(java)

本文介绍了如何在Java中实现类似Photoshop中的流动虚线框效果。首先讲解了虚线的构成,然后通过自定义画线方法来画虚线,接着分析了流动原理,最后展示了动态画虚线的实现代码,包括处理实线和虚线段的绘制以及流动过程的控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前两天写了个作业:在面板(Panel)上显示一张图片,并能够用鼠标随意拖动,将图片放置于任何位置。
 见:http://blog.youkuaiyun.com/caoxiongjun/archive/2006/09/19/1246533.aspx
    在完成那个作业后,我又想,在我双击图片后,能不能像photoshop那样,在“全选”之后,图片周围出现流动的虚线框的效果,想到就去做,于是我又研究了起来,那么,现在跟着我来看看,我是怎么实现的吧!(程序可能存在些不足,还请高手们指正).

第一步:认识虚线
        请看下图,虚线其实是由一条条不连续的"实线段"组成的,这里实线段是白色的部分,背景色是黑色,我们暂且称实线段之间间隔的空余部分为“虚线段”. 

第二步:画虚线
   java的Graphics提供了画直线的方法:drawLine(int x1,int x2,int y1,int y2),
其功能是画一条从点 (x1,y1)到 点 (x2,y2)的一条直线。
   假如,我们想画一条从点 (x1,y1) 到 点 (x2,y2)的虚线,那我们该怎么做呢?是直接调用Graphics的drawLine()方法吗?显然不是,drawLine()画的是实线。那Graphics有提供实现画虚线效果的方法吗?没有,我没在java的document中找到有这种功能的方法。那现在,我们只能自己动手了(利用drawLine()方法)。

 参看上图,假设,我们要画的虚线的 实现段 和 虚线段,其长度都为4个像素,那么其虚线就是:
         4个像素的线段----4个像素的空余----4个像素的线段----4个像素的空余--.......
用程序实现的过程就是:
 画4个像素的线段----跳过4个像素----画4个像素的线段----跳过4个像素----......直到达到了所要的虚线长度.代码如下:(只适用于水平线和垂直线)

 

     public   void  drawDashed(Graphics g,  int  x1,  int  y1,  int  x2,  int  y2)
    
{
        
int x = x1,y=y1;
        
int n = 4;  //实线段长度
        int m = 4;  //虚线段长度
        
        
int tx = 0,ty = 0;
        
        
int c = 0;
        
boolean flag = true;  //标记 有没有画完(达到要求的长度)
        
        
int mark_x = 0;  //标记 要画的是 水平线(值为1)
        int mark_y = 0;  //标记 要画的是 垂直线(值为1)
        
//要么0,要么 1
        if(x2-x1 != 0)
            mark_x 
= 1;
        
else
            mark_y 
= 1;
        
        
do
        
{
            tx 
= (int)((c*(n+m) - m)*mark_x + x1 );    
            ty 
= (int)((c*(n+m) - m)*mark_y + y1 );   

            
if(Math.abs(tx-x1) > Math.abs(x2-x1))
            
{
                tx 
= x2;
                flag 
= false;
            }

            
if(Math.abs(ty - y1) > Math.abs(y2 - y1))
            
{
                ty 
= y2;
                flag 
= false;
            }

            g.drawLine(x,y,tx,ty);
            x 
= (int)(c*(n+m)*mark_x + x1 );    //更新 实线段 + 虚线段
            y = (int)(c*(n+m)*mark_y + y1 );
            
            
if(x > x2 || y > y2) break;
            c
++;
        }

        
while(flag);
    }

第三步: 流动原理
   好了,会画虚线了,现在让我们来看看,虚线是怎么流动起来的.请看下图:

 

    中间有条蓝线,我们假定其为一张图片的边界,蓝线的右边是一张图片,左边是不存在的空间.有过photoshop经验的朋友应该清楚,流动的虚线在视觉上好像是从图片的左边,一条条实线段,排成一列,挨个进来,然后一直往前走.循环反复.有点类似一队单列士兵队伍,正通过城门,从城外有条不紊的进来,而我们站在城内,只看到了进到城内的士兵,看不到城墙之外的其他士兵.(比喻有点不恰当,因为图片之外是没有什么线条的).上图就是组成虚线的 "实线段" 正一条接着一条的从图片之外进到图片之内.从时间0到时间6,线段正一个像素一个像素的挪动着.

第四步:实现
     分两小步走,将要画的流动虚线分成两部分: 流动虚线的第一段(实线或虚线),流动虚线的剩下部分
 A.画虚线第一段,又分两种情况:实线,虚线
    a.实线,这时实线段正穿过图片边界,进入图片内部.使用drawLine()画出进入的部分,然后计算流动虚线的第二部分的起始位置(实线进入部分的长度 + 虚线段长度)
    b.虚线,这时,前一个实线段已经整个穿过图片边界,而后续的实线段还没有开始穿越,所以不需要画线,只须计算出流动虚线的第二部风的起始位置就可以(进入的虚线部分长度)

 B.画流动虚线的第二部分,由于A步骤已经计算出了该部分的起始位置,所以这里只要使用画虚线的代码,画出虚线就可以.

某个时间点的流动虚线已经画好了(静态),那么整个时间段的流动虚线(动态)怎么画呢?
while(true)
{
 1,计算某个时刻流动虚线第一个段的长度(从0到4一次变化,并且实线、虚线 交替出现)
 2,画某个时间点的流动虚线(如上所述)
}
ok,由于是while循环,会不停的工作,这样各个时间点就连贯起来了,虚线也就流动起来了.

第五步:代码

     说明: 以下代码所做的工作是画流动虚线框,就像photoshop中,选择一个区域时,出现的流动框一样, 虚线从区域的左上角涌出,汇入图片右下角,其中线段会拐弯.
 int templen, boolean isReal, int lenReal 是全局变量
 templen负责控制流动的整个过程,随着其值的变化(0--4),才出现了流动的效果,
 isReal 是布尔变量,标识现在正进入图片的是实线段,还是虚线段(在画完某条流动虚线后,值会发生变化)
 lenReal 是当前正在画的流动虚线的第一部分的长度(在画完某条流动虚线后,值会发生变化)。

 g.setColor(Color.black);        
 g.drawLine(x,y,x,height);
 这两条语句作用是在每次画虚线前,将上一次的虚线清空。

 画虚线部分的代码做了些改动,以适应流动虚线

 

     private   void  drawFlowRect(Graphics g,  int  x,  int  y,  int  width,  int  height)
    
{
        Color oldColor 
= g.getColor();
        templen 
= templen + 1;  //每次前进 1个像素,由templen控制
        if(templen >= 4)
        
{
            templen 
= 0;
            isReal 
= !isReal;
        }

        lenReal 
= templen;
            
        
boolean oldisReal = isReal;  //备份
        double oldlenReal = lenReal; //备份
                
        g.setColor(Color.black);          
//
        g.drawLine(x,y,width,x);
        g.setColor(Color.white);
        drawFlowLine(g, x,y,width,y);
            
        g.setColor(Color.black);         
//
        g.drawLine(width,y,width,height);
        g.setColor(Color.white);
        drawFlowLine(g, width,y,width,height);
                
                        
        isReal 
= oldisReal;     //还原 数据
        lenReal = oldlenReal;
                        
        g.setColor(Color.black);          
//
        g.drawLine(x,y,x,height);
        g.setColor(Color.white);
        drawFlowLine(g,x,y,x,height);
                        
        g.setColor(Color.black);         
//
        g.drawLine(x,height,width,height);
        g.setColor(Color.white);
        drawFlowLine(g, x,height,width,height);
                        
        isReal 
= oldisReal;     //还原 数据                
        g.setColor(oldColor);
    }

    
// 画流动虚线
    
// 需要返回的信息:最后一段是空的还是 实的, 以及长度
     private   void  drawFlowLine(Graphics g,  int  x1,  int  y1,  int  x2,  int  y2)
    
{
        
int x = x1,y=y1;
        
int n = 4;  //实线段长度
        int m = 4;  //虚线段长度
        
        
int tx = 0,ty = 0;
        
        
int mark_x = 0;  //标记 如果为1 表示水平线
        int mark_y = 0;  //标记 如果为1 标识垂直线
        
        
int c = 1;
        
boolean flag = true;
        
        
//要么0,要么 1
        if(x2-x1 != 0)
            mark_x 
= 1;
        
else
            mark_y 
= 1;
        
        
        
//先画流动虚线的第一部分
        if(isReal)
        
{
            
//实线
            tx = (int)(lenReal*mark_x + x1);
            ty 
= (int)(lenReal*mark_y + y1);
            g.drawLine(x,y,tx,ty);
            x 
= (int)((m + lenReal)*mark_x + x1);
            y 
= (int)((m + lenReal)*mark_y + y1);
            
//System.out.println("画了段 实线:len : "+ tx+", (x,y)" + x + ", " + y);
        }

        
else
        
{
            
//虚线
            x = (int)(lenReal*mark_x + x1);
            y 
= (int)(lenReal*mark_y + y1);
            
//System.out.println("画了段 虚线 (x,y)" + x + ", " + y);
        }

        
        
int ttx = x; //第二部分起始位置 x坐标
        int tty = y; //第二部分起始位置 y坐标
        
        
        
do
        
{    
            tx 
= (int)((c*(n+m) - m)*mark_x + ttx);
            ty 
= (int)((c*(n+m) - m)*mark_y + tty);
            
            
if(Math.abs(tx-x1) > Math.abs(x2-x1))
            
{
                
//System.out.println(" 越界了:tx = " + tx + ", x2 = " + x2);
                lenReal = Math.abs(tx - x2);   //只支持 水平线和竖线
                isReal = true;
                
                tx 
= x2;
                flag 
= false;
            }

            
if(Math.abs(ty - y1) > Math.abs(y2 - y1))
            
{
                lenReal 
= Math.abs(ty - y2);
                isReal 
= true;
                
                ty 
= y2;
                flag 
= false;
            }

            g.drawLine(x,y,tx,ty);
            x 
= (int)(c*(n+m)*mark_x + ttx);
            y 
= (int)(c*(n+m)*mark_y + tty);
            
if(x > x2 || y > y2)
            
{
                
if(flag)
                
{
                    
//System.out.println(" 虚 越界了:x = " + x + ", x2 = " + x2);
                    isReal = false;
                    
if(x > x2)
                        lenReal 
= x-x2;
                    
else
                        lenReal 
= y-y2; 
                }

                
break;
            }

            c
++;
        }

        
while(flag);
    }

 

 

-----------------------------------------------------------------------------------------------------------------

http://shop33871860.taobao.com/   

QQ: 780023319

旺旺: xichu_coa

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值