请教高手:关于显示/隐藏 DBGrid 列的问题---急!!! ( 积分: 50 )

M

muree

Unregistered / Unconfirmed
GUEST, unregistred user!
如果想通过 PopupMenu 的菜单控制 DBGrid 中各列的显示/隐藏,如 PopupMenu 的三个菜单:编号、姓名、工资(Caption属性)的 Name(控件名称) 分别为 N1、N2、N3,控制 DBGrid 中的对应列。我在 N1、N2、N3 共用的 OnClick 事件中写了一部分程序(想了点小方法,先在界面设计阶段将 N1、N2、N3 的 Tag 分别设置为 100、101、102),如下:

procedure TForm1.N1Click(Sender: TObject);
...
(Sender as TMenuItem).Checked := not (Sender as TMenuItem).Checked;
//if Sender = N1 then DBGrid1.Columns[0].Visible := N1.Checked;
//if Sender = N2 then DBGrid1.Columns[1].Visible := N2.Checked;
//if Sender = N3 then DBGrid1.Columns[2].Visible := N3.Checked;
//以下是简化的小方法
DBGrid1.Columns[(Sender as TMenuItem).Tag - 100].Visible := (Sender as TMenuItem).Checked;
...

这在 DBGrid 的各列没有拖动(变换位置)时可行得通,但在拖动后就对应不起来了。主要是 DBGrid 的各列不是一个单独的控件,没有象 N1、N2、N3 一样有固定的控件名称来对应控制 Visible 属性。如果再增加点难度,有另两个按钮 Button1、Button2 的显示/隐藏对应与 DBGrid 中姓名、工资列的显示/隐藏完全一致,该如何操作?
好象有一种方法,在 DBGrid 的 OnColumnMoved 事件中,按照 DBGrid 拖动后各列的位置生成对应的菜单,如 DBGrid 的列排列为:工资、编号、姓名,PopupMenu 从上到下的排序也如此(可以在 TCheckListBox 中这样实现),但不知具体如何在 PopupMenu 中实现?是不是每次要动态创建 N1、N2、N3,又要动态释放?且如果 PopupMenu 的三个菜单:编号、姓名、工资保持不变,而要显示/隐藏已经拖动后的 DBGrid 对应列,又该怎么办?请高手多指教!!!
 
1、要按顺序排列PopupMenu的话,我是用动态生成MenuItem的
procedure TForm1.PopupMenu1Popup(Sender: TObject);
var
MenuItem: TMenuItem;
I: Integer;
begin
PopupMenu1.Items.Clear;
for I := 0 to DBGrid1.Columns.Count - 1 do
begin
MenuItem := TMenuItem.Create(PopupMenu1);
with MenuItem do
begin
AutoCheck := True;
Caption := DBGrid1.Columns.Title.Caption;
Checked := DBGrid1.Columns.Visible;
Tag := DBGrid1.Columns.ID + 100;
OnClick := MenuItemClick;
end;
PopupMenu1.Items.Add(MenuItem);
end;
end;

2、TColumn有一个不变的ID,这是创建时候获取的,就算移动顺序之后其值也不变
就用你的Tag方法:
var
Col: TColumn;
begin
Col := TColumn(DBGrid1.Columns.FindItemID((Sender as TMenuItem).Tag - 100));
Col.Visible := (Sender as TMenuItem).Checked;
end;
 
To ANiDelphi:
谢谢!可是我复制你的代码去运行,发现 OnClick := MenuItemClick; 这条语句会出错,且你的 2、里面的代码应该是在 TMenuItem 的 OnClick 里执行,可这 OnClick 事件该写在哪里?
另外,MenuItem := TMenuItem.Create(PopupMenu1);创建后,要不要释放资源?
 
To ANiDelphi:
上面的第一个问题我试出来了,第二个问题继续,就是要不要释放资源?
 
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Grids, DBGrids, Menus;

type
TForm1 = class(TForm)
PopupMenu1: TPopupMenu;
DBGrid1: TDBGrid;
procedure PopupMenu1Popup(Sender: TObject);
private
procedure MenuItemClick(Sender: TObject);
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.MenuItemClick(Sender: TObject);
begin
with DBGrid1.Columns[TMenuItem(Sender).MenuIndex] do
Visible := not Visible;
end;

procedure TForm1.PopupMenu1Popup(Sender: TObject);
var
MenuItem: TMenuItem;
I: Integer;
begin
PopupMenu1.Items.Clear; //这里已经释放了原有的MenuItem
for I := 0 to DBGrid1.Columns.Count - 1 do
begin
MenuItem := TMenuItem.Create(PopupMenu1);
with MenuItem do
begin
Caption := DBGrid1.Columns.Title.Caption;
Checked := DBGrid1.Columns.Visible;
OnClick := MenuItemClick;
end;
PopupMenu1.Items.Add(MenuItem);
end;
end;

end.

不用释放资源。MenuItem := TMenuItem.Create(PopupMenu1);说明MenuItem的资源是PopupMenu1负责释放的,也就是说当PopupMenu1.Free时会将PopupMenu1所有的MenuItem都Free了,而PopupMenu1则由其Owner(Form1)负责释放。
如果使用MenuItem := TMenuItem.Create(nil); 来创建MenuItem的话,就要自己手动释放资源了,可以在Form1的OnDestroy事件中调用PopupMenu1.Items.Clear来释放资源
 
第二段程序没用到 MenuItem.Tag,更简洁了,非常感谢高手 ANiDelphi,这分是给定你了,可还有几个小问题再请教一个,呵呵,问题越来越多了[:)]
1、MenuItemClick 为什么要放在 private 里?
2、你的第一个回复里有 AutoCheck := True; 而第二个回复里没有,我当时发现第一个回复里如果没有的话,当 MenuItemClick 时 MenuItem 前面的对勾不会取消,而第二个回复里为什么没有就行了呢?
3、TMenuItem(Sender) 和 (Sender as TMenuItem) 有什么区别?
4、MenuItem 由其 Owner(PopupMenu1) 负责释放,而 PopupMenu1 由其 Owner(Form1) 负责释放,那 MenuItem 是不是在 Form1Destroy 才释放掉?可每次 PopupMenu1Popup 都要创建 MenuItem,这不是没释放掉又重新创建了吗?你的解释是每次创建之前 PopupMenu1.Items.Clear; 就释放了 MenuItem 资源,我想问问不是通过 MenuItem.Free; 这语句释放资源的吗?还有每个控件可由其 Owner 负责释放,是指其 Owner 释放掉它才释放,还是其 Owner 可以随时控制它的释放?
5、还有几个问题,你如有空,也请帮忙,照样送分,当然我想大虾是更注重解人忧难、救人危急的虾精(侠义精神,呵呵),我非常感谢!
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3819512
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3815384
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3819464
 
屬性裏設置一下吧。不會有這麽麻煩吧。
 
你既然这样,可以直接把列的Tag设成1,2,3,菜单的tag也对应设为123,然后在菜单点击里,显示相应tag的列,岂不简单?创建菜单可以动态,窗口释放再释放它.
 
1、MenuItemClick 为什么要放在 private 里?
这个没什么特别,放到protected、public、published里都没问题,就是其可见范围不同。

2、你的第一个回复里有 AutoCheck := True; 而第二个回复里没有,我当时发现第一个回复里如果没有的话,当 MenuItemClick 时 MenuItem 前面的对勾不会取消,而第二个回复里为什么没有就行了呢?
第一个回复里有 AutoCheck := True;是因为你的MenuItemClick中用了DBGrid1.Columns[(Sender as TMenuItem).Tag - 100].Visible := (Sender as TMenuItem).Checked;用到了MenuItem的Checked属性;
第二个回复里没有,也一样,是因为我的MenuItemClick中没有用到MenuItem的Checked属性

3、TMenuItem(Sender) 和 (Sender as TMenuItem) 有什么区别?
这个我也不太清楚,效果差不多,好象一个是强制类型转换,不知道在哪看过忘了。:)

4、MenuItem 由其 Owner(PopupMenu1) 负责释放,而 PopupMenu1 由其 Owner(Form1) 负责释放,那 MenuItem 是不是在 Form1Destroy 才释放掉?可每次 PopupMenu1Popup 都要创建 MenuItem,这不是没释放掉又重新创建了吗?你的解释是每次创建之前 PopupMenu1.Items.Clear; 就释放了 MenuItem 资源,我想问问不是通过 MenuItem.Free; 这语句释放资源的吗?还有每个控件可由其 Owner 负责释放,是指其 Owner 释放掉它才释放,还是其 Owner 可以随时控制它的释放?
PopupMenu1.Items.Clear;这个过程里就调用了Items.Free;逐个释放了所有MenuItem;我个人觉得(我不是学计算机专业的,自己看了点书)应该是这样的:退出程序时,Application.Free;这个过程中就逐个释放Owner为Application的Component,其中就有Form1,即Form1.Free。而在Form1.Free这个过程中又调用了PopupMenu1.Free。PopupMenu1.Free这个过程又调用MenuItem.Free。一层层往下全部Free。

5、还有几个问题,你如有空,也请帮忙,照样送分,当然我想大虾是更注重解人忧难、救人危急的虾精(侠义精神,呵呵),我非常感谢!
这几个问题都帮不上忙:(
 
再次感谢 ANiDelphi,送分结贴!
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
638
import
I
D
回复
0
查看
2K
DelphiTeacher的专栏
D
I
回复
0
查看
624
import
I
顶部