Canvas.StretchDraw在窗体改变大小后,画出的图片不正常,也就是并没有拉申(100分)

  • 主题发起人 主题发起人 ybxiao577
  • 开始时间 开始时间
Y

ybxiao577

Unregistered / Unconfirmed
GUEST, unregistred user!
主窗体是一个MDI窗体,上面pnlTop是工具栏,左边还有一个导航条,客户区就是用Canvas画的一个背景图(当然打开的子窗体也是在该区域显示)。

比如我现在要做一个隐藏左边导航条的功能,因为这时候改变了客户区的大小,这时候我希望背景图能被拉申,在新的客户区显示出来。目前我调用FormPaint()或者是Invalidate()方法都没有达到需要效果。

大致代码如下:
procedure TMainForm.FormPaint(Sender: TObject);
var
rect: TRect;
begin
rect := GetClientRect;
rect.Right := rect.Right - tvTJFL.Width ;
rect.Bottom := rect.Bottom - pnlTop.Height - StatusBar.Height ;
if Assigned(bmp) then
Canvas.StretchDraw(rect, bmp) ;//bmp是一个类变量,有定义也有赋值
end;

procedure TMainForm.HideNavigatorClick(Sender: TObject);
begin
TMenuItem(Sender).Checked := not TMenuItem(Sender).Checked;
if TMenuItem(Sender).Checked then
begin
oldWidth := pnlLeft.Width;
pnlLeft.Width := 0;
end
else
pnlLeft.Width := oldWidth;
Invalidate;
end;

procedure TMainForm.FormResize(Sender: TObject);
begin
Invalidate
end;
 
这样改试试
procedure TMainForm.FormResize(Sender: TObject);
begin
self.Canvas.Invalidate
end;
 
不需要OnResize的吧,既然在OnPaint中写了就不需要OnResize了,
因为任何窗体上的变化都会触发OnPaint。

>> rect := GetClientRect;
>> rect.Right := rect.Right - tvTJFL.Width ;
>> rect.Bottom := rect.Bottom - pnlTop.Height - StatusBar.Height ;
上面的代码默认的rect的left和top都为0,不知道这是不是你想要的。

大概你忘了给rect的left和top赋值了。
 
To antic_ant:
Canvas没有Invalidate这个方法

To koala:
rect的Left和Top在rect := GetClientRect时就已经取到了,都是0
 
就因为left和top都是0,才出问题的!

是否应该 rect.left := pnlLeft.Width;
rect.top := pnlTop.Height;
呢?
 
To koala:
rect的Left和Top设置为0是正确的,我测试过,但我也没法解释为什么Rect(0, 0, x, y)画的区间就是我指的客户区。

您用上面的代码测试一下,看到的结果就会让呢觉得奇怪了:-)
 
客户区CientRect是Form中除去MainMenu、边框之外的区域,所以隐藏了ToolBar之后,应该
减去ToolBar所占的区域,下面的代码应该可以解决这个问题

procedure TMainForm.FormPaint(Sender: TObject);
var
Rect: TRect;
begin
if not Assigned(Bmp) then
Exit;

Rect:=ClientRect;
if TopToolBar.Visible then
Inc(Rect.Top,TopToolBar.Height);
if StatusBar.Visible then
Dec(Rect.Bottom,StatusBar.Height);
if LeftToolBar.Visible then
Inc(Rect.Left,LeftToolBar.Width);
with ClientRect do
Canvas.StretchDraw(Rect,Bmp);
end;
 
To pihome:
客户区是从(0,0)开始的,不管隐藏了ToolBar还是Panel或者没有,都是从(0,0)开始的,所以您上述的代码跟koala说的是一样的,这样,画出来的客户区背景图就会在左边和顶部空出一块来。

我觉得应当不是客户区大小计算错误的原因。

我在前面不是说了,当我用其他程序遮挡一下本程序,然后再回到到程序后就可以看到背景图是正确拉申过了的,跟隐藏左边工具条或者改变窗体大小时OnPaint中画出的背景是不一样的。
而这时,程序不过得到一个需要重画窗体的消息,但正是这个消息却可以让程序看到正确的效果,而我在程序中该怎么模拟这消息呢?--我想,这也许是一个解决办法吧
 
斑竹帮我来瞧瞧,好吗。

多谢您老人家了:-)
 
参考http://www.delphibbs.com/delphibbs/dispq.asp?LID=1856028
 
呵呵,楼上的大哥,您的链接指在我这帖子上阿 :-)
 
晕,你自己搜索"MDI背景"吧,能搜索出一大堆:)
 
倒,如果可以搜索出来,我怎么会来问呢(当然,也有可能我没瞧仔细)

如果您不知道,那何必来答呢!

不懂就不要大师一样,我很不喜欢这种人,当然,我不是说大家不可以切磋,但是您的态度也要端正一点
 
很抱歉,我倒不知道我的态度哪一点不端正了???
以前有答案的问题为什么要重复回答?
这个问题就是客户区域刷新的问题,MDI与普通窗体的不同,所以不能简单的用FormPaint之类的解决
需要截获客户区处理过程自己处理,至于具体的代码,完全可以搜索出来,没必要给你贴出来

我承认,我也有很多问题不懂,我也不是大师,我也不是为讨某人喜欢而来这里的!
 
楼上的说话不用太冠冕堂皇了

我先问你,你可仔细看过我提的问题?你是在想当然?还是针对问题自己动手试验过了呢?

先指一个URL,然后又牛气轰轰地“全文搜索”,虚伪!

没时间没精力真正关心别人提出的问题就不用这样搞,与其这样,不如来个Up,别人还会跟你道声谢。
 
首先,以前我碰到过这样的问题,并用我第一帖的方法解决了部分问题,并在这里全文搜索找到正确答案
其次,你的问题我看清楚了,并动手试验过
第三,上面的URL是本来是贴以前收藏的,我试验写的代码不是很规范,所以借用他人的帖子
第四,我看来看去,觉得是我那个"晕"让你觉得不好,如果是这样,我申明一下,我没有贬低别人的意思,我这里是说我自己晕,贴个URL都弄错了
说实在的,我还没有得到过"虚伪"的评价,到是你,你不觉得如此轻易就对一个人下评价太草率些了么?
 
楼上的,说你虚伪可能有点过,我收回。

不过,我还是想指出来,你贴出来的代码跟我最开始帖的本质上有什么区别?因为问题的根本就不是绘图区计算错了。
再说,你自己的代码中也还有点小错误。
现在不是交作业,能够规划一点固然好,但如果您能给出一个解决的方法或者是一个解释就感激不已了
 
我第一贴写的代码可能会有错,因为看到你贴子的时候我首先是想到我以前碰到过类似的一个问题
因为图片的边界不明显,看起来好象缩放没问题的,但实上是没有缩放完全的,程序运行了很久才发现这个问题
看过你回贴之后知道我的回贴可能错了,调试了一下,答案是满意的
首先你的方法是错的,MDI窗体不能像普通窗体一样,用FormPaint的方法在画背景
为什么?实际上要正确的画图的话要响应一个重要的消息WM_ERASEBKGND,重画背景及需重画的区域
为什么FormPaint不行,因为我们不知道重画的区域已经改变了,所以不管怎么画都不正确
而用其他Form挡一下移开后就可以了,因为MDI窗体的客户区自己处理了这个消息并正确的重画了
所以我们没法用普通的方法正确的重画,只能截获MDI窗体的客户区处理过程自己来处理消息
这是我的理解,可能有一些描述不恰当的地方

如果你实在懒得搜索,给你贴上一篇贴子,来源及作者不知道了
在Form中添加Image控件

设BMP图象

name为 IMG_BK

在Foem的Create事件中写入

Self.brush.bitmap:=img_bk.picture.bitmap;

上面的方法在Win95里面有问题。

*****************

在MDI程序中,由于MDI的主窗口一般的功能是提供子窗口显示的位置和提供菜单、工具条、状态条等,而窗口的客户区则一般不会有其它的用途,所以Image运行时会不见。不过要显示也可以,你可以试一下以下方法:

第一步:创建一个新的工程。

第二步:将Form1的FormStyle设置为fsMDIForm,设置成MDI的主窗口。

第三步:在Form1上增加一个Image元件,并选择要设置的背景到Image的Picture中。

第四步:在Form1的Private中定义:

FClientInstance,

FPrevClientProc : TFarProc;

PROCEDURE ClientWndProc(VAR Message: TMessage);

第五步:在实现(implementation)中加入上述过程的具体内容:

PROCEDURE TForm1.ClientWndProc(VAR Message: TMessage);

VAR

MyDC : hDC;

Ro, Co : Word;

begin

with Message do

case Msg of

WM_ERASEBKGND:

begin

MyDC := TWMEraseBkGnd(Message).DC;

FOR Ro := 0 TO ClientHeight DIV Image1.Picture.Height DO

FOR Co := 0 TO ClientWIDTH DIV Image1.Picture.Width DO

BitBlt(MyDC, Co*Image1.Picture.Width, Ro*Image1.Picture.Height,

Image1.Picture.Width, Image1.Picture.Height,

Image1.Picture.Bitmap.Canvas.Handle, 0, 0, SRCCOPY);

Result := 1;

end;

else

Result := CallWindowProc(FPrevClientProc, ClientHandle, Msg, wParam, lParam);

end;

end;

第六步:在Form1的创建事件中加入:

FClientInstance := MakeObjectInstance(ClientWndProc);

FPrevClientProc := Pointer(GetWindowLong(ClientHandle, GWL_WNDPROC));

SetWindowLong(ClientHandle, GWL_WNDPROC, LongInt(FClientInstance));

上面的步骤已经完成了MDI主窗口背景图案的设置,下面可以增加一个MDIChild窗口,实现MDI程序。

第七步:新增加一个Form,并将FormStyle设置为fsMDIChild。

现在你可以编译运行这个程序,你会发现,Image元件并不会在Form上显示出来,但是整个Form的客户区域被Image中的图像所铺满。
 
后退
顶部