OnMouseWheel, reagiert nicht in Panel

Rund um die LCL und andere Komponenten
Antworten
Mathias
Beiträge: 6906
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

OnMouseWheel, reagiert nicht in Panel

Beitrag von Mathias »

In einem Formular habe ich ein Panel, das etwas kleiner ist als das Form.
Wen ich neben den Panel am Maus-Rad drehe, dann reagiert OnMouseWheel, im Panel nicht mehr.

Das Panel hat ein eigenes OnMouseWheel. Kann man dies umleiten, das dies auf das höher gelegene Fenster reagiert, in diesem Fall das Forrm.

Für Tasten gibt es für solche Fälle KeyPreview, wobei das beim Panel nicht gebraucht wird.



Code: Alles auswählen

unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, types;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure FormClick(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  Writeln('x:', x, ' Y:', y);
end;
 
procedure TForm1.FormMouseWheel(Sender: TObject; Shift: TShiftState;
  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
begin
  Writeln(MousePos.y);
end;
 
procedure TForm1.FormClick(Sender: TObject);
begin
  Writeln('Klick');
end;
 
end.
 
Schluss endlich brauch ich das ganze, weil ich ein OpenGLControl im Form habe, welches im Hintergrund manuell erzeugt wird.
Ich will bei meinen OpenGL-Anwendung auf Maus-Ereignisse reagieren.
Das sieht dann so aus:

Code: Alles auswählen

  OpenGLControl := TOpenGLControl.Create(Form);
  with OpenGLControl do begin
    Name := 'OpenGLControl';
    Parent := Form;
    Align := alClient;
  end;
 
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
theo
Beiträge: 10867
Registriert: Mo 11. Sep 2006, 19:01

Re: OnMouseWheel, reagiert nicht in Panel

Beitrag von theo »

Verstehe deine Frage nicht. Ich finde bei einem TPanel kein OnMouseWheel Ereignis.

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: OnMouseWheel, reagiert nicht in Panel

Beitrag von Michl »

Theo hat zwar Recht, ich versuche Dir trotzdem mal einen Tipp zu geben.

TPanel hat genauso, wie TForm einen gemeinsamen Vorfahren TLCLComponent, der das Ereignis OnMouseWheel zur Verfügung stellt:

Code: Alles auswählen

    property OnMouseWheel: TMouseWheelEvent read FOnMouseWheel write FOnMouseWheel;      
Bei TForm wird das Ereignis unter published zur Verfügung gestellt, bei TPanel nicht. Du hast jetzt die Möglichkeit, das Ereignis in TPanel direkt sichtbar zu machen und Lazarus neu zu bauen, eine eigene von TPanel abgeleitete Komponente zu erstellen oder direkt von TPanel abzuleiten.

Letzte Möglichkeit wäre z.B. so:

Code: Alles auswählen

  TMyPanel = class(TPanel)
    published
      property OnMouseWheel;
  end;
 
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  private
    Panel1: TMyPanel;
  public
  end;
...
procedure TForm1.FormMouseWheel(Sender: TObject; Shift: TShiftState;  //wird von Form1 und Form1.Panel1 genutzt
  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
begin
  Caption:=IntToStr(MousePos.y);  
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Panel1:=TMyPanel.Create(Self);
  Panel1.SetBounds(150, 50, 100, 100);
  Panel1.Parent:=Form1;
  Panel1.OnMouseWheel:=@FormMouseWheel;
end;  
Allerdings funktioniert das jetzt nur, da beide Klassen (TForm, TPanel) den gemeinsamen Vorfahr TLCLComponent haben. Da ich z.Zt. kein OpenGL installiert habe, weiss ich nicht, ob das bei einem TOpenGLControl (oder wie auch immer sich diese nennt) so möglich ist?!

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: OnMouseWheel, reagiert nicht in Panel

Beitrag von Scotty »

Das OpenGLControl reagiert selbst auf Wheel-Events, du brauchst kein Panel und musst auch nicht die Events des Hauptformulars umleiten. Wenn es darum geht, mehrere Bereiche mit einem gemeinsamen Event zu versehen, würde ich in jedem Control auf eine zentrale Routine zugreifen.

Code: Alles auswählen

 TOpenGLControl = class(TCustomOpenGLControl)
  published
    property OnMouseWheel;
    property OnMouseWheelDown;
    property OnMouseWheelUp;
 

Mathias
Beiträge: 6906
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OnMouseWheel, reagiert nicht in Panel

Beitrag von Mathias »

Ein bisschen genauer.

Ich habe folgenden constructor in meiner OpenGL-Bibliothek:

Code: Alles auswählen

constructor TOpenGL.Create(Form: TWinControl);
begin
  inherited Create;
  Camera := TCamera.Create;
 
  OpenGLControl := TOpenGLControl.Create(Form);
  with OpenGLControl do begin
    Name := 'OpenGLControl';
    Parent := Form;
    Align := alClient;
//    OnMouseWheel:=@Form.OnMouseWheel;
  end;
 
  InitOpenGL;
 
  OpenGLControl.MakeCurrent;
  ReadExtensions;
  ReadImplementationProperties;
 
  ProgramID := InitShader;
  glUseProgram(programID);
..............                                    
Im Hauptprogramm sieht es dann so aus:

Code: Alles auswählen

procedure THauptForm.FormCreate(Sender: TObject);
begin
  OpenGL := TOpenGL.Create(Self);
  OpenGl.AlphaBlending(True);
 
  OpenGL.Camera.Scale(1 / 130); 
...........
end;
 
procedure THauptForm.FormMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: integer; MousePos: TPoint; var Handled: boolean);
begin
  if WheelDelta < 0 then begin
    OpenGL.Camera.Scale(1.1);
  end else begin
    OpenGL.Camera.Scale(0.9);
  end;
end;
Das OpenGLControl reagiert selbst auf Wheel-Events,
Genau dies will ich umgehen. Ich will die OnMousexxx Funktionen des Formulares verwenden.
Wie schon gesagt, mit den Tasten geht es mit KeyPreview.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 6906
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OnMouseWheel, reagiert nicht in Panel

Beitrag von Mathias »

Problem gelöst.
Jetzt nimmt er sämtliche Mausfunktionen des Form.

Code: Alles auswählen

  OpenGLControl := TOpenGLControl.Create(Form);
  with OpenGLControl do begin
    Name := 'OpenGLControl';
    Parent := Form;
    Align := alClient;
    Enabled := False; // Dies muss man auf False setzen.
  end;   
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: OnMouseWheel, reagiert nicht in Panel

Beitrag von Scotty »

Durch das Disablen des Controls werden die Wheel-Events an die Hauptform geschicht, nur deswegen geht es jetzt. "Richtiger" wäre es so:

Code: Alles auswählen

 
interface
  TOpenGL=class(TOpenGLControl)
  private
    procedure DoMouseWheel
 
implementation
  procedure TOpenGL.DoMouseWheel
... 
  constructor TOpenGL.Create
    OpenGLControl.OnMouseWheel:=@DoMouseWheel;
//oder
    OpenGLControl.OnMouseWheel:=@Form1.DoMouseWheel;
 
(DoMouseWheel ist die mit dem OnMouseWheel-Event verknüpfte Routine.)

Mathias
Beiträge: 6906
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OnMouseWheel, reagiert nicht in Panel

Beitrag von Mathias »

Durch das Disablen des Controls werden die Wheel-Events an die Hauptform geschicht, nur deswegen geht es jetzt.
Habe ich dadurch irgendwelche Nachteile ?

Ich will ja, das die Events der HauptForm funktionieren.

Deine Variante mit @DoMo... geht nicht.
Es wird vom Compilier schon nicht erkannt.

Ich habe diese Zeile

Code: Alles auswählen

constructor TOpenGL.Create(Form: TWinControl);
mit

Code: Alles auswählen

constructor TOpenGL.Create(Form: TForm);
ersetzt, nützt aber nichts.

Im HauptFormular wird self.OnMouseWheel erkannt.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: OnMouseWheel, reagiert nicht in Panel

Beitrag von Scotty »

Mathias hat geschrieben:Habe ich dadurch irgendwelche Nachteile ?
Nicht unmittelbar, es ist einfach nur unsauber. Und die Methoden musst du schon richtig implementieren, damit der Compiler das akzeptiert. Das geht recht bequem, indem du einfach den Namen schreibst (@DoFoobar) und mit Shift+Ctrl+C die Klassendefiniton erzeugst.

Mathias
Beiträge: 6906
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OnMouseWheel, reagiert nicht in Panel

Beitrag von Mathias »

Nicht unmittelbar, es ist einfach nur unsauber.
Wieso ist dies unsauber, wen ich die Events von OpenGLControl deaktiviere ?

Code: Alles auswählen

procedure THauptForm.FormCreate(Sender: TObject);
begin
  OpenGL := TOpenGL.Create(Self);
  OpenGL.AlphaBlending(True);
  ....                               
TOpenGL ist ein von mir geschrieben Bibliothek, welche mir die wesentlichen Inizialisierung von OpenGL übernimmt.
Dort wird mir der Context für OpenGL erzeugt, dies mache ich mit OpenGLControl.
Dabei will ich sämtliche Events von Tastatur und Maus im Hauptform behalten.
Früher hatte ich den Context mit GetDC, etc. erzeugt, dann lief das Programm aber nur unter Windows.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten