我也学写天气预报。。。

Frank.WU 2010-09-11 10:04:36
加精
作为一个不务正业,在工作至于业余自学 delphi 的人,看到 VC 版本有说模拟 QQ 的外观的帖子,额,那个,我在 delphi 板块也学写一个天气秀。


先来看看结果的截图:

首先,准备好如下东西:
1.delphi2010, 听说那个叫“易博龙”的网站有下载,非免费。。。
2.GDIplus,你可以去 http://www.progdigy.com/ 下载,开源免费。
3.素材,我用 Fireworks 做了个,功底不好,不要见笑;
这是天气图片:

这是背景图:


先说下大概原理,其实就将需要的图片合成,然后在合成结果上面画上字,将这个最后合成的图作为窗体背景。一般用 Bitmap 位图的就不说,到处都有。这次只要是用 Png 图片作为窗体背景,处理 PNG 时候是用 GDI+ 来处理,就是这么简单。

好了,下面开始动工。
1.
先新建一个 VCL Form 应用工程;然后在引用单元手动输入以下几个单元:

GDIPUTIL, GDIPAPI, GDIPOBJ, {GDI+ 需要}
pngimage, {PNG 需要}
ActiveX;{内存流需要}

再拖一个 PopupMenu 上去,建两条项目:
一条 Caption 为 Close, 关闭程序用;
一条 Caption 为 About, 这个干嘛用?下面的同学说一下。。。
设置主窗体的 PopupMenu 为刚才拖下来的 PopupMenu1.

2.
定义一个类型:为下面 IStream / TStream 转换需要。

type
TFixedStreamAdapter = class(TStreamAdapter)
public
function Stat(out statstg: TStatStg; grfStatFlag: Longint): HResult;
override; stdcall;
end;

function TFixedStreamAdapter.Stat(out statstg: TStatStg;
grfStatFlag: Integer): HResult;
begin
Result := inherited Stat(statstg, grfStatFlag);
statstg.pwcsName := nil;
end;


3.
使用 GDI+ 合成图片:
先看看需要的子过程:

procedure DrawBkgroud; { 合成图片的过程 }

具体实现如下:
procedure TForm1.DrawBkgroud;
var
Bg: TGPBitmap;
G: TGPGraphics;
Guid: TGUID;
WD: TGPBitmap;
Cav: TGPBitmap;
Png: TPngImage;
MS: TMemoryStream;
FontFamily: TGPFontFamily;
LFont, SFont: TGPFont; { 字体 }
LPointF, SPointF: TGPPointF;
LSolidBrush, SSolidBrush: TGPSolidBrush;
begin

Png := TPngImage.CreateBlank(COLOR_RGBALPHA, 16, 359, 272); { 创建指定大小 359 * 272 空白的png }
{有同学会问 那个 359,272 是怎么得到的呢?额,根据背景图片大小自己写的。。。 }
Png.SaveToFile('png_out.png'); { 测试保存,结果是一个带 Alpha 通道的空白 PNG }

MS := TMemoryStream.Create;
Png.SaveToStream(MS);{ 保存到内存流,待用 }
Png.Free;

Bg := TGPBitmap.Create('bg.png'); { 载入背景图片 }
WD := TGPBitmap.Create('0.png'); { 载入天气状况图片 }
Cav := TGPBitmap.Create(TFixedStreamAdapter.Create(MS)); { 从内存流创建窗体背景图 }
MS.Free;

G := TGPGraphics.Create(Cav);{ 开始合成 }

FontFamily := TGPFontFamily.Create('Tahoma');
LFont := TGPFont.Create('Tahoma', 20, FontStyleBold, UnitPixel); { 大字体 }
SFont := TGPFont.Create('微软雅黑', 15, FontStyleBold, UnitPixel); { 小字体 }

LSolidBrush := TGPSolidBrush.Create(MakeColor(26, 161, 245));{ 字体颜色 }
SSolidBrush := TGPSolidBrush.Create(MakeColor(240, 240, 240));
G.DrawImage(Bg, 30, 30);
G.DrawImage(WD, 0, 0);

LPointF := MakePoint(130.0, 60.0);{ 位置 }
G.DrawString('25~32℃', -1, LFont, LPointF, LSolidBrush);

SPointF := MakePoint(130.0, 98.0);
G.DrawString('晴转阴,间中有钱掉下', -1, SFont, SPointF, SSolidBrush);

SPointF := MakePoint(130.0, 120.0);
G.DrawString('微风,风力 18 级', -1, SFont, SPointF, SSolidBrush);

{ 测试存为 png ... }
GetEncoderClsid('image/png', Guid);
Cav.Save('out.png', Guid);{ 看看合成结果呗 }

RenderForm(220, Cav); { 将窗体设置为靓靓背景吧。。。}

Cav.Free;
WD.Free;
G.Free;
Bg.Free;

end;


4.
既然上面已经使用了个过程 RenderForm(220, Cav),现在继续完成它。

{过程名程:RenderForm(透明度,窗体背景图)}
procedure RenderForm(TransparentValue: Byte; SourceImage: TGPBitmap);

procedure TForm1.RenderForm(TransparentValue: Byte; SourceImage: TGPBitmap);
var
zsize: TSize;
zpoint: TPoint;
zbf: TBlendFunction;
TopLeft: TPoint;
WR: TRect;
GPGraph: TGPGraphics;
m_hdcMemory: HDC;
hdcScreen: HDC;
hBMP: HBITMAP;
FDC: HDC;
begin
hdcScreen := GetDC(0);
m_hdcMemory := CreateCompatibleDC(hdcScreen);
hBMP := CreateCompatibleBitmap(hdcScreen, SourceImage.GetWidth(),
SourceImage.GetHeight());
SelectObject(m_hdcMemory, hBMP);
GPGraph := TGPGraphics.Create(m_hdcMemory);
try
{ GPGraph.SetInterpolationMode(InterpolationModeHighQualityBicubic); }
GPGraph.DrawImage(SourceImage, 0, 0, SourceImage.GetWidth(),
SourceImage.GetHeight());
SetWindowLong(Handle, GWL_EXSTYLE,
GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED); { 这个必须有 }
zsize.cx := SourceImage.GetWidth;
zsize.cy := SourceImage.GetHeight;
zpoint := Point(0, 0);
with zbf do
begin
BlendOp := AC_SRC_OVER;
BlendFlags := 0;
AlphaFormat := AC_SRC_ALPHA;
SourceConstantAlpha := TransparentValue;
end;
GetWindowRect(Handle, WR);
TopLeft := WR.TopLeft;
{ UpdateLayeredWindow(Handle, FDC, @TopLeft, @zsize, GPGraph.GetHDC, @zpoint,
0, @zbf, ULW_ALPHA); WIN7 里面可以,WINXPSP3 就不行。。。所以改为以下:}
UpdateLayeredWindow(Handle, 0, nil, @zsize, GPGraph.GetHDC, @zpoint, 0,
@zbf, ULW_ALPHA);
finally
GPGraph.ReleaseHDC(m_hdcMemory);
ReleaseDC(0, hdcScreen);
DeleteObject(hBMP);
DeleteDC(m_hdcMemory);
GPGraph.Free;
end;
end;


4.
啊?发现一切如愿都出来的,但是不能拖动窗体到处走。。。老生长谈的东西。

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
ReleaseCapture;
Perform(WM_SYSCOMMAND, $F012, 0);
end;


5.
继续继续,可是没东西可写了,好吧,就写个 About 。。。

procedure TForm1.MnuAboutClick(Sender: TObject);
begin
Application.MessageBox
('模拟天气预报,GDI+ 实现。' + #13#10 +
'email: sail2000#126.com' + #13#10 + '2010/09/10, 小帆, 广州', '关于',
MB_OK + MB_ICONINFORMATION);
end;


6.
额,原来如此简单,知道了吧,知道了,就应该写最后一句了:

procedure TForm1.MnuClose1Click(Sender: TObject);
begin
Close { 886 }
end;


最后,我是业余自学 Delphi 的,很多东西不知道原理,只知道这样用而用。
下面肯定有同学会问:咦?结果是出来的,但是不能再往窗体上放控件了!
对,这个事情,我曾经也问过外国的 delphi 技术高手,
那老头说:方法有二:
1.改用底层重写窗体。
2.用两个窗体搭配。。。(天气秀之类的就是这样实现的!!!)

好了,就这样了。
...全文
10066 438 打赏 收藏 转发到动态 举报
写回复
用AI写文章
438 条回复
切换为时间正序
请发表友善的回复…
发表回复
see_you_see_me 2013-02-25
  • 打赏
  • 举报
回复
楼主真是很强啊,好多年没使用delphi了,请问是在delphi2010下开发的吗,我下载工程后用D7打开后发现找不到bsPngImageList,是不是只能升级到delphi2010呢,谢谢
hubeijiaozi 2012-02-28
  • 打赏
  • 举报
回复
代码好像很多的!
wblaze 2011-10-30
  • 打赏
  • 举报
回复
学习一下吧
xiaoyongxiao 2011-08-22
  • 打赏
  • 举报
回复
强,很强
netilu 2011-08-21
  • 打赏
  • 举报
回复
果然很强大
dungeonsnd 2010-12-15
  • 打赏
  • 举报
回复
楼主,我要说实话了,比QQ2010的天气小窗口差很多,呵呵。
加油。
实现在QQ那样漂亮的倒不难,关键是实现(QQ2010里应该都是用directUI来画的),而不是自己手动用gdi+来画。

不妨也来讨论一下通过网络来获取天气和气温等实时信息。
我知道java中如何去连接网络。MFC中通过CInternet类应该也可以吧。
wsok120 2010-12-13
  • 打赏
  • 举报
回复
附上程序该有多好啊
jixiangshilin 2010-11-21
  • 打赏
  • 举报
回复
很棒啊!
foung 2010-09-26
  • 打赏
  • 举报
回复
lai de hao wan a
友谊之门 2010-09-21
  • 打赏
  • 举报
回复
好玩……呵呵
amazheng 2010-09-21
  • 打赏
  • 举报
回复
dephi没怎么接触过,主要还是觉得不主流,呵呵
paste 2010-09-21
  • 打赏
  • 举报
回复
[img=http://www.oidn.net/weather.png]http://www.oidn.net/weather.png[/img]
C++Builder的来了,直接抄妖哥有关gdi+的代码

代码
huwei1587403 2010-09-20
  • 打赏
  • 举报
回复
天天一样的天气
yhd1074694651 2010-09-20
  • 打赏
  • 举报
回复
恩 ············
zhuoyue 2010-09-20
  • 打赏
  • 举报
回复
路过学习
H_hou 2010-09-20
  • 打赏
  • 举报
回复
bucuoa
hwwr 2010-09-20
  • 打赏
  • 举报
回复
我也在学习中!呵呵
daiguangda 2010-09-20
  • 打赏
  • 举报
回复
每天回帖即可获得10分可用分!
豆豆虫豆豆 2010-09-20
  • 打赏
  • 举报
回复
挺实用的,
king10002010 2010-09-19
  • 打赏
  • 举报
回复
每天回帖即可获得10分可用分!
加载更多回复(363)

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi GAME,图形处理/多媒体
社区管理员
  • GAME,图形处理/多媒体社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧