2012年7月6日星期五

【转】Delphi实现DBGrid列宽度自动调整

大多数程序设计的爱好者选择并使用Delphi来编写软件,都是被其中丰富而功能强大的VCL控件所吸引。Delphi自带的数据感知(Data- Aware)控件,更是成为开发MIS软件的程序员之首选。在那么多数据感知控件中,TDBGrid由于其使用方便、显示信息量大成为最引人注目的一员, 大量的国内外软件中都出现了它的身影。或许是由于使用的人多了,对于它的期望也会更高,永远追求无限趋向于完美境界的程序员不会放过每一个能够改良 TDBGrid的机会。

经常使用TDBGrid的用户都知道,它没有提供这样的一种选择,使得我们能够让它的每一列与所要显示的数据的宽度相匹配。使得用户需要在程序运行时,手工对每一列进行调整,在下次运行这个程序时又得再做一遍同样的工作(图1)。

在进行修改后,我们可以得到一个更加智能化的TDBGrid,如果TDBGrid中所有列的宽度加起来大于它本身的宽度,那么智能化的 TDBGrid将会在它所含的最后一列的右边留出空白(见图2);反之如果TDBGrid中所有列的宽度加起来小于它本身的宽度,则会在它的下部显示一个 水平滚动条,用户就可以左右拖动该滚动条,显示更多想要的内容。

解决方案:

在本文中我将提供一个简便的过程(Procedure)来解决上面的问题,它能够在程序运行时自动固定TDBGrid中所显示列的宽度。

首先,在TForm的OnCreate事件中添加下面的代码:

Procedure TForm1.FormCreate(Sender: TObject);
  begin
  //在Tag属性中设置需要自动调整的列的最小宽度(固定值)
  //这里将列宽值设为40px
  Table1.FieldByName('FirstName').Tag := 40;
  //这里设置一个变化的值
  //该值是做过运算的列标题的宽度值
  Table1.FieldByName('LastName').Tag := 4 + Canvas.TextWidth( Table1.FieldByName('LastName').DisplayName);
end;

其次,最关键的一个过程(Procedure),就是用它来控制列的宽度:

Procedure FixDBGridColumnsWidth(const DBGrid: TDBGrid);
var
  i : integer;
  TotWidth : integer;//定义整个宽度
  VarWidth : integer;//定义变化的宽度
  ResizableColumnCount : integer;//定义变化宽度列的总数
  AColumn : TColumn;
begin
  //在重新调整前所有列的宽度
  TotWidth := 0;
  VarWidth := 0;
  //有多少列需要自动调整
  ResizableColumnCount := 0;
  for i := 0 to -1 + DBGrid.Columns.Count do
  begin
   TotWidth := TotWidth + DBGrid.Columns[i].Width;
   if DBGrid.Columns[i].Field.Tag <> 0 then
    Inc(ResizableColumnCount);
  end;
  //为每个列分隔线增加1PX
  if dgColLines in DBGrid.Options then
   TotWidth := TotWidth + DBGrid.Columns.Count;
  if dgIndicator in DBGrid.Options then
   TotWidth := TotWidth + IndicatorWidth;
  VarWidth := DBGrid.ClientWidth - TotWidth;
  //平均分配变化宽度的值
  //给所有需要自动调整的列
  if ResizableColumnCount > 0 then
   VarWidth := varWidth div ResizableColumnCount;
  for i := 0 to -1 + DBGrid.Columns.Count do
  begin
   AColumn := DBGrid.Columns[i];
   if AColumn.Field.Tag <> 0 then
   begin
    AColumn.Width := AColumn.Width + VarWidth;
    if AColumn.Width < AColumn.Field.Tag then
     AColumn.Width := AColumn.Field.Tag;
   end;
  end;
end;

最后,应用这一个函数:

Procedure TForm1.FormResize(Sender: TObject);
begin
  FixDBGridColumnsWidth(DBGrid1);
end;

上面一个简单的函数解决了经常会碰到的关于数据列的问题,遇到问题时多多开动脑筋,而不要一味的去找第三方控件,这样长期坚持下去就会真正提高自己的水平,才会从一名程序泥水匠变成真正的软件设计师。

摘自:http://www.bianceng.cn/Programming/Delphi/200710/4777.htm

2012年7月3日星期二

【转】delphi 播放声音 建议采用 异步方式,比较流畅

2008-06-06 08:57
//声明:  sndPlaySound(    lpszSoundName: PChar; {声音文件}    uFlags: UINT{播放选项}  ): BOOL;    //uFlags 参数可选值:  SND_SYNC      = 0; {同步播放, 程序须等到播放完毕才向下执行}  SND_ASYNC     = 1; {异步播放, 在函数返回之后开始播放, 不影响程序继续执行}  SND_NODEFAULT = 2; {声音文件缺失时, 函数自动返回不播放默认声音}  SND_MEMORY    = 4; {播放内存中的声音, 譬如资源文件中的声音}  SND_LOOP      = 8; {循环播放, 需要和 SND_ASYNC 组合使用}  SND_NOSTOP    = 16;{如果当前正在播放声音, 立即返回 False}  
//举例: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} uses MMSystem; {sndPlaySound 声明在该单元} const s = 'C:\WINDOWS\Media\Windows XP 启动.wav'; //同步播放 procedure TForm1.Button1Click(Sender: TObject); begin sndPlaySound(s, SND_SYNC); Beep; {播放完毕才会执行这句} end; //异步播放 procedure TForm1.Button2Click(Sender: TObject); begin sndPlaySound(s, SND_ASYNC); Beep; {马上会执行这句} end; //反复播放 procedure TForm1.Button3Click(Sender: TObject); begin sndPlaySound(s, SND_LOOP or SND_ASYNC); end; end.
//sndPlaySound 也可以用来播放资源或内存中的声音文件, 参加示例:
http://www.cnblogs.com/del/archive/2008/02/15/1069523.html

【转】学习使用资源文件[9] - WAVE 资源

//rc 文件:  sound1 WAVE "SoundFile1.wav"  sound2 WAVE "SoundFile2.wav"  
//代码: unit Unit1; interface uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,   Dialogs, StdCtrls; type   TForm1 = class(TForm)     Button1: TButton;     Button2: TButton;     procedure Button1Click(Sender: TObject);     procedure Button2Click(Sender: TObject);   end; var   Form1: TForm1; implementation {$R *.dfm} uses MMSystem; {下面用到的 sndPlaySound、PlaySound 都是在此单元声明的} procedure TForm1.Button1Click(Sender: TObject); var   rs: TResourceStream; begin   rs := TResourceStream.Create(HInstance, 'sound1', 'WAVE');   sndPlaySound(rs.Memory, SND_ASYNC or SND_MEMORY);   rs.Free; end; procedure TForm1.Button2Click(Sender: TObject); var   rs: TResourceStream; begin   rs := TResourceStream.Create(HInstance, 'sound2', 'WAVE');   PlaySound(rs.Memory, HInstance, SND_ASYNC or SND_MEMORY);   rs.Free; end; end.

摘自:http://www.cnblogs.com/del/archive/2008/02/15/1069523.html

2012年7月2日星期一

【转】Delphi 枚举类型元素个数的确定方法

  枚举类型属于序数类型,但我们有时需要确定我们定义的枚举类型中的元素个数,也就是枚举类型的取值范围,但讨论这个问题的前提是“不要指定枚举元素的初始值”时才有意义。在 Delphi 中有两种方法可以做到:

方法一:使用 RTTI

  利用 TypInfo 单元的 GetEnumName() 和 GetEnumValue() 可以遍历任意枚举类型,并获取其名称和值。如果枚举类型指定初始值,将不具备 RTTI 能力,所以不要指定初始值。

uses TypInfo;

procedure TForm1.BtnTestClick(Sender: TObject);
var
    p: PTypeData;
    i: Integer;
    s: String;
    pt: PTypeInfo;
begin
    ListBox1.Items.Clear;
    pt := TypeInfo(TWindowState);
    if pt.Kind <> tkEnumeration then begin
        ShowMessage('不是枚举类型');
        Exit;
    end;

    p := GetTypeData(TypeInfo(TWindowState));

    //将获取的枚举类型信息,以“枚举名 = 枚举值” 的形式加入到 ListBox 中
    ListBox1.Items.beginUpdate;
    try
        for i := p.MinValue to p.MaxValue do begin
            S := GetEnumName(pt,i);
            ListBox1.Items.Values[S] := IntToStr(GetEnumValue(pt, S));
        end;
    finally
        ListBox1.Items.EndUpdate;
    end;
end;

使用 RTTI,速度会慢一些,如果整个程序在运行过程中并不需要 RTTI,可以使用下面的方法。



方法二: 使用 Low(),High(),Ord() 系统函数。使用该方法依然不要指定枚举元素初始值。

type
    TEnum = (a,b,c);

const
    Min = Low(TEnum);
    Max = High(TEnum);

    Count = Ord(Max) + 1;

procedure TForm1.Button1Click(Sender: TObject);
var
    i,j: Integer;
begin
    i := Ord(Min);
    j := Ord(Max);

    ShowMessage(IntToStr(i) + ' ' + IntToStr(j) + ' ' + IntToStr(Count));
end;


摘自:http://apps.hi.baidu.com/share/detail/16452783

2012年7月1日星期日

【转】delphi:语音合成之SpVoiceClass详解

AlertBoundary
取得或设置停顿分界线。

AllowAudioOutputFormatChangesOnNextSet
设置是否允许声音自动调整到合适状态以适应其音频输出。

AudioOutput
.取得或设置当前声音使用的的音频输出对象

AudioOutputStream
取得或设置当前声音使用的的音频输出流对象。

EventInterests
取得或设置当前声音返回的事件类型。

Priority
取得或设置声音的优先级。

Rate
取得或设置阅读的速度。

Status
返回一个ISpeechVoiceStatus 对象用于显示当前阅读和事件的状态

SynchronousSpeakTimeout
取得或设置一个时间间隔,用于标识多久未获得一个输出设备后,一个同步的Speak 和SpeakStream将终止,以毫秒计算。

Voice
取得或设置发音对象。

Volume
取得或设置声音的大小 。




方法
描述

DisplayUI
是否在控制面板中展示详细设置。

GetAudioOutputs
返回一个可用的音频输出标记。

GetVoices
返回一个可用的发音对象。

IsUISupported
决定是否能通过控制棉板的音频设置来控制。

Pause
暂停朗读。.

Resume
恢复暂停,继续播放。

Skip
在当前输入的文本流中向前或向后跳一定距离再播放。

Speak
阅读一个字符串。

SpeakCompleteEvent
得到一个朗读完毕的时间句柄

SpeakStream
朗读一个文本流或一个声音文件。

WaitUntilDone
阻塞进程,直到声音播放完毕或者超时。.

摘自:http://hi.baidu.com/xiaoxiaolq/blog/item/a42fc7ca7e6e854cf31fe7e8.html

【转】将文本保存为音频文件(wav)的方法

★★将文本保存为音频文件(wav)的方法
准备控件:SpVoice,SpFileStream,SaveDialog,Button
Procedure   TForm1.Button.click(sender:TObject);
begin
  savedialog.filter:= 'wave文件|*.wav ';
  if   savedialog.execute   then
    begin
      spfilestream.format.type_:=SAFT32KHz8BitMono;
      spfilestream.open(savedialog1.filename,SSFMCreateForWrite,False);
      SpVoice.allowAudioOutputFormatChangesOnNextSet:=false;
      Spvoice.AudioOutputStream:=SpFilestream.defaultInterface;
      SpVoice.Speak( '祝CSDN的朋友工作顺利! ',1);
      SpVoice.waitUntilDone(-1);
      Spfilestream.close;
    end;
end;

摘自:http://topic.csdn.net/t/20031110/14/2445499.html 【8楼】

[转]DELPHI VCL 控件如何卸载?

附带通用控件安装方法:
----------------------------------------------------------------
基本安装
1、对于单个控件,Componet--> install   component..--> PAS或DCU文件--> install;
2、对于带*.dpk文件的控件包,File--> Open(下拉列表框中选*.dpk)--> install即可;
3、对于带*.bpl文件的控件包,Install   Packages--> Add--> bpl文件名即可;
4、如果以上Install按钮为失效的话,试试Compile按钮;
5、是run   time   lib则在option下的packages下的runtimepackes加之。
        如果编译时提示文件找不到的话,一般是控件的安装目录不在Delphi的Lib目录中,有两种方法可以解决:
1、反安装的源文件拷入到Delphi的Lib目录下;
2、或者Tools--> Environment   Options中把控件源代码路径加入到Delphi的Lib目录中即可。
注意:所安装的控件是否与你所用的Delphi版本相适应。
----------------------------------------------------------------
控件删除
在Component/Install   Packages中删除。  
选Component/configure   Palette…
有pages和components两个区域
双击components区域,选中要删除得控件,下面有得Delete按钮
但系统提供的控件只能Hide,不能delete。
打开控件所在的包文件(*.dpk),从中删除控件那个文件,再重新编译该包即可。
如果是整个控件包都要删除的话,project-> Option-> Packages,删掉那个packages,收工。

摘自:http://topic.csdn.net/t/20041027/23/3497655.html