Toon posts:

[Delphi] WM_SETFOCUS message negeren

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik heb een nieuwe ListView classe gemaakt die gebaseerd is op TListView. Met deze classe is het mogelijk om een ListView te gebruiken, waarmee de gebruiker bijv gewoon kan scrollen maar hij kan niet andere items selecteren.

In deze nieuwe classe zit een property DisableSelection. Als die op True staat dan mag de gebruiker dus niet de selectie wijzigen. (Dus deze property is ongeveer hetzelfde als Enabled := False, alleen kan je dan bij die klasse van mij gewoon de kolommen resizen, scrollen, enz..)

Nu is er 1 ding wat ik niet voor elkaar krijg. Als het component een WM_SETFOCUS krijgt en DisableSelection is True, dan zou de message dus weggegooid moeten worden, omdat het component geen focus mag krijgen.

Ik heb de volgende code:

Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
type
  TlistviewDisable = class(Tlistview)
  private
    { Private declarations }
    FDisableSelection: Boolean;
    procedure SetDisableSelection(Value: Boolean);
  protected
    { Protected declarations }
    procedure WndProc(var Message: TMessage); override;
  public
    { Public declarations }
    property DisableSelection: Boolean read FDisableSelection write SetDisableSelection;
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Win32', [TlistviewDisable]);
end;

{ TlistviewDisable }

procedure TlistviewDisable.SetDisableSelection(Value: Boolean);
begin
  FDisableSelection := Value;
end;

procedure TlistviewDisable.WndProc(var Message: TMessage);
begin
  if not DisableSelection then
    inherited
  else
    if (Message.Msg <> WM_LBUTTONDOWN) and
       (Message.Msg <> WM_RBUTTONDOWN) and
       (Message.Msg <> WM_SETFOCUS) and
       (Message.Msg <> WM_LBUTTONUP) and
       (Message.Msg <> WM_RBUTTONUP) then
      inherited;
end;

end.


In de WndProc staat dus dat als de message WM_SETFOCUS is dat die die moet weggooien. Maar met deze code gaat het niet goed. Als ik een kolom van de ListView resize en de muis vervolgens los laat dan krijgt het component toch de focus.


Als ik het op de volgende manier doe dan werkt het wel:

In de OnEnter event van het component zet ik:
Delphi:
1
2
3
4
5
6
7
8
procedure Tfrm_ArtikelVerpakking.lstvw_VerpakkingenEnter(Sender: TObject);
begin
  if (lstvw_Verpakkingen.DisableSelection) or (lstvw_Verpakkingen.Items.Count = 0) then
    SelectNext(lstvw_Verpakkingen, True, True)
  else
    if (lstvw_Verpakkingen.ItemFocused = nil) and (lstvw_Verpakkingen.Items.Count > 0) then
      SelectFirstItem;
end;


en ik haal in de WndProc van de klasse: (Message.Msg <> WM_SETFOCUS)
weg dan werkt het goed.


Maar dit is niet echt de beste oplossing, omdat ik dat dan in alle instanties van het component zou moeten doen.

Wie weet er een goede oplossing?

En als je in de WndProc procedure niet inherited toe bij een WM_SETFOCUS dan krijgt dat component toch niet de focus en houdt het huidige component toch de focus?

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Ik heb niet zo heel veel verstand van de inner workings van een listview, maar misschien dien je nog een andere message af te vangen voor de header?

Als een oplossing is om na het verkrijgen van de focus de focus door te schijven kan je ook gewoon de functie DoEnter overriden, ongeveer net zoals je de WndProc gedaan hebt, en dan daar je SelectNext code in. Dan hoef je jezelf niet aan het OnEnter event te koppelen.

We adore chaos because we like to restore order - M.C. Escher


  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10-2025
ahum... Ik moet beter lezen in het vervolg naar wat lordlarry schrijft :)


waarom override je dan niet
DoEnter() ?

dus zoiets van (niet getest)

in interface:

DoEnter(); override;

implementation:

procedure TlistviewDisable.DoEnter();
begin
if (Self.DisableSelection) or (Self.Items.Count = 0) then
SelectNext(Self, True, True)
else
if (Self.ItemFocused = nil) and (Self.Items.Count > 0) then
SelectFirstItem;
end

[ Voor 11% gewijzigd door martijn_brinkers op 26-01-2003 15:24 ]


Verwijderd

Topicstarter
Mooi het is gelukt. Ik had hiervoor zelf ook geprobeerd om het in de DoEnter procedure te doen. Maar dit gaf toen problemen.

Maar ik weet nu wat de oorzaak daarvan was. Ik gebruik SelectNext om het volgende control te krijgen. Maar aangezien de listview het enige control was in een panel krijg je nil terug en dat leidt weer tot foutmeldingen.

Maar goed dat van SelectNext gebruik ik nu nog steeds alleen zo dan dat er geen fouten ontstaan. Maar dat is zoiezo geen goede oplossing omdat je nu niet weet of gebruiker omhoog hoor de "tab lijst" gaat of juist omlaag.

Nu kan ik wel allerlei ingewikkelde procedure's maken die kijken welk control de focus heeft voordat een ander control die krijgt en zo vergelijken of de gebruiker omhoog gaat of juist omlaag. Maar ik denk dat het makkelijker is om gewoon zodra de DisableSelection property op True gezet wordt om dan de TabStop property uit te zetten.

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 08:23

Tomatoman

Fulltime prutser

De WndProc is een van de meest aangeroepen functies van een windowed control. Daarom zou ik hem even herschrijven. Niet dat het fout is wat je doet, maar het kan geen kwaad om het naar de 'standaardvorm' van een WndProc om te schrijven.
Delphi:
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
procedure TlistviewDisable.WndProc(var Message: TMessage);
begin
  if DisableSelection then
    case Message.Msg of
      WM_LBUTTONDOWN,
      WM_RBUTTONDOWN,
      WM_SETFOCUS,
      WM_LBUTTONUP,
      WM_RBUTTONUP: { niets doen };
    else
      inherited WndProc(Message);
    end
  else
    inherited WndProc(Message);
end;

Een goede grap mag vrienden kosten.


Verwijderd

Topicstarter
tomatoman schreef op 27 January 2003 @ 01:11:
De WndProc is een van de meest aangeroepen functies van een windowed control. Daarom zou ik hem even herschrijven. Niet dat het fout is wat je doet, maar het kan geen kwaad om het naar de 'standaardvorm' van een WndProc om te schrijven.
Oke ik zal de code herschrijven.
Pagina: 1