OnMouseMove事件的古怪问题 ( 积分: 100 )

  • 主题发起人 主题发起人 ujin
  • 开始时间 开始时间
U

ujin

Unregistered / Unconfirmed
GUEST, unregistred user!
我在Image的OnMouseMove事件中判断鼠标在不在某一范围之内(要判断的范围很多,几十个),如果在,在这个范围上显示一个图片,做一些处理,发现这样一个问题,Image的大小影响OnMouseMove的处理速度。
比如,Image增大一倍后,明显的感觉鼠标在要判断的范围内显示图片和从要判断的范围出来图片隐藏时变得迟缓,而这时cpu的使用率也大幅提高。
能解释这种现象?
 
我在Image的OnMouseMove事件中判断鼠标在不在某一范围之内(要判断的范围很多,几十个),如果在,在这个范围上显示一个图片,做一些处理,发现这样一个问题,Image的大小影响OnMouseMove的处理速度。
比如,Image增大一倍后,明显的感觉鼠标在要判断的范围内显示图片和从要判断的范围出来图片隐藏时变得迟缓,而这时cpu的使用率也大幅提高。
能解释这种现象?
 
图像刷新的太慢了吧,因为你的鼠标每移动一次都要对图像作一些处理,所以相对于鼠标的移动速度,图像的加载刷新就显得慢多了,你可以把form的doublebuffered打开,然后开块内存作图像处理,处理完后直接将图像assign到image上面,速度会快一些
 
作处理不是对图象做处理,只是输出位置。
鼠标移动部队图像作处理,只是计算是否在要判断的范围之内,如果在,我要显示一个图片,这个图片本身是已存在的(一个image 控件),只需要改变她的位置(放到要判断的范围上)和Visible(可见,不可见)
 
"改变她的位置(放到要判断的范围上)和Visible(可见,不可见)"随着这个范围不断的改变,你显示的图像就要不断的刷新,不管是移动修改还是其他操作image都要进行刷新,你可以试一下把form的doublebuffered打开如果只是移动一个不可见的图片,则cpu占用率会小的多,要是还不行就只能从代码考虑了,把你的代码贴出来吧。
 
贴代码:
procedure TForm1.Image2MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
j:integer;
begin
Image3.Visible:=false;//要显示的图片不可见
Form2.Label1.Caption :='';
for j:=0 to i-1 do
begin
if ((X-MPixArr[j].PixX*B<=10) and (X-MPixArr[j].PixX*B >=-10)) then//判断X坐标是否在范围内
if ((Y-MPixArr[j].PixY*B<=10) and (Y-MPixArr[j].PixY*B >=-10)) then//如果X在,判断Y坐标
begin
image3.Left :=MPixArr[j].PixX*B-9*B+Image2.Left;
image3.Top :=MPixArr[j].PixY*B-9*B+Image2.Top;//在范围内,设置Image3的位置
image3.Visible :=true;//可视
Form2.Label1.Caption :='&amp;micro;±&amp;Ccedil;°&amp;micro;&amp;atilde;&amp;micro;&amp;Auml;&amp;Icirc;&amp;raquo;&amp;Ouml;&amp;Atilde;&amp;pound;&amp;ordm;' + IntToStr(MPixArr[j].PixX) + ',' + IntToStr(MPixArr[j].PixY );//另一窗体进行提示
Break;//跳出循环
end;
end;
end;
当Image2长、宽各增加一倍时,鼠标经过要判断的范围时(显示Image)CPU占用率明显增加。
 
你的代码我试过了,占用率何止是增加就是100%啊
循环里的参数我不知道呆会再模拟以下,你先试一下把范围判断挪到其他的地方例如当image发生mouseenter消息时激活timer当mouseleave时停止timer
下面是我临时测试的一段代码,主要是一幅图片在另一幅图片上移动,不闪烁同时占用率也不高,timer的时间为1/10秒
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;

type
TForm1 = class(TForm)
Label1: TLabel;
Image2: TImage;
Timer1: TTimer;
Image3: TImage;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
m:tbitmap;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
m:=tbitmap.Create;
m.LoadFromFile('D:/我是骆驼/骆驼.bmp');
form1.DoubleBuffered:=true;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
m.Free;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
j:integer;
t:tpoint;
begin
// Image3.Visible:=false;//要显示的图片不可见
form1.Image2.Picture.Bitmap.Assign(m);
getcursorpos(t);
Form1.Label1.Caption :='';
image3.Left :=screentoclient(t).x;
image3.Top :=screentoclient(t).y;//在范围内,设置Image3的位置
// image3.Visible :=true;//可视
Form1.Label1.Caption :='www';//另一窗体进行提示

end;

end.
 
更正一下,我的image控件室自制的有mouseenter事件,标准的image是没有的另外我修改了部分代码,加了循环判断和图片大小,效果还可以,速度不慢,占用率不高,图片不闪,你试试看将image的mousemove事件里的判断写到timer里或者自己做一个timer类来进行判断速度应该能接受

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;

type
TForm1 = class(TForm)
Timer1: TTimer;
Image2: TImage;

Label1: TLabel;
Image3: TImage;
Label2: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
m:tbitmap;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
m:=tbitmap.Create;
m.LoadFromFile('D:/temp/工作文档/pic/风景1.bmp');
form1.DoubleBuffered:=true;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
m.Free;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
j:integer;
t:tpoint;
begin
Image3.Visible:=false;//要显示的图片不可见
form1.Image2.Picture.Bitmap.Assign(m);
getcursorpos(t);
label1.Caption:=inttostr(t.x);
label2.Caption:=inttostr(t.y);
for j:=0 to (image2.Width div 2)-1 do
begin
if (((screentoclient(t).x-j)>50) and ((screentoclient(t).x-j)<100))then
begin
image3.Left :=screentoclient(t).x;
image3.Top :=screentoclient(t).y;//在范围内,设置Image3的位置
image3.Visible :=true;//可视
break;
end;
end;
end;

end.
 
我试一下
 
作用不大:(
 
另外因为你的image2不需要修改所以 form1.Image2.Picture.Bitmap.Assign(m);那部分可以省略直接将图像加载在image里就可以了
 
CPU占用不应该是100%,另一部分代码:
i:=25;
SetLength(MPixArr,i);
MInfo := TMyPix.Create;
MInfo.PixX :=30;
MInfo.PixY :=30;
MPixArr[0]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=130;
MInfo.PixY :=130;
MPixArr[1]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=230;
MInfo.PixY :=230;
MPixArr[2]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=330;
MInfo.PixY :=330;
MPixArr[3]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=430;
MInfo.PixY :=430;
MPixArr[4]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=30;
MInfo.PixY :=130;
MPixArr[5]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=30;
MInfo.PixY :=230;
MPixArr[6]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=30;
MInfo.PixY :=330;
MPixArr[7]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=30;
MInfo.PixY :=430;
MPixArr[8]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=130;
MInfo.PixY :=30;
MPixArr[9]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=230;
MInfo.PixY :=30;
MPixArr[10]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=330;
MInfo.PixY :=30;
MPixArr[11]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=430;
MInfo.PixY :=30;
MPixArr[12]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=130;
MInfo.PixY :=230;
MPixArr[13]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=130;
MInfo.PixY :=330;
MPixArr[14]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=130;
MInfo.PixY :=430;
MPixArr[15]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=230;
MInfo.PixY :=130;
MPixArr[16]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=330;
MInfo.PixY :=130;
MPixArr[17]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=430;
MInfo.PixY :=130;
MPixArr[18]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=230;
MInfo.PixY :=330;
MPixArr[19]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=230;
MInfo.PixY :=430;
MPixArr[20]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=330;
MInfo.PixY :=230;
MPixArr[21]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=430;
MInfo.PixY :=230;
MPixArr[22]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=330;
MInfo.PixY :=430;
MPixArr[23]:=MInfo;
MInfo := TMyPix.Create;
MInfo.PixX :=430;
MInfo.PixY :=330;
MPixArr[24]:=MInfo;
这些就是中心点,鼠标判断如果实在中心点周围
if ((X-MPixArr[j].PixX*B<=10) and (X-MPixArr[j].PixX*B >=-10)) then//判断X坐标是否在范围内
if ((Y-MPixArr[j].PixY*B<=10) and (Y-MPixArr[j].PixY*B >=-10)) then//如果X在,判断Y坐标

就显示image3。
 
不应该呀我测试的代码在mousemove里时占用率其高,当我将其移动到timer里时占用率降低,而且开着doublebuffer可以减少图像的闪动
 
使用Timer控件CPU占用率还是高。
初始Image2的大小时600*450,这时CPU占用很小,由于要求Image2有放大功能,所以Image2放大时,长、宽各方大一倍,当Image3显示和隐藏时CPU占用率达到30%多,当Image2长、宽放大到3倍时,Image3显示时和隐藏时CPU占用率达到40%-50%,其它时候鼠标移动的时候CPU占用率很小,这是在赛扬1G+SD128M内存测试的结果。
如果是P4 2.4G+DDR512M内存那么无论在什么情况下,都很流畅,CPU占用最多的时候还不到10%。
 
重新测试了一下,终于发现问题所在:
Image2中的图形是在程序中手工绘制,当Image2的大小改变时,就会出问题,如果Image2是空白,或者是以存在的图片,那么就不会出问题。


这个问题应该怎么解决呢?
 
接受答案了.
 
image在每次修改后都需要刷新这就要占用很多资源,你只需要按照form1.Image2.Picture.Bitmap.Assign(m);那样的写法,先在内存中处理图像,处理后将图像assign到image2上面就可以提高速度,而且放到timer里assign比系统刷新占用资源少因为刷新不是时时的
 
后退
顶部