Solved

I want to customize combobox dropdown list

Posted on 2001-08-23
11
418 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
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

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

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

757 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

19 Experts available now in Live!

Get 1:1 Help Now