Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Mausrad, ScrollBox und PageControl (https://www.delphipraxis.net/171453-mausrad-scrollbox-und-pagecontrol.html)

Dalai 7. Nov 2012 11:07

Mausrad, ScrollBox und PageControl
 
Hey Leute,

da ich gestern auf dem PC meines Vaters ein Problem mit der Verwendung des Mausrads in einem meiner Programme hatte (reagierte nicht mehr und musste abgeschossen werden), wollte ich die Behandlung des Events umbauen. Dazu gab es vor kurzem bereits ein ähnliches Thema in der DP, aber da mein Problem etwas anders gelagert ist, eröffne ich besser ein neues Thema.

Ich beziehe mich mit dem Code für die Ereignisbehandlung auf diesen Post von Uwe Raabe, den ich 1:1 übernommen habe (nachdem ich die im Delphi 5 fehlende Funktion Sign() nachgebaut habe). Das Problem ist nun folgendes: Befindet sich auf der Form eine ScrollBox, funktioniert der Code sauber. Sobald ich auf der Form ein PageControl und darin (auf einem TabSheet) eine ScrollBox habe, ermittelt die Funktion ControlAtPos() das PageControl und nicht die ScrollBox.

Nochmal kurz als Übersicht:
Code:
Funktioniert:       TForm > TScrollBox
Funktioniert nicht: TForm > TPageControl > TTabSheet > TScrollBox
Das führt natürlich in der Folge dazu, dass die jeweils ermittelten Parents nur noch die Form und dann nil sind, wodurch das Scrollen natürlich nicht funktioniert. Eigentlich bleibt mir ja nichts anderes übrig, als die Childs des von ControlAtPos() ermittelten PageControls durchzugehen (z.B. mit dem property Components), aber dann könnte ich auch gleich auf die ScrollBox gehen, da ich ja weiß, dass auf jeder Seite des PageControl eine ScrollBox ist.

Wie würdet ihr das Problem angehen?

MfG Dalai

Pitschki1801 7. Nov 2012 13:11

AW: Mausrad, ScrollBox und PageControl
 
Hallo Dalai,

Ich habe in meinen Programmen bereits beide Strukturen verwendet und bis jetzt keine Probleme gehabt. Die Ereignisbehandlung von Uwe Raabe habe ich gerade bei mir getestet und sie klappt, wie in deinem Fall, wirklich nicht.
Jetzt frage mich allerdings warum du dies im Form OnMouseWheel behandelt willst und nicht im Ereignis der ScrollBox?
Ich habe in meinem Programm der ScrollBox im OnMouseWheel lediglich diese Zeile hinzugefügt:

Delphi-Quellcode:
procedure TForm.ScrollBoxMouseWheel(Sender: TObject; Shift: TShiftState;
  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
begin
    ScrollBox.VertScrollBar.Position := ScrollBox.VertScrollBar.Position - WheelDelta;
end;
Das funktioniert soweit ohne Probleme und vllt. löst es bereis dein Problem.

Gruß Pitschki

Dalai 7. Nov 2012 13:55

AW: Mausrad, ScrollBox und PageControl
 
Zitat:

Zitat von Pitschki1801 (Beitrag 1190146)
Jetzt frage mich allerdings warum du dies im Form OnMouseWheel behandelt willst und nicht im Ereignis der ScrollBox?

Das ist recht einfach zu beantworten und hat 2 Gründe:
  • die ScrollBoxen sind allesamt dynamisch erzeugt. Wenn ich die Ereignisbehandlung also in der Form mache, spare ich mir die (dynamische) Zuweisung des Eventhandlers komplett und damit potentielle Fehlerquellen.
  • Viel schwerwiegender ist aber, dass ich ein Scrollen auch dann ermöglichen will, wenn ein völlig anderes Steuerelement den Fokus hat (ein Button außerhalb des PageControls oder die Tabs des PageControls), der Mauszeiger aber trotzdem über der ScrollBox ist. Ich habe es gerade nochmal getestet und kann bestätigen, dass die Ereignisbehandlung der ScrollBox selbst nur dann ausgelöst wird, wenn ein Objekt innerhalb der ScrollBox (oder die ScrollBox selbst bei TabStop=True) den Fokus hat.

MfG Dalai

Dalai 7. Nov 2012 18:54

AW: Mausrad, ScrollBox und PageControl
 
Ich hab nun "ein wenig" (eher stundenlang, weil mir mein eigener Code im Weg stand :roll:) rumprobiert und bin zu der Erkenntnis gelangt, dass das harte Setzen der Position keine gute Idee ist, weil es bescheiden aussieht. Daher habe ich mich dazu entschieden, bei meiner Methode zu bleiben, nur mit dem Unterschied, dass ich nun
Delphi-Quellcode:
ScrollBox.Perform(WM_VSCROLL, msg, 0); // msg ist entweder SB_LINEDOWN oder SB_LINEUP
verwende statt wie bisher
Delphi-Quellcode:
SendMessage(ScrollBox.Handle, WM_VSCROLL, msg, 0);


Blöd ist, dass das Problem trotz dieser Änderung auf dem Problem-PC bestehen bleibt :?. Immerhin habe ich rausgefunden, dass das am Property ScrollBox.VertScrollBar.Smooth liegt. Schalte ich das ab, läuft das Programm normal weiter. Verstehen tue ich das nicht, denn das ist im Moment der einzige PC, auf dem das auftritt. Ich hatte das Problem schonmal auf meinem Laptop, allerdings war es nach einem Update der Synaptic-Treiber verschwunden.

Nur der Vollständigkeit halber hier noch die komplette Methode zur Ereignisbehandlung:
Delphi-Quellcode:
procedure TMainForm.FormMouseWheel(Sender: TObject; Shift: TShiftState;
  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
var
  rect: TRect;
  msg: LongInt;
begin
    if MainPageControl.ActivePageIndex < 0 then
        Exit;
    rect.Top:= 0;
    rect.Left:= 0;
    rect.TopLeft:= MainPageControl.ClientToScreen(rect.TopLeft);
    rect.Bottom:= MainPageControl.Height;
    rect.Right:= MainPageControl.Width;
    rect.BottomRight:= MainPageControl.ClientToScreen(rect.BottomRight);
    msg:= SB_LINEDOWN;
    if WheelDelta > 0 then
        msg:= SB_LINEUP;
    if PtInRect(rect, MousePos) then
    begin
        arPages[MainPageControl.ActivePageIndex].scroll.Perform(WM_VSCROLL, msg, 0);
        Handled:= True;
    end;
end;
// arPages ist ein dynamisches Array of record, in dem sich unter anderem eine ScrollBox und ein TabSheet befinden
// ja, ich weiß, dass man die Datenspeicherung noch optimieren kann :)
MfG Dalai

stahli 7. Nov 2012 19:50

AW: Mausrad, ScrollBox und PageControl
 
Ich habe jetzt nicht ganz genau verstanden welches Problem aktuell noch besteht, vielleicht gibt das Beispiel ggf. eine Anregung...

Delphi-Quellcode:
procedure TFormTest.MessageEvent(var Msg: TMsg; var Handled: Boolean);
var
  H: HWND;
  C: TControl;
  WC: TWinControl;
  I: Integer;

  function GetParentScrollBox(WC: TWinControl): TWinControl;
  begin
    Result := WC;
    if (not(WC is TScrollBox)) and (WC.Parent <> nil) then
      Result := GetParentScrollBox(WC.Parent);
  end;

begin
  if ((Msg.Message = WM_MOUSEWHEEL) or (Msg.Message = WM_MOUSEHWHEEL)) and (Msg.wParam and MK_CONTROL = 0) then
    begin
      H := WindowFromPoint(Msg.Pt);
      C := FindControl(H);
      if C is TWinControl then
        begin
          WC := GetParentScrollBox(C as TWinControl);
          if WC <> nil then
            begin
              for I := 1 to Mouse.WheelScrollLines do
                WC.Perform(CM_MOUSEWHEEL, Msg.wParam, Msg.lParam); // Msg.Message funktioniert nicht
              H := 0;
            end;
        end;
      if (H = 0) or ((Msg.HWND <> H) and (GetWindowThreadProcessId(H, nil) <> GetCurrentThreadId)) then
        begin
          Msg.HWND := 0;
          Msg.Message := WM_NULL;
          Handled := True;
        end
      else
        Msg.HWND := H;
    end
end;

Dalai 8. Nov 2012 08:00

AW: Mausrad, ScrollBox und PageControl
 
Zitat:

Zitat von stahli (Beitrag 1190213)
Ich habe jetzt nicht ganz genau verstanden welches Problem aktuell noch besteht [...]

Das Problem ist, dass sich eines meiner Programme beim Betätigen des Mausrads über einer ScrollBox aufhängt, aber nur auf diesem einen PC. Allerdings scheint das überhaupt nichts mit meiner Ereignisbehandlung zu tun zu haben, denn das passiert auch dann, wenn man auf einen der beiden Pfeile des Scrollbalkens klickt, und somit die Ereignisbehandlung des Mausrads überhaupt nicht ausgelöst wird.

Interessanterweise passiert das nicht, wenn man den Balken selbst anfasst und hin- und herschiebt. Sobald das Smooth-Scrolling der ScrollBox(ScrollBar) ausgeschaltet ist, tritt es ebenfalls nicht mehr auf. Es passiert auch nicht bei einem ListView im selben Programm; allerdings hat die dieses ListView beinhaltende Form auch keinen MouseWheel-Handler...

Ich habe die Vermutung, dass das an diesem einen PC hängt, der schon eine Uptime von mehr als 30 Tagen hat und vermutlich ist das Problem nach einem Neustart verschwunden, denn wie immer gilt: "Reboot tut gut" :) (vor allem bei Windows ;)).

MfG Dalai


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:17 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz