Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

How to redirect click events to my frame.

Posted on 2006-05-22
13
Medium Priority
?
513 Views
Last Modified: 2010-04-05
How can I make sure that a click anywhere in a form will be handled by a TFrame descendant that I am placing on a form? I am using a frame to trigger a TListBox to pop up as a suggestion list. At present, if the list box is showing and the user clicks on a speedbutton, the OnExit events I'm using to free the listbox, aren't triggered.

I've noticed that combo boxes seem to direct all clicks to themselves. If the drop-down part is showing, you have to click twice to press a speed button. The first click releases the form from the grip of the combo box, and the following one does what you want. A solution like that would be good enough.

Regards,

Mark
0
Comment
Question by:markaurelius
  • 5
  • 4
  • 2
11 Comments
 
LVL 20

Expert Comment

by:Mark Brady
ID: 16740265
Can you post an exxample of your form and explain exactly what you need to achieve ?  I half understand you but there is something missing in your explanation I think.  Thanks

Elvin
0
 
LVL 1

Author Comment

by:markaurelius
ID: 16740318
I can't really include a lot of code, it's commercially sensitive and quite long.

I'll try to make it clearer. I'm searching through a database. The main component of the frame I am talking about it a TEdit, into which the user enters a filter. On each OnChange event, the query is rerun and a TListBox pops up, with the form as the parent to allow it to overlay other parts of the form like the drop-down list in a combobox.

I'm using a frame because this sort of thing is going to be used in a number of places in the project. When the box is showing the user is either editing the TEdit or scrolling around in the list box. If they click anywhere outside those 2 I want the listbox to be removed. This is the behaviour of comboboxes, so would be more familiar than the present sticky list box, which hangs around if you click on a speedbutton. I am clearing the box at present in the OnExit events of the TEdit and TListBox, but speedbuttons don't trigger OnExit events.

Here's the code attached to the OnExit handler of the TListBox:

procedure TfaProjNum.BoxExit(Sender: TObject);
begin
  if GetParentForm(Self).ActiveControl <> edtProjNum then begin
    CloseBox;
  end{if};
end;// BoxExit -----------

Similarly the OnExit code for the TEdit is this:

procedure TfaProjNum.edtProjNumExit(Sender: TObject);
begin
  if GetParentForm(Self).ActiveControl <> box then begin
    CloseBox;
  end{if};
end;// edtProjNumExit -------------

I hope that clarifies what I'm trying to do.

Regards,

Mark
0
 
LVL 20

Expert Comment

by:Mark Brady
ID: 16740339
I just did a quick test using what you stated above. This is what I understand you want.

Once you leave the listbox and the focus goes to another control (eg: speedbutton) you want it to behave like a combobox....click speedbutton once so the listbox loses focus and runs the onexit events, then click speedbutton again to run the events for the button ?    Is that what you wanted ?

Or do you want to click anywhere on the blank part of a frame and have the listboxx run it's exit events ?  If so, then you can do somthing like this sample.............


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    ListBox1: TListBox;
    Button1: TButton;
    procedure ListBox1Exit(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Panel1Click(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ListBox1Exit(Sender: TObject);
begin
showmessage ('listbox lost focus');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
showmessage ('Your code goes here');
end;



procedure TForm1.Panel1Click(Sender: TObject);
begin
button1.SetFocus;
end;

end.


//now the form

object Form1: TForm1
  Left = 189
  Top = 114
  Width = 353
  Height = 348
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Panel1: TPanel
    Left = 0
    Top = 0
    Width = 345
    Height = 313
    Caption = 'Panel1'
    TabOrder = 0
    OnClick = Panel1Click
    object ListBox1: TListBox
      Left = 64
      Top = 16
      Width = 121
      Height = 65
      ItemHeight = 13
      Items.Strings = (
        'item1'
        'item2'
        'item3'
        'item4'
        'item5'
        'item6'
        'item7'
        'item8'
        'item9'
        'item10')
      TabOrder = 0
      OnExit = ListBox1Exit
    end
    object Button1: TButton
      Left = 96
      Top = 200
      Width = 75
      Height = 25
      Caption = 'Button1'
      TabOrder = 1
      OnClick = Button1Click
    end
  end
end

//  Now once the listbox loses focus by clicking anywhere in the panel on form1 then it triggers the onexit event for your listbox.


Elvin
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 1

Author Comment

by:markaurelius
ID: 16740362
The problem is that clicking on a TSpeedButton, or TLabel, or anything that is not descended from TWinControl, doesn't trigger OnExit. Such components can't take the focus.

It's not about clicking anywhere in the _TFrame_. The frame is just a convenient way to encapsulate the behaviour I'm after. It consists of one TEdit, and that's it. I need to know how else to signal, via the frame (used to encapsulate the code) that the user has clicked anywhere else on the Form or even the screen for that matter. Comboboxes do it somehow,so it must be possible.

Regards,

Mark
0
 
LVL 20

Expert Comment

by:Mark Brady
ID: 16740448
Yes but those components do have onclick events so why don't you use them like this...
//eg

TForm1.Panel1Click
if listbox1.Focused then
listbox1exit(sender);     //  put you exxit code name here
end;   //this forces the listboxx to lose focus without assigning focus to another control (in my case a button)


//  Using a label like this......

procedure TForm1.Label1Click(Sender: TObject);
begin
if listbox1.Focused then
button1.SetFocus;
end;                       // would transfer focus to the button which automatically triggers the listbox onexit event.



Am I getting close ?
0
 
LVL 1

Author Comment

by:markaurelius
ID: 16740469
No, you aren't on the right track. The thing I am doing works in most cases. The essential thing is with TSpeedButton instances, not TButton or any other control that descends from TWinControl, just TSpeedButton. WHen you click on a TSpeedButton, it doesn't shift focus. Focus can stay on the list box that I want to close down. So you move the mouse cursor away from the TEdit / TListBox area, click on something, and the TListBox remains. But if I do a Tab onto another TEdit, the OnExit on the TListBox is called, and it gets cleared.

Thanks for trying, but it's the distinction between TSpeedButton and other types of control that is the essential thing.
0
 
LVL 20

Expert Comment

by:Mark Brady
ID: 16740476
Ok sorry about that.  then why can't you place some code on the onclick event for the tSpeedbutton to force a change in focus therefore running your exit event ?

Elvin
0
 
LVL 20

Expert Comment

by:Mark Brady
ID: 16740508
two final questions...

When you are finished with the listbox what do you want to click on ?

Do you want focus to shift to another control as it does when you use the tab key ?
0
 
LVL 1

Author Comment

by:markaurelius
ID: 16741768
I could solve the immediate problem by tacking code into the handlers of the TSpeedbuttons, but I don't do that for each TComboBox I use. I'm using a TFrame to encapsulate the coding for this class, so that there is nothing else to think about - you just add the frame to your form, and it all works correctly.

When the list box closes I am just leaving the focus where it happens to be at present, that's not a problem.
0
 
LVL 35

Expert Comment

by:Slick812
ID: 16745909
hello markaurelius , , you mention a combo box dropdown listbox as having the reaction that you want. .  a system combo, drop-down list box is a "Pop-Up" window (like a TForm), it is not a "Child" control, and this pop-up list box will destroy itself, once it loses key-board focus (activation), so clicking anywhere off it or using Alt-Tab will kill the list-box, you might try that, it has worked for me
0
 
LVL 35

Accepted Solution

by:
Slick812 earned 500 total points
ID: 16746470
here is some code that may help? it is for the  TPopListBox, , which will hide itself if it loses focus



type
  TPopListBox = class(TListBox)
    private
    procedure WMActivate(var Message: TMessage); message WM_ACTIVATE;
    procedure WMLButtonUP(var Message: TMessage); message WM_LBUTTONUP;

    protected
    procedure CreateParams(var Params: TCreateParams); override;
    end;

implementation

procedure TPopListBox.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
  Style := (WS_POPUP or Style) and not WS_CHILD;
end;

procedure TPopListBox.WMActivate(var Message: TMessage);
begin
inherited;
if Message.WParamLo = WA_INACTIVE then
Hide;
end;

procedure TPopListBox.WMLButtonUP(var Message: TMessage);
begin
inherited;
Hide;
end;


 = = = = = = = = =  = = = = =  = = = = = =
below is code to use it -->



  TForm1 = class(TForm)
  private
    { Private declarations }
    PopListBox1: TPopListBox;
    hLBox: THandle;


// below is a button Click code to show the PopListBox
procedure TForm1.but_PopListBoxClick(Sender: TObject);
var
Pnt1: TPoint;
begin
Pnt1.y := but_PopListBox.Top+8;
Pnt1.x := but_PopListBox.Left+12;
windows.ClientToScreen(Handle, Pnt1);
if not IsWindow(hLBox) then
  begin
  PopListBox1 := TPopListBox.Create(Self);
  with PopListBox1 do
    begin
    Parent := Panel1{Self}; // you may want to make the Parent a windowed control that does NOT scroll
    SetBounds(Pnt1.x, Pnt1.y, 100, 60);
    Items.Add('Top');
    Items.Add('Middle');
    Items.Add('Low');
    SetFocus;
    hLBox := Handle;
    end;
  end else
  with PopListBox1 do
    begin
    SetBounds(Pnt1.x, Pnt1.y, Width, Height);
    Show;
    SetFocus;
    end;
end;
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

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

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
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…
Is your OST file inaccessible, Need to transfer OST file from one computer to another? Want to convert OST file to PST? If the answer to any of the above question is yes, then look no further. With the help of Stellar OST to PST Converter, you can e…
As many of you are aware about Scanpst.exe utility which is owned by Microsoft itself to repair inaccessible or damaged PST files, but the question is do you really think Scanpst.exe is capable to repair all sorts of PST related corruption issues?
Suggested Courses

578 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