Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
OK ich habs jetzt und er kompiliert auch. Ich seh es mir heute abend an. Vorweg: Er mag die Position Null nicht. Könnte was damit zu tun haben, dass der Code gewaltsam auf eins gesetzt wird, wenn er durch Null dividieren möchte. Wenn das stimmt, muss man die Berechnung daran anpassen. Ich muss mich jetzt aber ausklinken,
bis heute abend,
Traude
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Sorry Für das Doppelpost.
Hallo Nils,
bei Deiner ListBox ist eine grüne Zeile, in der die ListboxZeile Null steht. In Deinem Programm (uSkinDraw Zeile 884 ff.) hat Das Image.Top (das müsste das Image der Schrollbar sein) einen Wert von 11. Wenn man mit dem Debugger gleich nach Programmbeginn dorthin kommt, hat das Maus.Y z.B. einen Wert von 3 oder 4 und das Image.Top einen Wert von 11. Und da der Code eine Position, die kleiner als das Image.Top ist nicht zulässt, setzt er das uPos richtigerweise auf 11 und dadurch springt der Regler auf Pixelposition 11. Für den User sieht es so aus, als ob er willkürlich springt.
Allerdings: zu diesem Zeitpunkt war die Maus mitten in dieser grünen Zeile drin und hier sollte meiner Meinung nach das Maus.Y schon längst größer sein als das Image.Top. (Die grüne Zeile ist doch auch Bestandteil der Listbox - oder?) Es sieht für mich so aus, also ob das Image.Top erst am unteren Rand der grünen Zeile wäre.
In der Unit "Code" auf Zeile 47 erzeugst Du die ScrollBar, und ich habe ausprobiert, den Parameter Top von 11 auf 1 auszubessern und dann springt der Regler nicht mehr. Ist aber natürlich keine Lösung, weil schaut nicht gut aus. Aber wie Du Deine Skins anordnest, musst Du selber wissen.
Also ist Y in einer falschen Dimension ? Genügt es, Y umzurechnen, also Y := Y+Image.Top; ? Dann stimmen die Dimensionen denke ich, aber er hüpft immer noch. In der Draw-Prozedur wird jedoch in einer anderen Dimension gerechnet. Daher habe ich zumindest eine kleine Übergangslösung: Am Anfang von der Draw wird folgender Code geschrieben:
Code:
uPos := uPos-Image.Top;
if uPos < 0then
uPos :=0;
Ich glaube kaum, dass man das aus Schönheit so lassen kann, nur so funktioniert es wenigstens. Und eigentlich ist es gar nicht mal so sinnlos wie es scheint: Die Zeile "Pos := Round((uPos-Image.Top)*InternToUser);" benötigt Image.Top zur Berechnung, die Zeichenprozedur rechnet anders und sollte Y+Image.Top niemals verarbeiten, da es für sie einfach falsch ist. Diese Methode hat so wie es scheint allerdings Kinderkrankheiten: Wenn man den Regler absetzt und die Maus von der Trackbar wegbewegt, bewegt sie sich automatisch nach oben auf 0 (allerdings nicht in einem Schritt, die Bewegung ist komplett sichtbar). Irgendetwas läuft noch schief in Bezug auf Max: Man kann unendlich weit runterscrollen und das Verhältnis zur Listbox stimmt derzeit auch nicht, da die unterste Position der Trackbar (oder sagen wir lieber: beim unteren Border) so weit scrollt, dass der letzte Eintrag in der Listbox ganz oben steht.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Nils schrieb:
Zitat:
Also ist Y in einer falschen Dimension ?
Nein, Nils. Die Dimension ist Pixel und die ist schon in Ordnung. Ich meine, dass irgendetwas nicht stimmt mit den Werten [Left/Top/Width/Height], die Du in der Unit "Code" in den Konstruktor der Listbox und der ScrollBox einfüllst. Beim Debuggen war eindeutig zu sehen, dass zu einem Zeitpunkt, wo der Benutzer im guten Glauben ist, sich schon über der Scrollbar zu befinden, er in sich in Wirklichkeit ein Stück darüber befindet. Der Benutzer wird also durch den visuellen Eindruck getäuscht.
Zitat:
Diese Methode hat so wie es scheint allerdings Kinderkrankheiten: Wenn man den Regler absetzt und die Maus von der Trackbar wegbewegt, bewegt sie sich automatisch nach oben auf 0
Hm. Kriegst Du eigentlich immer alle MausMoves mitgeteilt, auch wenn sich die Maus garnicht über der ScrollBar befindet?
Zitat:
Irgendetwas läuft noch schief in Bezug auf Max: Man kann unendlich weit runterscrollen und das Verhältnis zur Listbox stimmt derzeit auch nicht, da die unterste Position der Trackbar (oder sagen wir lieber: beim unteren Border) so weit scrollt, dass der letzte Eintrag in der Listbox ganz oben steht.
Ha, ja. Erinnerst Du Dich, dass ich irgendwo oben gesagt habe, "Wenn Du mit der obigen Rechnung klargekommen bist, können wir darüber reden." Jetzt ist es soweit.
Du musst Dir darüber klarwerden, was Du da machst. Du ordnest Reglerpositionen den ListboxZeilen zu und zwar so:
SliderPosition = Image.Top + 0 ===> Oberste ListboxZeile ist ListboxZeile 0
SliderPosition = Image.Top + X ===> Oberste ListboxZeile ist ListboxZeile irgendwie
SliderPosition = Image.Top + Image.Height ===> Oberste ListboxZeile ist die letzte ListboxZeile [40]
Das ist auch richtig und sollte auch so bleiben, denn wir wollen ja eine eindeutige Zuordnung - Reglerposition => ListBoxZeile haben.
Das Verschwinden des Textes nach oben ergibt sich aus der Tatsache, dass Du beim Zeichnen der Listboxzeilen einfach mit der errechneten ListboxZeile anfängst. Und wenn Du mit der letzten ListboxZeile anfängst, sieht man nicht mehr viel Text. Das ist kein Fehler, das machen alle so.
Bei einer ScrollBar hat man das Problem nicht, denn hier repräsentiert die Slider-Länge immer die Länge einer Seite, längere Texte haben einen kürzeren Slider, eine Tatsache, die Du ganz einfach in irgendeinem Textverarbeitungsprogramm überprüfen kannst. Meine Lösung dazu war einfach: mein Slider blockiert, wenn er an der oberen oder unteren Grenze angekommen ist. Da die Sliderlänge im allgemeinen die Länge einer Seite repräsentiert, errechnet die letzte mögliche Sliderposition NICHT die letzte Listboxzeile, sondern:
Letzte oberste angezeigte Zeile = Maximale ListBoxZeile[40] minus Anzahl Zeilen pro Seite[23] = 17.
(könnte auch sein dass man noch eins dazuzählen muss, also 18 ).
So wie ich das jetzt sehe, können wir das hier so nicht machen. Daher musst Du dieses Blockieren selber simulieren. zB so: Du errechnest Dir die ListboxZeile so wie bisher (die Info, welche Listboxzeile es ist wollen wir ja haben), aber wenn Dir eine Zeile herauskommt, die größer als 17 ist verwirfst Du sie und zeichnest immer ab Zeile 17. Man könnte sagen, die Listbox "blockiert".
Es gibt natürlich auch einen Workaround, indem man die UserRange auf 17 setzt (man tut so, also ob man einen kürzeren Text hätte). Mir gefällt diese Lösung aber nicht, weil ich dann keine richtige Zuordnung ReglerPosition => ListboxZeile habe. Für ein Präzisionsinstrument wäre ein solcher Regler nicht geeignet.
Nun funktioniert alles. Dank ein paar Umwegen, wird von Max vor den ganzen Berechnungen (InternToUser usw.) die Anzahl der sichtbaren Einträge abgezogen, solange sich der Max geändert hat. Das klappt nun, vielen Dank für die ganze Hilfe und Deine Geduld!
so leid es mir tut, ich habe neuerdings wieder Probleme mit der Scrollbar. Ich weiß absolut nicht, was ich geändert habe. Fakt ist, dass es wieder Ärger gibt. Im Anhang ist ein Projekt. Schaut es euch bitte an. Ich habe eigentlich alles mitgeliefert. Klickt zunächst auf die Listbox, damit die Einträge sichtbar werden. Ich weiß nicht warum, man erst im Testprojekt draufklicken muss, im Hauptprogramm ist es jedenfalls nicht so. Ihr seht dann eine Listbox mit Einträgen von 0 bis 22. Scrollt komplett runter. Nun dürftet ihr die Einträge 27 bis 49 sehen. Soweit funktioniert alles. Nun scrollt komplett hoch. Ihr seht nun 1 bis 23 und genau das ist der Fehler. Nun kommentiert ihr die for-Schleife in OnCreate der code.pas aus (als 1. kommentiert) und kommentiert LoadPlaylist(...) (als 2. kommentiert) ein. Dann das gleiche Spiel, allerdings ein anderer Fehler:
Scrollt man leicht runter, wird weiter als nötig gescrollt und wenn man danach bis zum Ende scrollt korrigiert die Scrollbar den Fehler. In beiden Fällen kann man nicht mehr voll hochscrollen. Jedoch ist der Fall mit LoadPlaylist schlimmer und ich kann mir überhaupt nicht erklären warum.
Trotz des Projekts hier der relevante Code. Er ist eigentlich idiotisch einfach aufgebaut: Er besteht aus der uSkinFile (die uns in dem Fall zwar als Basis dient, jedoch nicht interssiert) und der uSkinDraw. Also bezieht sich alles was nun folgt auf die uSkinDraw.pas:
In der Draw-Prozedur der TSkinTrackBar wird geprüft, ob es eine Scrollbar oder eine Trackbar ist. Es ist in unserem Fall eine Scrollbar, daher steht Mode auf True. Die Scrollbar ist vertikal, daher steht Vertical auf True. So reduziert sich das relevante auf ein Minimum und ich habe den entsprechenden anderen Code zur Übersichtlichkeit für euch aus dem Testprojekt entfernt. In MouseMove gibt es die gleichen If-Abfragen, welche ich ebenfalls reduziert habe.
In dem Array Pic sind alle einzelnen Grafiken in Form von Bitmaps drinnen. Die Prozedur LoadSkin befüllt das Pic- und Col-Array. Im Col-Array sind Ersatzfarben gespeichert.
Die Skinlistbox ist einfach aufgebaut. Es gibt eine Variable ItemHeight auf der alles aufbaut. Denn aus der Höhe eines Eintrags lässt sich vieles berechnen, da alle Einträge gleich hoch sind. Wenn man die Listbox mit dem richtigen Parameter erzeugt, generiert sie eine dazu passende Scrollbar. Jede Scrollbar hat eine Prozedur namens Scroll, welche sich von TSkinTrackBarScroll ableitet und welche die Listbox scrollt. Daher wird die Prozedur genau dann aufgerufen, wenn die Scrollbar fertig gezeichnet und verschoben ist und der rechte Zeitpunkt gekommen ist, die Listbox an die Scrollbar anzupassen.
Der Code ist in meinen Augen ziemlich der gleiche wie ich ihn vor langer Zeit mit Traude zusammengestellt habe. Es gibt daher die interne Reglerposition der Scrollbar und die User-Position (=die Äußere <-- das was man sieht). Es wird immer wieder umgerechnet mithilfe von dem Faktor InternToUser und UserToIntern. Der Rest ist denke ich gut am Code zu sehen.
Außerdem ist die uAudio extrem gekürzt, sie hat fast nichts mehr mit dem Original zu tun, also seid nicht schockiert, wie sinnlos sie aufgebaut ist.
Ich hoffe, ich konnte den Code soweit gut erklären. Falls nicht, dann schmeißt den Code bitte nicht in die Ecke, sondern fragt einfach nach, was ihr nicht versteht. Es ist kein leichtes Problem. Daher halte ich es für wichtig, dass ihr gerne mal kleine Nachfragen stellt, selbst wenn ihr die ein oder andere am Code sehen könntet, jedoch nur keine Lust habt, alles komplett durchzuarbeiten - was ich gut verstehen kann. Es ist mit Delphi nicht so gut wie mit der opbitmap-Bildbibliotheksammlung die nur unter Lazarus läuft möglich, abgesehen von BMP und JPEG Bilder zu laden. Daher konnte ich zumindest heute leider kein Delphi-Projekt, sondern nur ein Lazarus Projekt erzeugen. Oben habe ich ja geschrieben, dass es nötig sei, Teile abzuändern und wieder zu schauen. Im Anhang sind beide Varianten als Exe drinnen, damit ihr auch ohne Compiler auskommt.
Hier die uSkinDraw.pas wie sie dem Testprojekt beiliegt. Das Testprojekt erhaltet ihr hier.
phRegler, hRegler, shRegler :Integer;// shRegler = Zuerst gesetzt Höhe ODER Breite des Reglers; hRegler = Höhe des Reglers, kann auch als wRegler eingesetzt werden
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hallo, Nils,
Heute bin ich viel zu müde, um noch grade schauen zu können, aber morgen kann ich es mir mal ansehen. Aber ich hätte dafür eine Bitte. Ich habe mich die letzte Zeit mit Linux und dem X11 Server beschäftigt. Ich möchte gerne OpenGL-Programme in Linux ohne SDL laufen lassen können und habe schon etwas gebastelt, das bei mir lauffähig ist. Meine Umgebung ist Lazarus unter Ubuntu. Hast Du eine Linux-Umgebung zur Verfügung? Wenn ja, kannst Du mein Lazarus-Programm mal bei Dir ausprobieren? Ich kann es hier nur auf meinem eigenen Computer testen, denn ich lebe mit lauter Windows-Menschen zusammen. Wenn Du einverstanden bist, hänge ich den Source Code morgen hier herein.
Traude
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hier mal mein Testprogramm (Lazarus-Sourcecode für Linux, braucht den X11 Server). Ich würde gerne wissen, ob es läuft. Ein Druck auf irgendeine Taste beendet das Programm. Es ist keine besondere Grafikkarte erforderlich.
Dankeschön
Traude
EDIT: habe ein Delphi-Beispiel für eine einfache Listbox mit Scrollbar reingehängt. Sie ist nicht schön, aber behübschen könnt ihr sie ja selber.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
nun endlich Ferien, Feiertage vorbei - endlich wieder mal richtig Zeit zu programmieren und hoffentlich genug um bis zur nächsten Schulzeit die größten anstregenden Programmierprobleme loszuwerden.
Da habe ich gestern und heute mal richtig was gemacht. Deine Scrollbar habe ich komplett an mein System angepasst und daher fast komplett umprogrammiert. Sie ist nicht mehr _ganz_ so perfekt, aber sie funktioniert - sie dient endlich ihrem Zweck, wieso also noch Zeit verschwenden damit. Ich bin gerade dabei, sie in das Hauptprojekt zu integrieren. Nun stellen sich erstmal zwei Fragen, an denen ich grübel:
1. Du hattest eine Variable namens fListIndex, welche die Listbox regelrecht gesteuert hat und als ItemIndex-Ersatz diente wie man es von einer normalen TListBox kennt. Ich möchte nicht, dass fListIndex den ItemIndex ablöst. Kein Thema, einfach nicht mehr einfärben und das Scrollen funktioniert trotzdem noch und sieht gut aus. Aber: Nun bin ich dran, ein OnClick-Ereigniss zu schreiben, denn wenn man auf einen Eintrag klickt, soll dieser natürlich selektiert werden. Daher muss ich nun eine neue Variable namens fItemIndex einführen, die genau dafür da ist. Die Frage ist nun: Wie berechne ich den ItemIndex bzw. fItemIndex auf Basis der Mausposition ? Sehe ich es richtig, dass ich nun ähnlich wie bei der Scrollbar - eventuell sogar mit dem gleichen Faktor (fInternToUser) - den ItemIndex setzen muss ? Ich krieg einfach nicht genau raus, wie man das am einfachsten lösen könnte. Nur um es klar zu sagen: Der ItemIndex bzw. fItemIndex ist auf der Array-Ebene und nicht auf der Pixel-Ebene. Er ist vergleichbar mit dem ItemIndex einer stinknormalen TListBox.
2. Die Scrollbar bezieht sich ja bei der Berechnung des fListIndex auf die eigene Höhe. Nun dachte ich mir, ich bau mir das ganze so zusammen, dass Scrollbar und Trackbar in einer einzigen Klasse sind. Wenn ich also eine Equalizer-Trackbar in einem Audio-Player habe, dann kann ich die Scrollbar wie eine normale Trackbar benutzen. Sehe ich das richtig ? Denn ich sehe keinen wirklichen DIREKTEN Bezug zur Listbox, mir kommt die Scrollbar regelrecht wie ein Dreisatz vor.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hallo, Nils.
Ich finde es toll, dass Du Dein Projekt weitermachst.
Ich habe mir an Dir ein Beispiel genommen und habe auch weitergemacht: ich habe das Beispiel so erweitert, dass es alles macht, was man so von einer Listbox erwartet: nicht nur, dass man den Slider bewegen kann, sondern auch einen Listbox-Eintrag anklicken kann, den man so ähnlich wie in der VCL aus der Listbox herauskriegt. Um das zu demonstrieren, habe ich einen Label ganz unten im Formular, der die ganzen Listbox-Mausklicks mitschreibt. Der ItemIndex, der jetzt in dem Beispiel drin ist, verhält sich ganz genauso wie der TListBox-Itemindex.
Wenn man jetzt eine Zeile anklickt, wird der ItemIndex davon berechnet und diese Zeile wird in der Listbox rot angezeigt. Die Änderungen, die ich gemacht habe, sind in einer Textdatei namens "ChangeLog.txt" im Zip-File beschrieben. Die Berechnung des ItemIndex findest Du in der Listbox-Prozedur "MouseDown". Weil ich nicht in der ersten Zeile der Listbox anfange zu schreiben (fFirstVisibleLine:= 2), sieht es ein wenig wie Gefrickel aus, aber die Berechnung ist nur ganz kurz.
Zitat:
Wenn ich also eine Equalizer-Trackbar in einem Audio-Player habe, dann kann ich die Scrollbar wie eine normale Trackbar benutzen. Sehe ich das richtig ?
Naja, die Scrollbar hat eine Integer-Range. Wenn der Equalizer sich irgendwie in eine Integer-Range hineinquetschen lässt, gehts. Die Scrollbar ist bewusst eigenständig implementiert, damit man sie auch für andere Elemente verwenden kann.
Aber was ist ein Dreisatz?
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
dein neustes Testprojekt hat mir extrem weitergeholen, vielen Dank!
Ich meinte mit Dreisatz, dass Scroll-/Trackbar und Listbox sich gegenüberstehen wie eine Gleichung, also das man auch die Listbox austauschen kann, genauso wie die Scroll- bzw. Trackbar, solange grundlegenste Grundlagen beide Gleichungsseiten erfüllen. Ich meine damit also: Es ist alles so sauber programmiert, dass man keine festen Abhängigkeiten hat.
Die Scrollbar ist ebenso wie die Listbox sehr sauber programmiert. Die Scrollbar ist fast komplett (abgesehen vom IndexEvent) unabhängig von der Listbox. Daher dachte ich, man könnte einfach die Scrollbar mit anderen Grafiken versehen, und statt einer Listbox einfach etwas anderes damit anstellen, zum Beispiel Equalizer-Trackbars. Das wäre doch möglich oder ? Denn über das IndexEvent der Scrollbar sendet diese ja ihre Position. Wenn ich nun den passenden Min- und Max-Wert wähle, ist alles geritzt. Oder sehe ich das falsch ? Ich will kurz gesagt nur wissen, ob man die Scrollbar noch anpassen müsste, um eine normale Trackbar zu bekommen (abgesehen von den Grafiken) oder nicht. Ich denke und hoffe nicht.
Ich habe hier zwar gerade noch eine kleine nette Zugriffsverletzung, welche unerklärlicherweise beim Doppelklick (habe ich noch hinzugefügt) auftritt, die aber nichts mit dem Skinsystem zu tun hat (hoffe ich zumindest, ich weiß noch nicht was genau schief läuft). In dem Sinne, ist hoffentlich dieses Thema nun endgültig - wenn nicht noch ein anderer Interessierter Fragen hat - erledigt, denn den Rest des Skinsystems dürfte ich relativ reibungslos auf die Beine bekommen.
Ich finde es toll, dass Du mir die ganze Zeit so super geholfen hast! Vielen Dank!
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Zitat:
Wenn ich nun den passenden Min- und Max-Wert wähle, ist alles geritzt. Oder sehe ich das falsch ?
Nein, das siehst Du ganz richtig. Ich habe bei mir eine ScrollBar, die genau nach dem gleichen Prinzip funktioniert, in mehrere verschiedene (OpenGL-)Items eingebaut und sie arbeitet sehr gut. Man muss nichts anpassen, solange man eine Integer-Range (ich meine damit den Bereich zwischen Min und Max, das sind ja alles Ganzzahlen) brauchen kann. Wenn Du Gleitkommazahlen bräuchtest, müsstest Du den den Code ändern.
Zitat:
Ich finde es toll, dass Du mir die ganze Zeit so super geholfen hast! Vielen Dank!
Lass nur: solche Fragen tauchen immer wieder auf. Für den nächsten gibts dann ein fertiges Delphi-Beispielprogramm.
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.