ScrollBox automatisch scrollen
-
hi,
ja das mit der bedingung ist nicht einfach. ich habe dazu die mausposition genommen, ich glaube im onmousemove-handler ala "if (Y < Height)" ich weiß aber nicht mehr genau. vielleicht auch mit getcursorpos die cursorposition feststellen und wenn diese eine gewisse größe über/unterschreitet dann handeln...
wie gesagt, es hat dann funktioniert, wie du schon sagtest die bewegungen sind ziemlich ruckartig, naja, vielleicht findest du einen weg...mfg
murph
-
Vorsicht, es gab nur 3 Genies: Caesar, Da Vinchi, Einstein.
Jau, @DerAltenburger, das sieht nach Volltreffer aus. Mir gelang es nicht, die Position der Maus korrekt zu erfassen. Deswegen die Zufälligkeiten.
Muß es noch umsetzen, aber an dem Weg dürfte gar nichts stören. -20 ist IMHO das Problem. Ich will nicht schon scrollen, wenn ich noch so weit vom Rand weg bin. ZB. IrfanView macht es so, das stört beim Arbeiten. Erst wenn die Maus außerhalb der ScrollBox ist, ist der richtige Zeitpunkt zum Scrollen. Aber Scrollen ist Pflicht, sonst kann man IMHO nie Ausschnitte markieren, die größer sind als der sichtbare Bildausschnitt.
Daß die Funktion nichts tut, wenn nicht gescrollt wird, ist genau das, was gebraucht wird. Einfach mit der Maus hin- und herfahren, dann scrollt es weiter. Dann wieder zurück ins Image und die Draw-Form exakt positionieren. So ist es professionell.
(Und was anderes wird hier gar nicht gebaut :p )!
Also ab in die Werkstatt und umsetzen. Gibt's hier kein Smielie für eine Flasche Sekt? Volltreffer müssen gefeiert werden. - Deine Hilfe ist schon jetzt unbezahlbar. Das ist nicht meine App, das ist deine.
-
Hm... in eine Reihe mit Caesar gestellt zu werden würde mir nicht gefallen.
-
Das saust noch blitzmäßig durch.
DXR=ScrollBox->ClientWidth-X+10; DXL=X; if (DXR<1) ScrollBox->HorzScrollBar->Position+=1;
läuft schon langsamer und beginnt erst nach dem Rand mit Scrollen.
So scrollt es rasterpixelweise bei Zoomfaktoren:
DXR=ScrollBox->ClientWidth-X+10; DXL=X; if (DXR<1 && fmod(DXR,VFac) != 0) ScrollBox->HorzScrollBar->Position+=1;
Ich kann das Scrollen stoppen und kontrollieren. Aber pixelweise Scrollen ist quälend langsam. Bei höheren Arbeitsvergrößerungen komm ich nur etwa 4 px/sec weiter. Dazu das starke Rastergeruckel.
Aber immerhin, erst mal besser als nix. Das muß noch stark optimiert werden. Noch fällt mir aber nix besseres ein (vielleicht noch mit den Werten Spielen). Meine letzten 30 Kamele und meine antike Ölquelle für eine gute Idee. :p
@murph, kram das alte Grafiktool wiederaus der Schublade. Mit etwas Ideenglück bringt man die Geschichte sicher noch nach Wunsch auf die Reihe.
Hähä...@WebFritzi, etwas Gag und Schmunzelfaktor muß dabei sein. Caesar? Der Junge paß nicht in die Reihe.
-
Und mit dem API geht es in unkontrolierten größeren Rucken. Die auskommentierte Zeile finde ich als momentan besten Kompromiß. Wenn nur die Ruckartigen Bewegungen nicht wären.
if (ScrollBox->HorzScrollBar->Position<ScrollBox->HorzScrollBar->Range) { //falls Maus am rechten Rand DXR=ScrollBox->ClientWidth-X+10; DXL=X; if (DXR<1 && fmod(DXR,VFac) != 0) SendMessage(ScrollBox->Handle, WM_HSCROLL, SB_LINEDOWN, 0); //ScrollBox->HorzScrollBar->Position+=8; }
-
SendMessage(ScrollBox->Handle, WM_HSCROLL, SB_LINEDOWN, 0);
Da passen Message und WPARAM nicht zusammen!
-
@Omega: Vergiss besser die SendMessage-Sache. Die wird im VCL-Code sowieso intern aufgerufen. Spiel mal lieber ein bisschen mit den Eigenschaften Range und Increment des ScrollBar-Elements rum.
-
Die API-Zeile ist auch unspezifisch. Sowas ist gut, um zB. im RichEdit FindText ind den Sichtbereich zu bringen oder eben die ScrollBox schnell zu bewegen.
Mit Increment hab ich noch gat nicht expirimentiert. Könnte besser sein als Position+=8, auschecken. Range? Hmmm... mit größerem Range könnte der Ablauf eleganter werden.
Das wichtigste war sicher erst mal ein Stop-Faktor. OnMouseMove wirkt ja bei solchen Operationen quasi wie eine schleife. Das muß unterbrechbar sein, sonst bekommt man dieses Durchlaufverhalten...
Uff... ich seh nix mehr. Ist schon Nacht? Ich sollte weitermachen, wenn's draußen wieder hell ist. :p
-
Hi Omega-X
Du solltest mit Lob warten bis es optimal geht!
Und diese Uebertreibung!!!
(Waeren statt Cäsarnicht Bill Gates und Gott auch genug :p )Bei Dir fetzt das durch wie'n Puma???
(Da kommt wahrscheinlich MouseMove zu schnell in rekursion?)
Da hilft nur eins:
Das Ganze NICHT in MouseMove packen, sondern in eine NORMALE public- Funktion z.B. TimeScroll(...)
Da drin:
-- Mausposition abfragen
-- UMRECHNEN auf ScrollBox- Koordinaten!!!
-- Test aehnlich wie gepostet machen und Scrollen!!!Damit kannste auch auf Maus- Positionen reagieren, die AUSSERHALB der Box liegen
Die Funktion kann von 'nem ein/aus- schaltbaren Timer der Form gerufen werden.
(Kannst auch 'n Timer in die Klasse einbauen; ist aber Verschwendung, wenn Du das in mehreren Kompos machst)Ich mach in Form ein Timer, kleines Intervall (10..100 ms)
-- Timer- Event ruft fuer alle zu steuernden Kompos die dort eingebauten
-- Routinen TimeXXX() auf.-- in den Routinen wird dann mit Teiler (Als Property steuerbar?) zum Speibiel
-- nur jeder Zehnte Aufruf wirksam!-- Ich geb' den Routinen noch das Timerintrvall als Parameter mit, dann kann
-- sich jede Kompo individuell auf beliebiges (steuerbares) Vielfache des
-- Timerintervalls synchronisieren. :p(So in etwa mach ich das fuer eine Thumbnail- Anzeige. Die rauscht sonst auch durch!)
Ich hoffe, das hilft weiter!
-
Klar, Lob erst nach getaner Arbeit. Aber wann wird das sein? Bis dahin ist die Kehle längst ausgetrocknet. :p
Deine Ideen helfen auf jeden Fall. Timer? Die Maus soll doch selbst "Timer" spielen. Ansonsten würden sich beide wohl ins Handwerk pfuschen?. Nur jeder 10. Aufruf, das geht auch in einer Schleife. Muß ich auschecken, da die Maus zum Scrollen ja hin- und herfährt.
Variablen setzen, um später Properties draus machen zu können, stößt erst mal an Grenzen:
int Dfmod = fmod(DXR,VFac);
ScrollBox->HorzScrollBar->Position+=Dfmod;Eigentlich sollte jetzt bei jeder Mausbewegung bis zum nächsten Bildpixelraster durchgescrollt werden. Es erfolgt aber gar keine Reaktion. Der Modulo besteht aber, sonst würde es auch mit der if-Bedingung nicht klappen. Es sieht so aus, als würde Position nur einen Wert aber keine Variable akzeptieren. Das macht mir einen dicken Strich durch eine ansich vielleicht gute Rechnung. Das Verhalten irritiert mich.
Mit der Umrechnung von X auf ScrollBox-Maße hab ich Probs. X=0 ist außerhalb der ScrollBox-Position, wenn schon gescrollt wurde. Ich bräuchte einen Bezug für die Umrechnung. Vielleicht sind Screen-Koordinaten die Lösung? Damit werd ich mich mal auseinandersetzen...
-
Hi
ich glaub' jetzt haben wir uns mistverstanden!
Ich geh' davon aus, dass mit OnMouseMove das Teil zu schnell scrollt. (Scrollen loest wieder OnMouseMove aus-> Scrollen > OnMouseMove..... ==Rekursion ohne Ende!!!)
Deshalb 'Timing' vorgeben (wenn Maus am Rand der Scrollbox ist!)
-- eigene 'Timer'- Funktion
-- darin Mouse->CursorPos abfragen (Punkt in Screenkoordinaten!)
-- mit Umrechnen war nicht Skalieren gemeint! Sondern Abstand DeltaX und DeltaY
-- zu ScrollBox- Umgrenzung - Alle 4 Seiten kontrollieren
-- Dazu ev. MousePosition in ClientKoordinaten DER FORM umrechnen und mit
-- Left/Top/Right/Bottom der ScrollBox in Bezug bringen!!!-- Wenn Maus an einer Kante der ScrollBox ist, dann Scrollen um ScreenPixel!
?? Scrollweite Skalieren auf Anzeige- Bild- Pixel nur bei Vergroesserter
?? Darstellun sinnvoll!?? Skalierung mit fmod == RESTWERTDIV ??? (Ich denk 'ne normale Division
?? ist besser ???*****************************************************************************
DAS GILT ALLES NUR BEI EIGENER FUNKTION, NICHT BEI ONMOUSEMOVE DER SCROLLBOX!
*****************************************************************************
-
Hi Omega-X (Die Zweite)
Bau 'mal folgendes in eine Timerroutine Deiner Form ein und kuck Dir an was passiert, wenn die Maus aussen in die Naehe Deiner ScrollBox (hier IPSBox) kommt! :p
void __fastcall TForm1::Timer1Timer(TObject *Sender) { int DXl,DXr,DYo,DYu; int Rand=16; TRect ARect,IRect; TPoint Pt; ARect.Left=IPSBox->Left-Rand; ARect.Top=IPSBox->Top-Rand; ARect.Right=ARect.Left+IPSBox->Width +2*Rand; ARect.Bottom=ARect.Top+IPSBox->Height +2*Rand; IRect.Left=IPSBox->Left; IRect.Top=IPSBox->Top; IRect.Right=IRect.Left+IPSBox->Width; IRect.Bottom=IRect.Top+IPSBox->Height; Pt=ScreenToClient(Mouse->CursorPos); if ((Pt.x>ARect.Left)&&(Pt.x<ARect.Right)&&(Pt.y>ARect.Top)&&(Pt.y<ARect.Bottom)) { if ((Pt.x>IRect.Left)&&(Pt.x<IRect.Right)&&(Pt.y>IRect.Top)&&(Pt.y<IRect.Bottom)) { Form1->Color=clBtnFace; } else { //Maus im Randbereich (Ausserhalb)!!! DXl=IRect.Left-Pt.x; DXr=Pt.x-IRect.Right; DYo=IRect.Top-Pt.y; DYu=Pt.y-IRect.Bottom; if (DXl>0) Form1->Color=DXl*16; if (DXr>0) Form1->Color=DXr*16; if (DYo>0) Form1->Color=DYo*16; if (DYu>0) Form1->Color=DYu*16; } } else { Form1->Color=clBtnFace; } } //---------------------------------------------------------------------------
Hilft das weiter?
-
*Meuter*! Was bringen mir Screen-Koordinaten?
TPoint MPt = ClientToScreen(MovePt);
ShowMessage(IntToStr(MPt.x));Image->Left ist mindestens 200 vom Bildschirmrand entfernt. Ich geh auf ein Randpixel im Image nahe Image->Left, die Message sagt "3". Ist das nicht herrlich?
TPoint ScrollBScr = ScrollBox->ClientToScreen(ScrollBScr);
So sollte es nach der Hilfe gehen, die ScrollBox mit Bildschirmkoordinaten zu berechnen. Aber was hab ich jetzt definiert? Womit kann ich was berechnen? *Oh_ich_liebe_mein_Hirn_denn_es_ist_so_erfrischend_leer* :o
Wer kann einen gepeinigten Omega-X retten? Ich brauch ein gemeinsames Bezugssystem für die Scrollbox und das darin enthaltene TImage.
Beispiel: Wenn ScrollBox->Left=52; ist, soll die Message "53" ausgeben, wenn die Maus im ersten sichtbaren Image-Pixel ist. - Ansonsten vergleich ich Elefanten mit Mäusen.
-
Sorry, war so konzentriert, hab deinen beitrag erst jetzt gesehen. Ich check das mal. Auf den ersten Blick scheint es darum zu gehen, optisch darzustellen, wann Aktionen stattfinden würden. Recht aufwändig aber primstens testgeeignet. Und wieder ab in die Werkstatt. :p
-
Hmmm... nachdem nichts geschah, hab ich Color im if-Zweig auf clRed gesetzt, im else-Zweig auf clBlue. Egal, wohin ich mit der Maus geh, else ist immer true.
Konnte den Code nicht linear übernehmen.
// läuft bei mir nicht
Pt=ScreenToClient(Mouse->CursorPos);// So geht es
TPoint CursorPos;
Pt=ScreenToClient(CursorPos);Ob das den Unterschied macht?...
-
Hi
Komisch, das muesste geh'n.
Einfache Funktion:
1.ARect festlegen = Umriss der ScrollBox um Rand groesser
2.IRect festlegen = Umriss der ScrollBox
3.Pt=ScreenToClient(Mouse->CursorPos);
--MouseKoordinaten holen (= ScreenKoordinaten)
--Umrechnen in Form- Koordinaten.
??Falls das nicht geht nimm: Form1->ScreenToClient(...)??
4.Test, ob Maus im AUSSENRECHTECK (ScrollBox + Rand!!!)
-- Wenn ja, Test ob Maus im INNENRECHTECK (ScrollBox)
---- Wenn ja, Normale Farbe
---- sonst Farbe = Abstand der Maus von Kontur
-- sonst Normale FarbeD.h.:
Wenn Maus zu weit von Scroller weg ist oder innerhalb -> normale Farbe
Wenn Maus dicht an der Box (aussen) Farbe abhaengig von Abstand!Ist nur 'n Demo: Soll nur zeigen, wie Randberuehrung zeitgesteuert moeglich ist!
Bei mir wechselt die Farbe von dunkel bis Hellrot, wenn Maus im Randbereich ist.
Je weiter weg desto Heller Rot!(bis ARect verlassen wird) :pDie Breite des Randes ist einstellbar. Ob der sensitive Bereich ausserhalb an der Box oder innerhalb liegt, haengt von Berechnung AREct / IRect ab. Mich wuerde die Mausreaktion innen stoeren. Mir ist's lieber, wenn Reaktion nur in kleinem Bereich ausserhalb erfolgt - ist aber ANSICHTSSACHE!
-
Alles hängt daran, daß ich den die Mausposition nicht in Screenkoordinaten umwandeln kann. Damit wär ich nämlich aus dem Schneider. Hab es nach deinem Beispiel auch noch mal mit der Form als Basis versucht, bringt auch kein anderes Ergebnis.
MovePt = Form1->ClientToScreen(MovePt);
Bei der erst verwendeten Methode hab ich gemerxt, daß sich der Punkt des Scrollbeginns immer weiter ims Image hinein zurückverlagert, je größer Position ist. Das war bei dem Ansatz das Haupthandicap.
Karamba, wenn die Mausposition als Screen-Kordinaten ermittelbar wäre, könnte man exakt vergleichen, ohne die Rechtecke benutzen zu müssen. Und dann die Position der ScrollBar nur über den Timer verschieben. Das wär 'ne klare Sache.
Also, ich brauch die Mausposition als Screenkoordinaten! Was mach ich falsch? Es muß gehen, wenn es in der Klasse so vorgesehen ist.
Zum letzten Absatz: Mich würde auch stören, wenn die Mausreaktion innen ist. Die muß außen liegen, dann ist alles paletti. Als Bedingung setz ich auch, daß Drawing oder Dragging true sein muß. Sonst würde jede Mausbewegung im Bildschirm was bewegen.
-
Original erstellt von <Omega-X>:
Alles hängt daran, daß ich den die Mausposition nicht in Screenkoordinaten umwandeln kann. Damit wär ich nämlich aus dem Schneider.Wenn es dir weiterhilft:
POINT pt; GetCursorPos(&pt);
-
Hi
Das versteh' ich jetzt nicht!(???)
mit
Pt=Form1->ScreenToClient(Mouse->CursorPos)
muesste doch exakt die Positin der Maus IN FORM kommen:
-- Mouse->CursorPos enthaelt doch die ScreenKoordinaten der Maus!!! (BCB 4.0)
-- Form1->ScreenToClient macht daraus FORM- bezogene Koordinaten!Wo holst Du Dir die Mauskoordinaten; Was enthalten die genau?
Das hat eigentlich mit dem Stand der Rollbalken nichts zu tun???
Wo ist dein Timer? Sollte in der Form liegen, nicht in Klasse der ScrollBox!
PS: Liegt Deine ScrollBox in der Form oder auf einem Pane / Registe?
Wenn die NICHT in der Form direkt liegt, stimmt die ganze Rechnung nicht!
(ARect / IRect). Dann musste ScreenToClient von Panel nehmen![ Dieser Beitrag wurde am 14.03.2003 um 12:12 Uhr von DerAltenburger editiert. ]
-
@WebFritzi, *Volltreffer*!!!
Damit gehören dir meine letzten 30 Kamele und die antike Ölquelle, wie auf Seite 1 angekündigt.
Will sagen, super Dank, genau das war's.
Ole, jetzt wieder ab in die Werkstatt. @DerAltenburger, jetzt kann ich die Sachen nachvollziehen. - Ich hab übrigens das Image auf dem Panel liegen. Hat sich aus praktischen Gründen bewährt. Das über das Image hinausgeschobene Paste-Image wird nun nur noch soweit angezeigt, wie es über dem Image liegt. So soll es sein, da der Rest ja abgeschnitten wird.