Jak dodać zdarzenie OnKeyPress do komponentu, który go nie posiada?

0

Cześć,
mam komponent niestandardowy z kodem źródłowym typu a'la ComboBox, jednak nie posiada on autouzupełniania, tj, jak mam listę rozwijaną typu TStrings, to jak wpisuję dane w ten komponent
to treści nie podpowiadają mi się. Chciałbym uzyskać efekt takiego podpowiadania jak w comboboxie standardowym jest to możliwe.

Wymyśliłem, że najpierw potrzebuję zdarzenia które zareaguje na wciśnięcie klawiszy podczas wpisywania, aby potem szukać w TStrings.
Zastanawiam się jak można 'wstrzyknąć' taki event do takiego komponenty - bez jego dużych zmian. Najlepszy byłby jakiś helper który by to zrobił, aby zbytnio nie psuć oryginalu.
jakieś pomysły?

0

Trudno zgadywać skoro nie wiadomo co to za komponent i po czym dziedziczy.

0

Next Components -> bergsoft.nl

TNxComboBoxInspectorNode6 = class(TNxStringsInspectorNode6)
     TNxStringsInspectorNode6 = class(TNxInspectorNode6)
         TNxInspectorNode6 = class(TComponent, INxViewComponent, INxBase)
              ....

Jakieś pomysły? Może jakieś inne zdarzenie?

1

Może coś takiego:

type
  TTwojeComboBox = class(TComboBox)
  private
    procedure WndProc(var Message: TMessage); override; 
  end;
  
implementation
 
procedure TTwojeComboBox.WndProc(var Message: TMessage);
begin
  inherited WndProc(Message);
  if Message.Msg = CN_KEYUP then
  begin
    Memo1.Lines.Add('Key Up, kod klawisza: ' + IntToStr(Message.WParam) + ', tekst: ' + self.Text);
    //tu robisz autouzupełnianie bazując na tym, co już jest w self.Text
  end; 
end;
0

@loleeek: w razie gdybyś był zmuszony do ręcznej implementacji autouzupełniania treści, to polecam opierać się na już gotowych implementacjach. W razie czego możesz skorzystać z kodu LCL – autouzupełnianie jest standardem dla podstawowego TComboBox, a kod za niego odpowiedzialny, znajduje się w klasie bazowej, czyli w TCustomComboBox. Łatwo nie będzie, ale przynajmniej nie będziesz musiał wszystkiego samemu wymyślać.

3

Ponieważ wczoraj poimprezowałem i nie zdrowia pisać sensownego kodu a mam trochę czasu postanowiłem przyjrzeć się sprawie, która w tym przypadku jest nieco skomplikowana i rozwiązania powyżej proponowane nie zadziałają.

TNxComboBoxInspectorNode6 to tak naprawdę TNxComboBox6 tylko mający zastosowanie jako edytor właściwości komponentu TNextInspector6, który przechwytuje komunikaty i posiada zdarzenie OnKeyPress na które w edytorze właściwości (którym może być wspomniany ComboBox) w normalnych warunkach nie reaguje.
Próba dodania do niego obsługi komunikatu WM_CHAR też z nieznanych przyczyn nie działa. Czyli na zwykłe dodanie zwykłe nie reaguje.

type
  TNextInspector6 = class(NxInspector6.TNextInspector6)
  protected
    procedure WMChar(var Message: TWMChar); message WM_CHAR;
  end;

Natomiast da się nadpisać zdarzenie CMChildKey (musi być subclasing helpery nie obsługują zdarzeń)

type
  TNextInspector6 = class(NxInspector6.TNextInspector6)
  protected
    procedure CMChildKey(var AMsg: TCMChildKey); override;
  end;
//------
implementation

procedure TNextInspector6.CMChildKey(var AMsg: TCMChildKey);
var
  Ref: IInterfaceComponentReference;
  Comp: TComponent;
  ComboBox: TNxComboBox6;
begin
  inherited;
  if Supports(Self.InplaceEdit, IInterfaceComponentReference, Ref) then
  begin
    Comp:= Ref.GetComponent;
    if Comp.ClassNameIs('TNxComboBox6') then
    begin
      ComboBox:= TNxComboBox6(Self.InplaceEdit);
      if Assigned(ComboBox) and (Assigned(Self.OnKeyPress)) then
        Self.OnKeyPress(ComboBox, Char(AMsg.CharCode));
    end;
  end;
end;

no i oczywiście trzeba w TNextInspector6 ustawić zdarzenia OnKeyPress na które tak przerobiony OnKeyPress tym razem będzie reagował dla przykładu:

procedure TForm1.NextInspector61KeyPress(Sender: TObject; var Key: Char);
var
  ComboBox: TNxComboBox6;
begin
  if Sender is TNxComboBox6 then
  begin
    ComboBox:= TNxComboBox6(Sender); //abyś operowal na wlasciwym  ComboBox
    OutputDebugString(PChar('NxComboBox61KeyPress ' + Key));
  end;
end;

Wadą rozwiązania jest to że Key jest zawsze wielką literą. Nie wiem dlaczego tak się dzieje. Nie znalazłem nic w dokumentacji aby CM_CHILDKEY miał być wielką literą ale to pewnie dlatego że tu chodzi o klawisz a nie znak z klawiatury. Nie mamy też polskich znaków. Możliwy Fix... prawdę mówiąc wydaje mi się z D wzięty ale innego pomysłu w tej chwili (możliwe że z powodu kaca giganta) nie mam:

procedure TNextInspector6.CMChildKey(var AMsg: TCMChildKey);
const
  //taką tablicę - mapę trzeba dla wszyskich wielkich liter polskich znaków
  POLISH_KEYS: array [0..2,0..1] of Char  = (('A', 'Ą'), ('C', 'Ć'), ('E', 'Ę'));
var
  Ref: IInterfaceComponentReference;
  Comp: TComponent;
  ComboBox: TNxComboBox6;
  MyKey: Char;
  i: Integer;
begin
   inherited CMChildKey(AMsg)
  if Supports(Self.InplaceEdit, IInterfaceComponentReference, Ref) then
  begin
    Comp:= Ref.GetComponent;
    if Comp.ClassNameIs('TNxComboBox6') then
    begin
      ComboBox:= TNxComboBox6(Self.InplaceEdit);
      if Assigned(ComboBox) and (Assigned(Self.OnKeyPress)) then
      begin
        MyKey:= Char(AMsg.CharCode);
        if ((GetKeyState(VK_RMENU) and $8000) > 0) then  //polskie litery
          for i:= Low(POLISH_KEYS) to High(POLISH_KEYS) do
             if MyKey = POLISH_KEYS[i][0]then
             begin
               MyKey:= POLISH_KEYS[i][1];
               break;
             end;
        if ((GetKeyState(VK_SHIFT) and $8000) = 0) and ((GetKeyState(VK_CAPITAL)and $0001) = 0) then //mala czy wielka
          MyKey:= AnsiLowerCase(MyKey)[1];
        Self.OnKeyPress(ComboBox, MyKey);
      end;
    end;
  end;
end;

Oczywiście ta procedura uniemożliwia zmianę kodu wciśniętego klawisza jaki ma dotrzeć do ComboBox ale na razie nie chce mi się kombinować bo to nie takie proste zwykłe AMsg.CharCode:= $41; //A nic nie daje bez względu gdzie i czy w ogóle jest wywołanie inherited.

.
EDIT:

Ostateczna tym razem chyba bez zarzutu funkcja dająca wpisany znak (czyli mała lub wielka litera, zwraca poprawnie polskie znaki):

procedure TNextInspector6.CMChildKey(var AMsg: TCMChildKey);

function GetCharFromKey(Key: Word): string;
var
  KeybState: TKeyboardState;
  KeybLayout: HKL;
begin
  KeybLayout:= GetKeyboardLayout(0);
  GetKeyboardState(KeybState);
  SetLength(Result, 2);
  ToUnicodeEx(key, key, @KeybState, @Result[1], 2, 0, KeybLayout);
end;

var
  Ref: IInterfaceComponentReference;
  Comp: TComponent;
  ComboBox: TNxComboBox6;
  MyKey: Char;
begin
  inherited CMChildKey(AMsg);
  if Supports(Self.InplaceEdit, IInterfaceComponentReference, Ref) then
  begin
    Comp:= Ref.GetComponent;
    if Comp.ClassNameIs('TNxComboBox6') then
    begin
      ComboBox:= TNxComboBox6(Self.InplaceEdit);
      if Assigned(ComboBox) and (Assigned(Self.OnKeyPress)) then
      begin
        MyKey:= GetCharFromKey(AMsg.CharCode)[1];
        Self.OnKeyPress(ComboBox, MyKey);
      end;
    end;
  end;
end;
0

@kAzek: dzięki, kod działa, wirtualne piwo dla Ciebie!
jak już mamy OnKeyPress, to wystarczy dać Autocomplete := True na Comboboxie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1