Solved

I want to customize combobox dropdown list

Posted on 2001-08-23
11
422 Views
Last Modified: 2010-04-06
I'm in the process of creating a DB aware component called TDBLookupEntry.
It is based on a TCustomPanel and contains a TEdit, TEdit and TSpeedButton so it looks like:
 -------------------
|EDIT1||EDIT2    |SB|
 -------------------
EDIT1 will be for a code and EDIT2 will be for a description so the user can enter either to find his record.

I currently have the Speedbutton dropping down a TForm with a TDBGrid with various techniques to keep setting the focus back to the form that contains the TDBLookupEntry but 1. the forms captions keeps flashing and 2. it doesn't set the focus back when the user uses the scrollbar on the TDBGrid and 3. you can move the form that contains the TDBLookupEntry and the dropdown form stays where it is.

After all the above said, I don't think its the way I want to go...I would much prefer to use the same method that the Internet Explorer 'address' combobox uses, ie. you can type a partial entry into the address, it drops down the list and you can cursor up/down, use the lists' scrollbar (and sizegrip) but the caret is still focused in the 'address' edit box and also when you click anywhere else it disappears.

Can any one point me in the right direction with tips/WinAPI.
Points awarded for best help...

Thanks
0
Comment
Question by:djadja
  • 6
  • 5
11 Comments
 
LVL 9

Expert Comment

by:ITugay
ID: 6421130
Hi djadja,

you can dowload TDBFieldsGrid component with the source code, there is code that allow you to  simulate dropped down combobox. Take a look at TConstBox there.

http://i-g-o-r.virtualave.net/

------
Igor.
0
 

Author Comment

by:djadja
ID: 6421412
Using Delphi 5 and without hacking the unit about I can't compile and run the demo :(

Maybe there is someway of setting a Form/window to not allow activation, eg. like a TPopupMenu (it can overlap its parent window and even though it accepts focus it doesn't 'activate' it)?
0
 

Author Comment

by:djadja
ID: 6421444
Using Delphi 5 and without hacking the unit about I can't compile and run the demo :(

Maybe there is someway of setting a Form/window to not allow activation, eg. like a TPopupMenu (it can overlap its parent window and even though it accepts focus it doesn't 'activate' it)?
0
 
LVL 9

Expert Comment

by:ITugay
ID: 6421494
Hi djadja,

here is "extraction" from one of my unit. It demonstrate how to show some control without loosing focus on current form.

------
Igor.

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Grids, Buttons, StdCtrls;

type
  TDropGrid = class(TStringGrid)
  private
    FLastClick: Integer;
  protected
    procedure WndProc(var M: TMessage); override;
    procedure CreateWnd; override;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure DropDown;
    procedure CloseUp(Ready: Boolean);

  public
  published
  end;

  TForm1 = class(TForm)
    SpeedButton1: TSpeedButton;
    Edit1: TEdit;
    Edit2: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
  private
    { Private declarations }
  public
    { Public declarations }
    G: TDropGrid;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}


procedure TDropGrid.WndProc(var M: TMessage);
begin
  if M.Msg = WM_LBUTTONDBLCLK then
  begin
    CloseUp(True);
    exit;
  end;

  if (M.Msg = WM_LBUTTONDOWN) or
    (M.Msg = WM_NCLBUTTONDOWN) then
     FLastClick := GetTickCount;

  if (M.Msg = 45060) and
    (FLastClick + 100 < GetTickCount) then
      CloseUp(False);

  inherited;
end;

procedure TDropGrid.CloseUp(Ready: Boolean);
begin
  Visible := False;
end;

procedure TDropGrid.CreateWnd;
begin
  Inherited;
  windows.SetParent(Handle, 0);
end;

procedure TDropGrid.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.ExStyle := WS_EX_TOOLWINDOW;
end;

procedure TDropGrid.DropDown;
begin
  SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0,
    SWP_SHOWWINDOW or SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
  Visible := True;
  SetFocus;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  G := TDropGrid.Create(Self);
  G.Visible := False;
  G.Parent := Self;
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  G.DropDown;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if G.Visible then
  begin
    G.KeyDown(Key, Shift);
    Key := 0;
  end;

end;

end.
0
 
LVL 9

Expert Comment

by:ITugay
ID: 6421503
Hi djadja,

in previous sample Form1.KeyPreview should be True. It allow to redirect key events to "dropped down" control.

Control has ability to hide itself if you click mouse outside of control.

-----
Igor.
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 

Author Comment

by:djadja
ID: 6421607
>>Control has ability to hide itself if you click mouse outside of control.
I couldn't get this to happen - does it have something to do with...
 if (M.Msg = 45060) and
   (FLastClick + 100 < GetTickCount) then
     CloseUp(False);
I couldn't find the value in Messages.pas?! Can you explain this to me also if I click on the Parent of the TEdit form caption, hold and move I can move the Form and the TDropGrid form stays where it is :( PS. The points will be yours as everything else works a treat!

To get this straight in my head/help someone in the future) can I just confirm these...

1. You set the Parent of the DropGrid via vcl property and then use the Windows API SetParent to display it on the desktop. Very clever.

2. I had to set the AutoScroll = False for the edit's parent form otherwise scrollbars kept appearing (if the edit's parent is smaller than the 'dropdown').

3. I have changed the TDropGrid to be based on a TForm to allow any number of controls within it but had do a few other things...

type
 TDropGrid = class(TForm)

procedure TDropGrid.CreateParams(var Params: TCreateParams);
begin
 inherited CreateParams(Params);
 Params.Style:=Params.Style and (not WS_CAPTION);  // remove the form's caption
 Params.ExStyle := WS_EX_TOOLWINDOW;  // this is to stop control appearing on the taskbar
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 G := TDropGrid.CreateNew(Self);  // .create complains about missing DFM's
 G.Visible := False;
 G.Parent := Self;
 with TStringGrid.Create(G) do begin  // added extra control
      Parent:=G;
  Align:=alClient;
 end;
end;

and set position etc.
0
 
LVL 9

Expert Comment

by:ITugay
ID: 6421657
Hi djadja,

45060 - message is unknown for me, I just found that it sended when I clicked  out of control. But this message also apears just after I clicked on scrollbars of control. So, I have to store time when scollbar was clicked and if 45060 message was sent immediatelly after it (time is less then 100ms) then control shouldn't be closed.

You are right about 1) and 2), but I'm not sure about 3).
The problem will be in TForm. It would be good to use TPanel instead ot TForm. Once I tried to use TForm and have no any positive results.

------
Igor.
0
 

Author Comment

by:djadja
ID: 6423973
45060 = CM_CANCELMODE             = CM_BASE + 4;
its a VCL message
The TForm worked fine but I've had other problems in the past with it so I've derived from TCustomControl.

Problem is now I've used the TCustomControl to hold a TDBGrid (alClient) and a TPanel (alBottom) for a drawn size grip - the WndProc code for cancelling the dropdow you posted doesn't work! I've spent approx 5 hours getting the scrollbars and grid clicking to work and eventually I managed via this method:
procedure TDBGridDropDown.WMVScroll(var Message: TWMVScroll);
var
  bOldAcquireFocus: Boolean;
begin
  bOldAcquireFocus:=fAcquireFocus;
  fAcquireFocus:=False;
  try
    inherited;
  finally
    fAcquireFocus:=bOldAcquireFocus;
  end;
end;

Same code for MouseDown (to handle clicking in grid)!

I've tried CaptureMouse but it stops the above code working. I think it's because it's using the VCL Parent stuff and hence doesn't work coordinates out properly for the scrollbar & grid.

Can you offer any more help <pretty please>?
0
 

Author Comment

by:djadja
ID: 6423979
Oops - sorry forgot to tell you that the TDBGridDropDown is inherited from TDBGrid (so I could set the fAcquireFocus to false) as it trys to DBGrid.SetFocus when you click in it/on the scrollbars.
0
 
LVL 9

Accepted Solution

by:
ITugay earned 200 total points
ID: 6424489
Hi,

I just wrote this part of code and seems it works for me. Take a look at this, may be you will get something usefull from there.

------
Igor.


  TDropControl = class(TCustomControl)
  private
    FLastClick: Integer;
    FStringGrid: TStringGrid;
    FSGWndProc: TWndMethod;
  protected
    procedure WndProc(var M: TMessage); override;
    procedure SGWndProc(var M: TMessage);
    procedure CreateWnd; override;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure DropDown;
    procedure CloseUp(Ready: Boolean);
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  public
    constructor Create(AOwner: TComponent); override;
  published
  end;

.....

constructor TDropControl.Create(AOwner: TComponent);
begin
  Inherited;
  Width := 200;
  Height := 200;

  FStringGrid := TStringGrid.Create(Self);
  FStringGrid.Align := alTop;
  FSGWndProc := FStringGrid.WindowProc;
  FStringGrid.WindowProc := SGWndProc;
  InsertControl(FStringGrid);
end;

procedure TDropControl.WndProc(var M: TMessage);
begin
  if M.Msg = WM_LBUTTONDBLCLK then
  begin
    CloseUp(True);
    exit;
  end;

  if (M.Msg = WM_LBUTTONDOWN) or
    (M.Msg = WM_NCLBUTTONDOWN) then
     FLastClick := GetTickCount;

  if (M.Msg = 45060) and
    (FLastClick + 100 < GetTickCount) then
      CloseUp(False);

  inherited;
end;

procedure TDropControl.SGWndProc(var M: TMessage);
begin
  if M.Msg = WM_LBUTTONDBLCLK then
  begin
    CloseUp(True);
    exit;
  end;

  if (M.Msg = WM_LBUTTONDOWN) or
    (M.Msg = WM_NCLBUTTONDOWN) then
     FLastClick := GetTickCount;

  if (M.Msg = 45060) and
    (FLastClick + 100 < GetTickCount) then
      CloseUp(False);

  FSGWndProc(M);
end;

procedure TDropControl.CloseUp(Ready: Boolean);
begin
  Visible := False;
end;

procedure TDropControl.CreateWnd;
begin
  Inherited;
  windows.SetParent(Handle, 0);
end;

procedure TDropControl.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.ExStyle := WS_EX_TOOLWINDOW;
end;

procedure TDropControl.DropDown;
begin
  SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0,
    SWP_SHOWWINDOW or SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
  Visible := True;
  SetFocus;
end;

procedure TDropControl.KeyDown(var Key: Word; Shift: TShiftState);
begin
  TDropControl(FStringGrid).KeyDown(Key, Shift);
  Inherited;
end;

....
procedure TForm1.FormCreate(Sender: TObject);
begin
  G := TDropControl.Create(Self);
  G.Visible := False;
  G.Parent := Self;
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  G.DropDown;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if G.Visible then
  begin
    G.KeyDown(Key, Shift);
    Key := 0;
  end;

end;

0
 

Author Comment

by:djadja
ID: 6447685
Still can't get the dropdown to cancel when you click outside but you answered the main question re separating the control from the main form so here you go...

PS. I've mailed you the component I'm still trying to get done in a hope you can fix it!
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
How to use Hibernate  and delphi ? Does anyone know any tutorial? 2 147
TVirtualStringTree  search using TEdit 7 106
Sending Gmail through Delphi 3 91
Delphi Form ownership 4 73
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
Internet Business Fax to Email Made Easy - With  eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, f…

863 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

25 Experts available now in Live!

Get 1:1 Help Now