3h关于TTreeNode和Bitmap的两个小问题(100分)

  • 主题发起人 主题发起人 3h
  • 开始时间 开始时间
3

3h

Unregistered / Unconfirmed
GUEST, unregistred user!
1、如果在程序中取得要求的TreeNode的位置?
(X,Y或者Left,Top,Width,Height)
主要想在它的Canvas中重Draw.
2、如果不使用操作而用程序装入一个Bitmap图形?要求不用到图形文件,
如用loadformfile()什么的即属离题!需要的是,例如写一个控件需要
装入一个自己的图,不能用文件的方法吧?我想将图的数据放在控件内,
也就是一大堆数字的那个,象在Form中用"View as Text"看到的一样,
由于用到的图不多,只有几个,我想这个比较方便。
2.5、如果(2)实现起来有困难,再问另一个办法,我发现函数:
LoadBitmap()中它的第二个参数可以用一个常量,OBD_CheckBoxes,即:
Var
B : TBitmap;
begin
B := TBitmap.Create;
B.handle := LoadBitmap(0,PChar(Obd_checkboxes));
...
end;

结果得到的 B 竟然是一个有十二个图象的大图!我想将它划成几个,
或者取它的十二分之一成为一个新图,就是从中剪下一块,可有办法?
我知道这100分远没有达到要大侠动手写程序的动力,但实在是没有什么家
产了,还望诸位笑纳。 :)
3h 1999-04-09
 
3h啊,自己找个有SOURCE的控件看一下吧
深圳同非有个很不错的
 
找了整个DELPHI的源码目录。没找着。
你可有类似的帮我弄一个?一定少不了给你加分。
BTW:你昨天给我那个版主的HTML生成程序已经成功了,多谢!
 
1.关于1的问题,可不可以说的再清楚一些....
2.这个问题很容易实现,可以有很多种方法
(1)在控件中使用可以这样做:
type
TMyPic=class(TGraphicControl)
private
FPic:TBitmap;
procedure SetPic(const Value:TBitmap);
public
constructor Create(aOwner:TComponent);
destructor Destroy;
published
Pic:TBitmap read FPic write SetPic;
end;
……
constructor TMyPic.Create(aOwner:TComponent);
begin
inherited;
FPic:=TBitmap.Create;
end;

destructor TMyPic.Destroy;
begin
FPic.Free;
inherited
end;

procedure SetPic(const Value:TBitmap);
begin
FPic.Assign(Value)
end;

(2)从资源中读出位图应该这样做:
首先用Image Editor打开资源文件(如果你的Procect为
Pro.dpr,在资源文件为Pro.res),在其中加入一个位图资源
起名为MyPic,然后用
aBmp:=TBitmap.Create;
aBmp.LoadFromSourceName(HInstance,"MyPic");
aBmp.Free;

(3)最后一个方法是一个小技巧,可以在程序设计阶段在任何
地方放置一个Image控件,并调入位图,然后设置其Visible属性
为false,以后使用:
aBmp:=TBitmap.Create;
aBmp.Assign(Image.Picture.Graphic);
即可得到该位图的一个副本....
 
第一个问题再说一下,有一个TREEVIEW,其内必有节点TREENODE,我想得到它的位置,如左,上,宽,高,或者是X,Y的值也可以。
我看第二个问题的提出还是让VC有点误解了。我的原意是,用一大堆数字表示一
个确定的位图!我看VC的例程,(1)是从别的地方取得,或者需要用户装入;
(2)是从文件读出;(3)是在设计应用程序时用的。
而我的意思是,我有二三个图,强制的,必须在控件中使用的,当然不能让用户去
LOAD一个图吧?要不发布到别的地方岂不是要带一个BMP?所以我觉得要用数据代替
位图夹在文件内,而不是用真的图。其实这种例子在DELPHI已经可以的,如,
按钮上的图,用View as text看,就能看到这个图其实已经变成一大堆用大括号
括起的数字了。
大家再想点办法,不定有的。:)
 
1.使用TTreeNode的DisplayRect方法
下面引自Delphi Help:
TTreeNode.DisplayRect
Returns the bounding rectangle for a tree node.
function DisplayRect(TextOnly: Boolean): TRect;
Description
If the TextOnly parameter is True, the bounding rectangle includes only the text of the node. Otherwise, it includes the entire line that the node occupies in the tree-view control.
2.使用资源文件
参见:<a href="http://www.gislab.ecnu.edu.cn/delphibbs/DispQ.asp?LID=103801">请问如何把大批图片放到资源文件中,如何调用?</a>
或者可以参考一下我写的一个小控件:<a href="ftp://202.120.100.49/vcl/new/TStore.zip">TStore.zip</a>
 
To tqz: 你那个文件找不到,链接错误。
&amp;: 你提到的那个已答问题让我好好再研究一下。
 
1.tqz已经说清楚了,就象这样用:
aRect:=TTreeView1.Selected.DisplayRect(true);
2.先写一个小程序,把TBitmap数据变成可视字符,并放在程序中作为一
个字符串常数的值(如可以变为十六进制的数值),在控件的 Create中
把图像数据(就是那个字符串常量)解码放在一个TMemoryStream中,再
用TBitmap.LoadFromStream读入Bitmap中,不知道这能不能满足你的要
求....
 
嘿嘿,这些简单的问题让大家见笑了。
提出这件事的原意是,前些天CAKK不是提出想做一个带CHECK盒的TREEVIEW
吗?我就想就些问题做一个,顺便学习一下做控件的技巧。没想到问题多多。
:)
由CAKK的问题以及大家对此问题的作答,我拟出两个方案:
<font color="red">1、用CANVAS。</font>
用TREEVIEW的CANVAS直接进行TEXTOUT和DRAW,将原来的NODE向后面移
一定距离,而这个位置就留给CHECKBOX。用此方法可以让原来的STATEIMAGES
能继续使用,也就是说,加上这个BOX,一个NODE可以同时有三个图标。尽
管这没有必要。但它需要知道NODE的位置才能DRAW和TEXTOUT;
<font color="red">2、用已有的STATEIMAGES。</font>
我想,屏蔽了原来的这个选项,直接在控件内部建一个IMAGELIST,
并让它原来的STATEIMAGES指向它,然后用CheckState属性直接得到它的图标。
由此,必须建立一个内部的ImageList,而且为了使用这个有内容(图标),还
必须弄上几个小图,如TQZ所说的放在资源文件中(这一点来说是正确的,接
受答案了)。
可是又发现了新问题,安装了控件之后运行程序竟然发现有“找不到
TCustomImageList类”!真是头痛。我有个直觉,应该是在<font color="red">
FCheckImageList := TCustomImageList.Create(AOwner);</font>
这一句出乱子,而且后面的参数好象也用得不大好。

第一次学做控件,不了解控件的很多方面,知识还浅薄的很,请大侠们原谅,
并给予指教。下面是控件的源码,致命错误是一定有的,请指正。
<font color="gray">只写了丁点儿就发生这样的事,真让我心灰意冷。</font>
另求教,<font color="red">如果屏蔽了原来的stateimages属性呢?</font>
unit CheckTreeView;
interface
uses
Messages, Windows, MultiMon, Classes, Sysutils, Graphics,
CommCtrl, Controls, ComCtrls, ImgList;
type
TCheckTreeView = class(TTreeView)
private
FCheckState : Byte;
FChecked : Boolean;
FCheckImageList : TCustomImageList;
protected
{ Protected declarations }
public
constructor Create(AOwner: TComponent);
OverRide;
procedure CreateWnd;
OverRide;
destructor Destroy;
override;
procedure SetChecked(Index: Integer;
State : Byte);
procedure SetCheckState(Index: Integer;
State : Byte);
function GetChecked(Index: Integer) : Byte;
function GetCheckState(Index: Integer) : Byte;
{ Public declarations }
published
property StateImages Read FCheckImageList;
property Checked : Boolean read FChecked Write FChecked Default False;
property CheckState : Byte read FCheckState Write FCheckState Default 1;
{ Published declarations }
end;

procedure Register;
implementation
<font color="blue">{$R CheckTreeView.res}</font>
procedure Register;
begin
RegisterComponents('Standard', [TCheckTreeView]);
end;

constructor TCheckTreeView.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
FCheckImageList := TCustomImageList.Create(AOwner);
end;

procedure TCheckTreeView.CreateWnd;
Var
FBMP : TBitmap;
begin
inherited CreateWnd;
With FCheckImageListdo
begin
FBMP := TBitmap.Create;
FBMP.Handle := LoadBitmap(hInstance, PChar('UnCheck.bmp'));
// 这三个图都已放在资源文件中了。
FCheckImageList.Add(FBMP, FBMP);
// state = 0, no use always
FCheckImageList.Add(FBMP, FBMP);
// state = 1, UnCheck
FBMP.Handle := LoadBitmap(hInstance, PChar('Checked.bmp'));
FCheckImageList.add(FBMP, FBMP);
// state = 2, Checked
FBMP.Handle := LoadBitmap(hInstance, PChar('GrayCheck.bmp'));
FCheckImageList.Add(FBMP, FBMP);
// state = 3, Graycheck
end;
FBMP.Free;
end;

destructor TCheckTreeView.Destroy;
begin
FCheckImageList.Free;
inherited;
end;

procedure TCheckTreeView.SetChecked(Index: Integer;
State : Byte);
begin
//
end;
procedure TCheckTreeView.SetCheckState(Index: Integer;
State : Byte);
begin
//
end;
function TCheckTreeView.GetChecked(Index: Integer) : Byte;
begin
//
end;
function TCheckTreeView.GetCheckState(Index: Integer) : Byte;
begin
//
end;
end.
--------------------------------------------------------------
TO VC:
如何将文件变成流数据呢?
又如何将流放在TMemoryStream中呢?
给出源码至少给分1/3。
 
to 3H;
连接没错
to VC:
你是否想对Bitmap进行MIME编码呢?这样当然可以,不过太不标准了。
 
1.继承TCustomTreeView,然后将所有需要published的属性在
TCheckTreeView的published中重新声明一遍,象这个样子:
published
AutoExpand;
可以看着help或TTreeView的源程序慢慢写声明....
2.变成流数据很容易的,就象这个样子:
const
CharPerLine=80;
var
fn1,fn2:string;
//fn1是输入的Bmp文件名,fn2是输出的文件名
f1:TFileStream;
f2:TextFile;
i:integer;
buf:byte;
begin
f1:=TFileStream.Create(fn1,fmOpenRead);
AssignFile(f2,fn2);
Reset(f2);
try
Write(f2,' ');
for i:=0 to f1.Size-1do
begin
f1.ReadBuf(buf,1);
if i mod CharPerLine=0 then
begin
if i<>0 then
begin
WriteLn(f2,'''');
Write(f2,'+')
end;
Write(f2,chr(buf mod 16+ord('A'))+chr(buf div 16+ord('A')))
end;
end;
WriteLn(f2,''';');
finally
CloseFile(f2);
f1.Free
end;
end;

然后写入TMemoryStream中的代码为:
假设有:
const
data='ABCDDEASDFASDSDAFASDF';
写入的代码为:
var
f:TMemoryStream;
i:integer;
buf:byte;
begin
f:=TMemoryStream.Create;
try
i:=2;
while i<=Length(data)do
begin
buf:=(ord(data[i-1])-ord('A'))+(ord(data)-ord('A'))*16;
f.Write(buf,1);
inc(i,2)
end;
f.Position:=0;
bmp.LoadFromStream(f)
finally
f.Free
end
end;

以上代码效率不是很高,如果你嫌慢,还可以优化,如在f.Write时一次
多写几个字节....
不好意思,都没有调试过,不过应该没有问题,你试试吧....
 
to tqz:
速度太慢引起,好在文件很小,已下载完正在看。
to VC:
为什么不在TTreeView继承?它也是从TCostomTreeView继承来的呀?
直接继承岂不更好?
那段代码我正想试。 :-)
&amp;: 我上面很多字写错了,很多“如果”实际上是:“如何”。
 
从TCustomTreeView继承是一个好方法,也是一个相对正规一点的方法,
它里面的很多属性都是protected的,这也是TTreeView与它的唯一区别,
别的控件也应该这要做....
 
经过大家的指点昨天晚上又学习了一下进展良多,关于前面提到的那个参数,
觉得用 SELF 可行。
发现一个新的问题,StateIndex是属于TreeNode的属性,应如何在TreeView
中控制呢?
我想控制它的 OnClick事件形成一个新的OnClickCheck事件应如何处理?
谢了。
 
在Protected中覆盖TCustomTreeView的MouseDown方法:
procedure MouseDown(Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
dynamic;
在其中调用GetNodeAt方法得到改点所在的节点,然后再处理....
记住处理MouseDown时首先inherited;
....
 
虽然大家的意见都很好,但一切都随计划的放弃而失去作用。
不过还是多谢朋友们,在这个问题中我学了很多东西。
 
后退
顶部