2012-02-10 2 views
4

Я использую функцию SHAutoComplete() из функций легкой утилиты Shell , чтобы включить автоматическое завершение пути для редактирования полей в модальном диалоговом окне.Как проверить, отображается ли в настоящее время окно SHAutoComplete()?

Диалог должен закрываться при нажатии клавиши Esc, но только если автоматическое завершение не активировано.

Как проверить, отображается ли список завершения для сфокусированного элемента управления?

Edit:

Я использую Delphi 2009 на Windows XP 64. Код, отправленный Давидов

procedure TMyForm.FormKeyDown(Sender: TObject; var Key: Word; 
    Shift: TShiftState); 
begin 
    if Key = VK_ESCAPE then 
    ModalResult := mrCancel; 
end; 

не работает для меня - диалог закрывается.

+1

+1, хороший вопрос; Мне интересно, если кроме проверки, что 'IAutoComplete' показывает список, также можно [' invoke it'] (http://stackoverflow.com/q/9077396/960757) вручную. – TLama

+0

Итак, вы говорите, что в вашей программе прямо сейчас клавиша Esc отменяет окно автозаполнения * и * закрывает ваше диалоговое окно? Если это так, я удивлен, потому что объект автозаполнения уже обрабатывает сообщения клавиатуры, поэтому он должен знать, что не пересылать клавишу Esc после ее перехвата. –

+0

@Rob: Да, именно так. Я отключил свойство «Отменить» кнопки «Отмена» и вместо этого использовал «KeyPreview» и «OnKeyDown» формы, но он все равно вызывается, даже если сообщение Esc отменило список завершения. – mghie

ответ

1

Я не могу воспроизвести вашу проблему. Следующий обработчик OnKeyDown в сочетании с KeyPreview := True дает желаемое поведение в пустой форме.

procedure TMyForm.FormKeyDown(Sender: TObject; var Key: Word; 
    Shift: TShiftState); 
begin 
    if Key=VK_ESCAPE then 
    ModalResult := mrCancel; 
end; 

Я думаю, что в вашей форме есть что-то еще, что закрывает диалог.

4

Я пытался несколько систем, со странными результатами:

  • на моем ПК с Windows XP 64 Диалоговое окно закроется, а список обрывается вниз
  • на Windows XP Pro в виртуальной машине VMware диалоговое окно закрывается слишком

но

  • на моем ноутбуке с Windows 7 диалог лань ы не закрывать
  • на Windows 2000 Pro в виртуальной машине VMware диалоговое окно не закрывается

Поскольку это настолько хаотичным я решил написать небольшой компонент, который заставляет правильное поведение, даже если операционная система не обеспечить его.


Компонент может быть использован, как это:

procedure TForm2.FormCreate(Sender: TObject); 
const 
    SHACF_FILESYS_DIRS = $00000020; 
begin 
    SHAutoComplete(Edit1.Handle, SHACF_FILESYS_DIRS or SHACF_USETAB); 
    fAutoSuggestDropdownChecker := TAutoSuggestDropdownChecker.Create(Self); 
end; 

procedure TForm2.FormKeyDown(Sender: TObject; var Key: Word; 
    Shift: TShiftState); 
begin 
    if Key = VK_ESCAPE then begin 
    if not fAutoSuggestDropdownChecker.DroppedDown then 
     ModalResult := mrCancel; 
    end; 
end; 

, но важно, что кнопка Отмена не имеет набор Cancel свойств.

Сам компонент работает, подключаясь к обработке сообщений приложений и используя перечисление окон для текущего потока, чтобы проверить видимое окно с именем класса «Автоматическое предложение разворачивания». Если это существует и отображается, то список автоматического завершения будет сброшен.

unit uAutoSuggestDropdownCheck; 

interface 

uses 
    Windows, Classes, Messages, Forms; 

type 
    TAutoSuggestDropdownChecker = class(TComponent) 
    private 
    fDroppedDown: boolean; 
    fSaveMessageEvent: TMessageEvent; 
    procedure AppOnMessage(var AMsg: TMsg; var AHandled: Boolean); 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 

    property DroppedDown: boolean read fDroppedDown; 
    end; 

implementation 

//////////////////////////////////////////////////////////////////////////////// 

function EnumThreadWindowsProc(AWnd: HWND; AParam: LPARAM): BOOL; stdcall; 
var 
    WndClassName: string; 
    FoundAndVisiblePtr: PInteger; 
begin 
    SetLength(WndClassName, 1024); 
    GetClassName(AWnd, PChar(WndClassName), Length(WndClassName)); 
    WndClassName := PChar(WndClassName); 
    if WndClassName = 'Auto-Suggest Dropdown' then begin 
    FoundAndVisiblePtr := PInteger(AParam); 
    FoundAndVisiblePtr^ := Ord(IsWindowVisible(AWnd)); 
    Result := False; 
    end else 
    Result := True; 
end; 

function IsAutoSuggestDropdownVisible: boolean; 
var 
    FoundAndVisible: integer; 
begin 
    FoundAndVisible := 0; 
    EnumThreadWindows(GetCurrentThreadId, @EnumThreadWindowsProc, 
    LParam(@FoundAndVisible)); 
    Result := FoundAndVisible > 0; 
end; 

//////////////////////////////////////////////////////////////////////////////// 
// TAutoSuggestDropdownChecker 
//////////////////////////////////////////////////////////////////////////////// 

constructor TAutoSuggestDropdownChecker.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 
    fSaveMessageEvent := Application.OnMessage; 
    Application.OnMessage := AppOnMessage; 
end; 

destructor TAutoSuggestDropdownChecker.Destroy; 
begin 
    if (TMethod(fSaveMessageEvent).Code = TMethod(Application.OnMessage).Code) 
    and (TMethod(fSaveMessageEvent).Data = TMethod(Application.OnMessage).Data) 
    then begin 
    Application.OnMessage := fSaveMessageEvent; 
    end; 
    fSaveMessageEvent := nil; 
    inherited; 
end; 

procedure TAutoSuggestDropdownChecker.AppOnMessage(var AMsg: TMsg; 
    var AHandled: Boolean); 
begin 
    if ((AMsg.message >= WM_KEYFIRST) and (AMsg.message <= WM_KEYLAST)) 
    or ((AMsg.message >= WM_MOUSEFIRST) and (AMsg.message <= WM_MOUSELAST)) 
    or (AMsg.message = WM_CANCELMODE) 
    then 
    fDroppedDown := IsAutoSuggestDropdownVisible 
end; 

end. 

код, как размещены здесь только проверка концепции, но может послужить отправной точкой для тех, кто борется с той же проблемой.

Смежные вопросы