Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Dann begehst Du einen Denkfehler. Der Regler kümmert sich überhaupt nicht um irgendwas. Der Regler ist bloß ein Ding, das man hin- und herschieben kann, aber sonst nichts. Du musst die Reglerposition auch nicht berechnen, sondern nur abfragen. In meiner Anwendung ist der Regler ein eigenes Control - sogar ein ziemlich dummes Control, das nur der Maus folgt, solange bis es auf eine obere oder untere Grenze stößt, dann bleibt es einfach stehen. Das wars schon.
Der Regler hat ein Ereignis "OnMouseMove".
Die Scrollbar erzeugt so einen "selbständigen" Regler und nimmt ihn in Betrieb. Die Methode "SliderShift", die ich Dir oben gezeigt habe, hängt sich in die TGUISlider.OnMouseMove ein. Jedes Mal, wenn der Regler jetzt ein Mausmove registriert und damit verschoben wird, ruft er die Methode TGUIScrollBar.SliderShift auf. Diese Methode schaut nur mehr nach, wo das Slider.Top grade ist und beginnt mit den obigen Berechnungen. Oder besser: Berechnet daraus die UserPosition, also die ListBox-Zeile.
Angenommen du hast ganz wenige - aber gerade zum Scrollen ausreichende - Einträge in der Listbox. Dann ist es schwachsinnig, dass die TrackBar stur der Maus folgt, dass sie stattdessen Sprünge macht - man die Maus also entsrpechend ein ganzes Stück weiterbewegen muss - ist wesentlich sinnvoller finde ich. Es kann gut sein, dass wir wieder aneinander vorbeireden. Im ersten Beitrag habe ich nämlich gesagt, ich hätte schon einen Regler welcher der Maus folgt, allerdings möchte ich, dass er lieber Sprünge - falls notwendig - macht. Hat man 5000 Einträge in der Listbox, sollen logischerweise keine Sprünge mehr gemacht werden, bei einer Listbox die nur 10 Einträge anzeigen kann und 15 enthält, sollen Sprünge in der Bewegung des Reglers sein, also keine Pixelbewegungen.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Da die Listbox ja einen direkten Draht zur ScrollBox hat - sie kann die ScrollBox.Positon setzen - sollte das kein Problem sein. In so einem Fall, wo Du Sprünge machen willst, muss Du die Zeile ermitteln, wo du hinspringen willst, also z.B. in dem oben geschilderten Fall, wenn die aktuelle Position die Zeile Null ist und man kriegt eine ScrollBox-Meldung, dass die Position zu ändern ist.
Dann muss man
1) die ScrollBar.Position auf Maximum-LinesPerPage+1 setzen, in unserem Fall 15-10+1 = 6 und
2) die Anzeige der Listbox entsprechend anpassen
Verdammt. Ich habe mal gerade zwei Listboxen auf eine Testform geknallt, in beide Einträge via for-Schleife eingefügt und gerade mal festgestellt, dass die Scrollbar einer Listbox eine andere ist als meine erwünschte: Die Scrollbar scrollt, wird anschließend beim absetzen begradigt (man sieht, dass sie sich noch kurz ein Stück nach oben oder unten verschiebt). Ich möchte es eher wie bei meinem Vorgängerprogramm und -skinsystem machen, also mit Sprüngen.
Ich muss anhand der Listboxposition den Regler setzen. Oder habe ich dich falsch verstanden ? Wenn das stimmt: Wie komme ich überhaupt von der Maus-Position und Scrollbarhöhe auf die Position der Listbox. Dein Code basiert doch auf der Position des Reglers ? Im Anhang sieht man die alte Version meines Players mit dem alten bzw. veralteten Skinsystem. Für die neue Version dieses Programms programmiere ich das Skinsystem. Die alten Skins werden so wie es scheint, direkt übertragen, das heißt was du hier siehst, sieht in der neuen Version - solange der Skin aktiv ist - genauso aus. Die Trackbar rechts neben der Playlist (sie ist wirklich daneben wie man sehen kann), ist mein Ziel. Man sieht bei meiner Playlist zwar nicht alles, aber dass es eine Trackbar ist sollte das Ziel nochmal besser zeigen, weil eine TrackBar stufenweise den Regler bewegt (bei einer TTrackBar den Tick anzeigen lassen und die Sprungstellen werden mit Strichen markiert).
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Nils schrieb:
Zitat:
Dein Code basiert doch auf der Position des Reglers ?
NEIN.
Der Umrechnungsfaktor "UserToIntern" rechnet Listboxzeilen in ScrollBarpositionen um
Der Umrechnungsfaktor "InternToUser" rechnet ScrollBarpositionen in Listboxzeilen um (und ist demgemäß der Kehrwert des Faktors "UserToIntern")
Du musst genau unterscheiden, was Du grade brauchst.
Da ich beide Faktoren habe, gibts folgende zwei Möglichkeiten:
1) die Listbox will der Scrollbox die Position vorgeben: Kommunikationsrichtung ListBox ==> ScrollBox In dem Fall richtet sich der Regler nach der Listbox
2) die Scrollbox teilt der Listbox mit, dass der Benutzer am Regler herumfummelt: Kommunikationsrichtung ScrollBox ==> ListBox In dem Fall richtet sich die Listbox nach dem Regler
Zitat:
Ich muss anhand der Listboxposition den Regler setzen. Oder habe ich dich falsch verstanden ? Wenn das stimmt: Wie komme ich überhaupt von der Maus-Position und Scrollbarhöhe auf die Position der Listbox.
Du machst auf mich grade einen ziemlich verwirrten Eindruck. Tut mir leid, ich wollte Dich nicht verwirren. Du hast mit diesen beiden obigen Umrechnungfaktoren wie ich oben gesagt habe, immer beide Kommunikationsrichtungen. Ich muss gestehen, dass ich - als ich das ganze geschrieben habe, auch an einem Punkt ziemlich verwirrt war. Ich habe mir damit beholfen, die Nomenklatur für mich so deutlich wie möglich zu machen. Aus dieser Zeit stammt auch "UserToIntern". Wenn Dir das zu wenig deutlich ist, nenne es "ÜbersetzteListboxzuScrollBox" oder so ähnlich.
Um Deine Frage zu beantworten:
Gegeben: Mausposition und Regler.Top
Gesucht: ListboxZeile
Aber eine Frage ist noch offen:
Ich bewege den Regler und will die Listbox beeinflussen, daher InternToUser.
Angnommen man hat die Zeile wie du sie genannt hast: ListBoxZeile = (Regler.Top - Border1) * InternToUser. Dann bewegt man den Regler und die Listbox bewegt sich im richtigen Verhältnis. Aber der Regler selbst ist ein zusätzliches Problem: Er soll sich eben wie schon gesagt wie ein Trackbar-Regler verhalten. Man muss sich aber zwischen InternToUser und UserToIntern entscheiden, beides geht wohl kaum, denke ich. Daher frage ich mich, wie ich die Sprünge des Reglers hinbekomme.
Habe nochmal längere Zeit drüber nachgedacht:
Man hat die Reglerposition in Pixeln und rechnet das auf die Userposition (Listboxposition) um. Von der Userposition rechne ich nun wieder zurück auf den Regler und setze ihn. Dann hätte man allerdings eine typische Scrollbar und keine Sprünge während der Bewegung selbst.
Du brauchst dich nicht für meine Dummheit zu entschuldigen, die Begriffe haben mich nicht verwirrt, ich weiß jetzt gerade sowieso nicht mehr, was daran so verwirrend war.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Zitat:
Du brauchst dich nicht für meine Dummheit zu entschuldigen
Das hat nichts mit Dummheit zu tun, sondern ist ein Problem der Synchronisierung: Die Welt in Deinem Kopf sieht anders aus als meine. Damit wir uns verstehen, müssen wir uns erst auf gemeinsame Begriffe einigen usw. Das passiert jedesmal, wenn Leute aufeinandertreffen, die sich gar nicht kennen. Dass wir uns auch nicht gegenübersitzen, macht es noch zusätzlich schwerer.
Zu Deinem Regler: Du willst dem Regler nur gestatten, ganz bestimmte Positionen einzunehmen. Das ist für mich jetzt eigentlich nur ein Problem des Reglers. Wenn der Benutzer den Regler nach unten zieht, hüpft der Regler auf die nächste erlaubte Position, nicht auf die nächste Pixelposition. Dabei prüft der Regler die Mausposition, die er reinkriegt und vergleicht Maus.Y mit seinem eigenen Regler.Y. Auf welche Position er springt, kommt jetzt auf die Differenz (Regler.Y - Maus.Y) an.
Annahme: Wir haben den Koordinatenursprung oben links. Wenn in diesem Fall Maus.Y > Regler.Y, dann genügt ja doch ein einfaches
Inc(Regler.Y, FixeDistanz)
wenn es genügt, dass er immer nur EINE Position weiterspringt.
Wenn das erledigt ist, kann man wieder die Listboxzeile mit der obigen Formel berechnen, denn die Formel ist allgemeingültig. Die Folge davon ist aber, dass er in der Listbox AUCH hüpft. Willst Du das so?
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Der Regler repräsentiert die gesamte Textlänge, von der man nur einen Ausschnitt sieht, sonst bräuchte man ja gar keinen Regler.
Wenn man dem Regler nur ganz bestimmte Positionen erlaubt, repräsentieren diese Positionen auch nur ganz bestimmte Zeilennummern des Textes. Diese Zeilennummern haben eine bestimmte Distanz zueinander. Wenn der Regler also weiterspringt, muss auch die Listbox ein paar Zeilen weiterspringen, sonst sind sie nicht mehr synchron. Oder sollen sie das gar nicht sein?
Ah, habe ich verpeilt. Dann stimmt es. Es macht auch keinen Sinn bei wenigen Einträgen, einen einzigen Eintrag pro Bewegung des Reglers weiterzuscrollen finde ich.
uPos ist die Reglerposition in Pixeln. Die Trackbar ist eine Klasse, daher muss ich Y über eine Variable (uPos) an die Zeichenprozedur der Trackbar weiterleiten. Ich zeichne auf ein TImage. Daher ist der Top-Wert der Trackbar und in dem Fall auch Listbox Image.Top. Nun bekomme ich am Anfang des Scrollvorgangs eine Zugriffsverletzung "Listenindex überschreitet das Maximum -32". Da ich trotzdem einfach mal wissen wollte, ob es wenigstens annähernd funktioniert, habe ich ganz kurz ein - eingesetzt: Pos := -Round((uPos-Image.Top)*InternToUser); So scrollt die Trackbar in die falsche Richtung, aber man sieht wenigstens ob der Ansatz einigermaßen stimmt. Er stimmt, es sah nicht schlecht aus. Wenn ich dann zu weit runterscrolle, erhalte ich logischerweise wieder die nette Zugriffsverletzung - ich habe es ja auch nur "gespiegelt". Siehst du einen Fehler ? Hier ist nochmal der obige Code umgeschrieben. So sollte er für dich leichter zu verstehen sein. Falls du dort keinen Fehler findest, habe ich irgendwelche Bezeichner durcheinander gebracht, aber das hätte ich denke ich schon selbst gefunden:
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Code:
UserRange:=Abs(Max-Min)+1;
if UserRange =0then
UserRange :=1;
Das sieht für mich in Ordnung aus. Bei der Userrange nehme ich den Absolutwert der Differenz [Abs(Max-Min)], weil bei mir rein theoretisch der User auch negative Werte für Max und Min eingeben kann. Normalerweise ist Min Null, dann ist der Absolutwert hier eine reine Fleißaufgabe.
Wenn Du bei der Berechnung der SliderRange genau hinsiehst, fällt das Image.Top weg (einmal +Image.Top und einmal -Image.Top gibt Null). Dann siehst Du auch, dass das +1 zum Schluss weg gehört, denn dann bleibt über: SliderRange = Image.Height. Und das ist auch logisch. Das heißt also, im großen und ganzen stimmt das auch, bloß das (+1) sollte eliminiert werden.
Die Berechnung der Listbox-Zeile schaut auch richtig aus. Regler.Top MUSS immer größer oder gleich dem Image.Top sein, dann funktioniert es.
Das Y kann ich nicht beurteilen, weil ich nicht sehe, woher Du das hast. Gleichzeitig ist das Y aber der Knackpunkt bei der ganzen Sache. Das Y hat folgenden erlaubten Bereich:
Wenn Dein Y das Maus-Y ist, kann es den erlaubten Bereich auch verlassen, denn der User kann die Maus hinführen, wohin er will. Wo immer Du das Y auch herhast: Du musst unerlaubte Bereiche im Ansatzpunkt abfangen. Auch das ist logisch: wenn dieses Y im unerlaubten Bereich ist, dann reitet Dein Regler nach oben oder unten über die Grenzen des Image aus. Das sollte leicht zu überprüfen sein: es ist am Bildschirm zu sehen.
Danke, dass du doch noch schreiben konntest. Ich habe die Fehler korrigiert. Und das mit dem Mausbereich war der Grund für die Zugriffsverletzung. Es verhält sich die Scrollbar derzeit noch etwas seltsam. Diese Werte (alle Pos-Werte) verdeutlichen dies (Max ist übrigens 40):
Code:
0
0
0
0
0
0
[...]
0
0
0
1
1
1
1
2
2
2
2
2
2
3
3
3
3
3
3
3
3
3
4
4
4
4
4
4
4
5
5
5
5
5
6
6
6
6
6
6
6
6
7
7
7
7
7
7
7
7
7
7
8
8
8
8
8
8
8
9
9
9
9
9
9
9
10
10
10
10
10
10
11
11
11
11
11
11
11
12
12
12
12
12
12
12
Die letzten Werte befinden sich außerhalb des Maximums. Wie die Werte zeigen, macht der Regler einen riesigen Sprung am Anfang. Man muss die Maus dafür so wie es scheint einen Schritt herunterbewegen.
Ich Idiot! Mir ist gerade aufgefallen, was ich vorerst programmieren wollte: Eine Scrollbar, welcher erst später zur Trackbar umgebaut wird. Daher muss ein großer Sprung stattfinden. Aber warum muss es dennoch über das Maximum hinauslaufen um überhaupt den letzten Eintrag jemals zu sehen ? Weil Pos falsch ist. Wenn man 12 mit 40 vergleicht, ist klar, dass es noch weiter runtergehen darf und muss. Also ist die Berechnung von Pos falsch. Der Code erscheint mir allerdings richtig. Ein Sprung nach ganz oben ist übrigens nicht möglich, sollte er aber sein. Falls du es vergessen hast: Pos ist die Listboxzeile.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hallo Nils,
Wenn das die Werte der Trackbar sind (denn Pixelwerte können es ja keine sein), dann sehe ich keinen Sprung. Die Werte gehen von Null ziemlich kontinuierlich nach 12.
Ich bin jetzt aber ein wenig unsicher, was das Restproblem ist. Der Slider geht über die MaximalPosition hinaus? Wenn ja, wie weit geht er hinaus? Ist der Maximalwert 12 der richtige Maximalwert oder nicht? Wo genau befindet sich der Slider, wenn er seine Maximalposition einnimmt? Ich sitze hier irgendwie am toten Ende...
Die Fehlerquelle habe ich noch nicht gefunden, aber es scheint mit der Höhe der Trackbar/Listbox zusammenzuhängen. Schau dir einfach folgendes Testprojekt an. In der uSkinDraw geht in Zeile 884 der entscheidende Code los. Er geht nicht weiter als bis zum nächsten end; In der sich am Anfang öffnenden code.pas kannst du die Höhe der Listbox und Scrollbar beide verändern. Schadet aber nicht, wenn beide immer auf der gleichen Höhe sind. Je höher die Top-Werte, desto größer der Sprung am Anfang. Warum dieser Fehler auftritt ist mir unklar, habe viel probiert. Probier am Ende auch die Scrollbar auf 0 hoch zu bewegen. Abgesehen davon solltest du eben immer warten, bis die Einträge in der Listbox angekommen sind. Warum das so lange dauert weiß ich nicht.
Ich hoffe du kannst das Projekt einwandfrei kompilieren. Delphi7 macht bekannterweise mit PNG Ärger, daher musste ich gewisse Units hinzufügen. Werde das Projekt gerade deshalb auch bald nach Lazarus portieren.
Mitglieder in diesem Forum: 0 Mitglieder und 10 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.