ich habe ein eigenes Skinsystem, welches auf Canvas basiert. Es zeichnet und verwaltet also die Komponenten vollkommen unabhängig von der Windows- bzw. Linux-GUI. Das ist zwar alles schön und gut, aber da ich es wirklich selbt mache, gibt es auch mehr Probleme. Ich hänge schon über einen Monat an folgendem Problem:
Eine ListBox benötigt eine vertikale Scrollbar. Die Scrollbar ist eine Trackbar mit einem leicht anderen Design, also in dem Sinne wirklich eine nicht nennenswerte Abwandlung meiner eigenen TrackBar. Mein Problem bei der TrackBar: Wie berechnet man das ? Es gibt in zwei Dimensionen bei meiner Trackbar: Pixel- und eine Umwandlung der Pixel-Dimension. Die Pixel-Dimension ist die Position des Reglers in Pixeln (für das Zeichnen des Reglers nötig), die andere ist vergleichbar mit TTrackBar.Position --> sie bezieht sich auf den Max- (und Min-)Wert. Bei einer Listbox ist es sinnvoll, den Min-Wert auf 0 zu lassen und den Max-Wert auf die Anzahl der Einträge der Listbox zu setzen. Als Angaben habe ich den Y-Wert in Pixeln, die Höhe der Trackbar in Pixeln und den Max-Wert in eigener Dimension. Ich muss die Position des Reglers in Pixeln und der anderen Dimension berechnen. Angenommen ich löse nach Y eigener Dimension auf, erhalte ich Y~=Y/Height*Max~ (~ steht für eigene Dimension). Dann reagiert die Trackbar allerdings auf jede Mausbewegung. Der Regler soll Sprünge machen, sich also nur bewegen wenn notwendig (wie man es von einer Scrollbar kennt). Wie könnte man dies lösen ?
Ich habe extra keinen Code mit angegeben, da es denke ich sinnvoller ist, dieses Problem im theoretischen Bereich zu lösen und später auf das praktische umzusetzen. So sollte es euch auch leichter fallen, mir zu helfen.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Das müsste klappen, wenn du das Ergebnis von Y/Height rundest (mit Round) bevor du mit Max multiplizierst (ich hoffe, ich habe dein Problem jetzt richtig verstanden)
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
tmp1 und tmp2 sind Kommazahlen, Pos (umgerechnete Pixel-Position) und uPos (Pixel-Position) ganze Zahlen. Mit diesem Code bewege ich den Regler so, dass er immer genau dem Cursor folgt. Wenn ich nun Y / Image.Height mit Round runde, ist das extrem gerundet: Es gibt bei einer Bewegung über die Höhe der Scrollbar hinaus eine Veränderung von 0 auf 299 Pixel. Das ist eine vollkommen falsche Dimension.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hallo Nils.
Ich hätte hier funktionierenden Code für eine ScrollBar. Die Prozedur rechnet die Werte des jeweiligen Benutzers (z.B. eine Listbox = "User", Dimension: Zeilen-Indices) in die Werte der ScrollBar um ("Intern", Dimension: Pixel).
Zu diesem Zweck berechnet sie die Umrechnungsfaktoren ("Translation Factors") "UserToIntern" und "InternToUser" als Gleitkommazahlen.
Border1 und Border2 sind die oberen und unteren Grenzen für den Slider. Wenn Du Knöpfe auf Deiner Scrollbar hast, musst Du diese Knöpfe auch bei den Borders berücksichtigen.
Die Slider-Größe wird hier auch berechnet, weil es hier einfach der geeignetste Platz dafür war.
Code:
Procedure TGUIScrollBar.CalcTranslationFactors;
Var UserRange,SliderRange: TInt32;
Begin
// Calculate UserRange
UserRange:=Abs(fMax-fMin)+1;
If UserRange =0
Then UserRange:=1;// Division by zero!
// Calculate SliderRange
With fSlider Do SliderRange:= Border2-Border1+1;
If SliderRange =0
Then SliderRange:=1;// Division by zero!
// Calculate translation factors
fUserToIntern:= SliderRange/UserRange;
If fUserToIntern =0
Then fUserToIntern:=1;// Division by zero!
fInternToUser:=1/fUserToIntern;
// Calculate slider size
fSlider.Size:=Trunc(fLargeChange*fUserToIntern);
End;
Wenn jetzt der Benutzer den Slider schiebt, teilt der Slider das seiner Scrollbar mit, die Scrollbar berechnet die neue User-Position und berichtet ihrerseits an den User:
ich habe probiert es umzusetzen, leider bewegen sich weder Regler noch Listbox-Einträge. Die Stelle mit dem nur für eine Zeile geltenden with bei deinem Code ist für mich schwer zu verstehen: Ist die lokale Variable SliderRange eine andere als fSlider.SliderRange ? Ich denke schon, aber wo liegt der genaue Unterscheid ? Alle Variablen enhalten unabhängig von der Reglerposition die gleichen Werte.
Das ist mein bisheriger Code:
Code:
UserRange:=Abs(Max-Min)+1;// Min=0; Max=1
if UserRange =0then
UserRange :=1;
// with fSlider do
SliderRange :={Border2-Border1+}1;// Border2-Border1 habe ich bewusst weggelassen. Da meine Scrollbar keinen wirklichen Border hat, dürfte das keine Probleme machen.
if SliderRange =0then
SliderRange :=1;
UserToIntern := SliderRange/UserRange;
if UserToIntern =0then
UserToIntern :=1;
InternToUser :=1/UserToIntern;
Pos:=Round(Top*InternToUser);// Pos ist die User-Variable, wie du sie nennst
uPos :=Round(UserToIntern);// uPos wird zum Zeichnen verwendet
Da die Werte der Variablen immer gleich sind, hier die immer wieder auftretenden Variablen. Die Listbox hat 41 Einträge.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Nils schrieb:
Zitat:
Border2-Border1 habe ich bewusst weggelassen.
Aber genau die sind essentiell.
SliderRange kann gar nicht 1 sein, das ist definitiv nicht möglich, weil das nämlich die Strecke ist, in der sich der Slider bewegen kann.
Wenn die ScrollBox keine Knöpfe hat, repräsentiert die SliderRange daher die Höhe der ScrollBar in Pixel, also sagen wir mal, sie wäre 300 Pixel hoch.
Border1 ist bei uns das gleiche wie das ScrollBarTop, also sagen wir mal eine Hausnummer: Border1 = 25.
Weiter folgt daraus dass Border2 gleich dem ScrollBar.Top+ScrollBar.Height ist, also Border2 = 25+300-1 = 324
UserRange: Min=0, Max=40, UserRange = Max-Min+1 = 40-0+1 =41
SliderRange ist Border2-Border1+1 = 324-25+1 = 300 (nochmal: das ist die Strecke, auf er sich der Slider bewegen kann, Dimension: Pixel)
Der Benutzer hat jetzt den Slider bewegt (seine Position hat sich schon verändert).
Was haben wir zur Verfügung? Das Top des Sliders sowie Border1 und Border2.
Das Top des Slider muss sich zwischen Border1 und Border2 befinden, sonst haben wir etwas falsch gemacht. Also sagen wir mal, das Slider.Top ist jetzt bei 120.
Die interne Scrollposition in Pixeln errechnet sich so: Intern Position = Slider.Top - Border1 = 120 - 25 = 95
Die UserPos (=ZeilenIndex der Listbox) errechnet sich so: UserPosition = ScrollPosition * InternToUser = 95*0,1376 ~ 13
In der Listbox heißt das, wir sind bei Zeile 13. Und wenn wir hier nicht zwischen 0 und 40 herauskommen, haben wir auch etwas falsch gemacht:
Interne Position 0 ===> UserPosition = 0*0,1376 = 0
Interne Position 299 ===> UserPosition = 299*0,1376 = 40,87
Holla, hab ich einen Fehler gemacht. Warum? Weil die Rechnung
Maximale Userposition = Maximale Interne Position * InternToUser genau 40 ergeben muss.
Und wie erreichen wir das? Indem wir die obigeRechnung
UserToIntern:= SliderRange/UserRange = 300/41 = 7,3171 korrigieren auf
UserToIntern:= SliderRange/UserRange = 299/40 = 7,475
InternToUser:= 1/UserToIntern = 1/7,475 = 0,1338
Interne Position 299 ===> UserPosition = 299*0,1338 ~ 40
Ich danke für das Aufdecken eines Bugs in meiner GUI.
Ganz wichtig ist, dass Du verstehst, was Du da genau berechnest. Zeichne Dir das ganze an besten auf.
Übrigens, wenn Du Dir die obige Rechnung genau überlegst, wirst Du draufkommen, dass das Slider.Top nur dann die maximale Position von 299 einnehmen könnte, wenn seine Höhe Null wäre. Da aber Slider immer eine bestimmte Höhe haben ist das nicht möglich. Wenn Du mit der obigen Rechnung klargekommen bist, können wir darüber reden.
Viele Grüße,
Traude
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Darf ich fragen, was uPos ist? Ich sehe, wie Du es berechnest, aber ich verstehe nicht, wozu Du es brauchst.
Der Umrechnungsfaktor UserToIntern braucht alle seine Kommastellen. Und ich wüßte nicht, was man mit einem gerundeten Wert anfangen kann.
Alles andere sieht für mich schon recht ordentlich aus.
Zuletzt geändert von Traude am Do Jun 19, 2008 16:32, insgesamt 1-mal geändert.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Das glaub ich Dir nicht. Wenn als Userposition 40 herauskommt, dann heißt das, das der Regler(=Slider) auf seiner Maximalen Position steht. Und die ist in unserem Beispiel von mir aus 300 , wenn wir es relativ sehen(als Bereich), oder 325, wenn wir es absolut sehen (als Fensterkoordinaten), aber ich wüßte nicht, wie es zu einem Wert von 7 kommen kann.
Jo, die 40 ist falsch. er wäre denke ich bei ungefähr 2. Die 7px stimmen aber, denn ich habe den Regler nur ein kleines Stück nach unten bewegt. Danach konnte man ihn wegen der 40 nicht mehr weiterbewegen. Daher denke ich, dass die 7px stimmen, allerdings die 40UserEinheit nicht.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Welche Höhe in Pixeln hat Dein Regler? Oder andersrum gefragt, wie sind die Abmessungen und Positionswerte (Left/Top/Width/Height) Deiner Listbox und Deiner ScrollBox?
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Das macht nichts. Was wir hier zunächst brauchen ist ein beiderseitiges Verständnis, was wir hier tun, wir reden nämlich irgendwie aneinander vorbei.
Was genau hast Du als Angaben und was möchtest Du berechnen? Zur Orientierung, was ich damit meine:
Ich nehme das aktuelle Regler.Top und rechne das in die ScrollBarposition um, also in eine Position relativ zur ScrollbarRange (genauer: eine Position mit Minimum Null und Maximum 300 und dazwischen ist sie irgendwo).
Diese Position rechne ich jetzt in eine Zeile der ListBox um, das ist eine Position mit Minimum Null und Maximum 40 und dazwischen ist sie irgendwo. Das braucht die Listbox für die richtige Darstellung ihrer Zeilen.
Ich rechne mich also von der Reglerposition in Richtung Listbox-Zeile, bildlich ausgedrückt.
Was mich nämlich stutzig gemacht hat: ich muss zu diesem Zeitpunkt den Regler nicht mehr zeichnen, das ist schon längst erledigt. Die Position des Reglers ist für mich INPUT, und bei Dir scheint es der OUTPUT zu sein.
Deshalb wäre gut zu wissen, wovon Du ausgehst und was Du eigentlich berechnen möchtest.
Ich habe jetzt gerade oben nachgelesen und gesehen, dass Du genau umgekehrt rechnest. Du hast eine Bildschirmposition gegeben (der MausKlick) und möchtest die Reglerposition berechnen, ist das richtig?
Mitglieder in diesem Forum: 0 Mitglieder und 7 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.