Anfngerfrage: DB ffnen / Beispiele

Das ist der Code der korrespondierenden Methode “LadeClients” mit Originalbezeichnungen:

[code]ListClients.DeleteAllRows

Dim sqlClients As String = “SELECT * FROM Clients”
Dim rsClients As RecordSet
rsClients = DB.SQLSelect(sqlClients)

If rsClients <> Nil Then
While Not rsClients.EOF
ListClients.AddRow(rsClients.Field(“CLT_LABEL”).StringValue)
rsClients.MoveNext
Wend
rsClients.Close
End If
[/code]

Vielleicht sollte ich aber noch erwhnen, dass das oben beschriebene Hinzufgen (bzw. Nicht-Hinzufgen) des Datensatzes in einem eigenen Fenster erfolgt.

Alles korrekt.

Ist DB eine globale Variable (in einem Modul)?

DB ist in den Properties beider Fenster definiert (DB As SQLiteDatabase). Momentan jeweils als Public, weil ich auch damit herumprobiert hatte.

SQLite is single user. Es wre besser (muss aber nicht sein), wenn Du nur an einer Stelle in Deinem Programm die Datei ffnest und dann den Connect machst.

Du kannst ja mal DB.MultiUser auf True setzen direkt nach Connect(). Aber ich denke nicht, dass das etwas verndert.

Hast Du mal mit eine SQLite Editor geschaut ob die Datenstze vorhanden sind? Vielleicht hast Du zwei verschiedene Dateien im System.

… ich bin dann mal weg (fr heute).

Ja, hau dich hin oder feier weiter. :wink: Habe dich lange genug aufgehalten. Ich gucke mir das auch lieber morgen noch mal in Ruhe an.

Ich bin den Anwesenden wohl eine Erklrung schuldig. Und jetzt habe ich auch eine:

Schuld sind wie immer andere. In diesem Fall der Ulrich. :wink:

Nein, im Ernst: Als es in einem frhen Stadium mit dem direkten Zugriff auf die DB-Datei mit GetFolderItem(“dateiname.sqlite”) nicht klappte, hatte ich die Datei, wie von Ulrich ganz oben fr die Beispieldatei von Eddies Electronics empfohlen, in die Build Settings gezogen. Und dann vergessen. Da ich die Daten bisher immer nur eingelesen und an anderen Baustellen gearbeitet hatte, war das auch nicht aufgefallen. Es funktionierte ja alles.

Und ich hatte den jetzt auftretenden Fehler im fr mich als Vertreter alter (prozeduraler) Schule teilweise immer noch kryptisch anmutenden Code gesucht. Nach den Hinweisen gestern hier im Forum kam ich dann aber doch darauf, noch mal in die Buid Settings reinzuschauen …

Ich habe den Eintrag dann dort entfernt, das GetFolderItem durch GetOpenFolderItem ersetzt und die Datei manuell per Dateidialog geffnet. Und jetzt wird auch gespeichert.

So bleibt fr den Moment eigentlich nur die Frage, wieso der Direktzugriff per GetFolderItem(“dateiname.sqlite”) nicht klappt, obwohl die DB-Datei doch im selben Ordner liegt. Zumal bei GetOpenFolderItem auch automatisch genau dieser Ordner geffnet wird. Ist jetzt kein groes Problem, da ich ja nur selbst damit arbeite, aber falls jemand eine Idee hat …

Sorry fr die Umstnde. Es rgert mich, wenn ich nicht nur meine eigene, sondern auch die Zeit anderer Leute mit meiner Dmlichkeit verschwende. Immerhin lernt man bei der Fehlersuche und -dokumentation ja einiges, auch in den angrenzenden Bereichen des Problems - falls das jemanden trstet. :wink:

Fr den Moment erst mal vielen Dank und einen schnen Sonntag!

Hallo Axel,

danke dir für deine Klarstellung! Das ist in der Tat ein Problem, dass ich noch nicht lösen konnte und bei dem ich für sachdienliche Hinweise dankbar bin: Ein “vollständiges” Tutorial kann gerne eine Stunde oder länger werden. Das finde ich tl;dw und schwer, darin irgendeinen Detailaspekt schnell mal wiederzufinden.
Andererseits geht bei einer schnelleren Repräsentation mittels CopyBuild-Step dann eben gerne ein wichtiges Detail wie das feste Platzieren einer DB unter. Wenn du Verbesserungsmöglichkeiten siehst, hab ich ein sehr offenes Ohr dafür. Sollen ja helfen und nicht mehr als nötig verwirren, die Filmchen …

Nach Entfernen des BuildSteps sollte dein Programm auch mit GetFolderItem funktionieren. Es war wohl bislang so, dass die von dir platzierte DB bei jedem Start durch eine frische Version ersetzt wurde. Was prima für Demozwecke ist, aber eben nicht wirklich zum dauerhaften Konservieren von Daten dient. Wenn dein Folderitem auf den richtigen Pfad gesetzt ist, gibt es keinen Grund, die Dateiauswahl zu bemühen. Hardcoding klappt da ebenso gut. Gibtst du nur den Dateinamen an oder definierst du den Pfad genauer? Generell anzuraten ist, die DB eher in einen dafür vorgesehenen Systemordner zu legen, wie Specialfolder.ApplicationData.

Und die Umstände: Neenee, das sind doch eher wertvolle Hinweise, wo was verbessert werden kann oder vielleicht ein, zwei kleine Tutorials fehlen – die ganze Dateihandhabung ist nicht so ganz trivial, finde ich, und eventuell wäre es auch mal interessant, ein Mini-Tutorial zu den BuildSteps zu machen. Die sind wahnsinnig hilfreich, man übersieht sie aber auch gerne. Da bist du nicht der Erste, der über so was gestolpert bist.

Hallo Ulrich, nee, GetFolderItem(“dateiname.sqlite”) (sic!) funktioniert eben nicht. Deshalb war ich seinerzeit ja überhaupt erst auf die (schlechte) Idee gekommen, die Datei testweise einfach mal in die Build Settings zu ziehen (ohne wirklich zu wissen, was ich da tue). Hatte bei dem Beispielprojekt ja auch geklappt. Also, scheinbar … :wink:

Bei Anwendungen, die man verteilt, wäre die Herangehensweise mit dem direkten Aufruf natürlich generell problematisch, das ist mir durchaus bewusst, aber da ich ja erst mal nur selber daran herumbastle, hatte mir das für den Anfang genügt. Andere Baustellen waren mir wichtiger.

Ich war ursprünglich halt davon ausgegangen, dass, wenn kein bestimmter Pfad angegeben ist, automatisch zuerst in demselben Ordner gesucht wird, in dem sich auch die Projektdatei befindet. Dem scheint aber nicht so zu sein (obwohl auch bei GetOpenFolderItem automatisch eben jener Ordner aktiviert wird).

Nun habe ich halt einfach den kompletten Pfad in die Anweisung geschrieben, also hardcodiert, wie du es nennst:

GetFolderItem("C:\\User\\Docs\\Trallala\\Hoppsassa\\dateiname.sqlite")

Hätte ich auch gleich machen können, dann wäre uns viel Ärger erspart geblieben. :slight_smile:

Zu den Tutorials: Die sind auf jeden Fall hilfreich. Punkt. Und da ich selbst mehrere Jahre als EDV-Dozent (ja, damals hieß das noch so) in der Erwachsenenbildung gearbeitet habe, weiß ich, wieviel Mühe in solchen Tutorials steckt und wie schwierig es generell ist, einen didaktischen Leitfaden zu entwickeln und umzusetzen. Deshalb halte ich mich ungefragt bei derartigen Angeboten, erst recht kostenlosen, in der Regel mit “guten Ratschlägen” zurück. Nicht aus Bequemlichkeit, sondern weil Verbesserungsvorschläge de facto ja immer auch eine Kritik am Bestehenden implizieren. Und man will ja nicht undankbar erscheinen.

Bei Interesse lasse ich dir aber gerne die eine oder andere Idee zukommen, ganz subjektiv, also ohne Anspruch auf Richtigkeit und Allgemeingültigkeit. Du müsstest mir dann nur sagen, auf welchem Wege (dieses Forum ist vermutlich kein geeigneter Rahmen, oder?).

Dank & Gruß

Axel E. aus B.

Welcher Standardordner bei welchem Folderitem geöffnet wird, müsste ich auch einmal genauer eruieren. Meines Erachtens greift ein Folderitem nur mit Dateinamen auf das Bundle zurück, und in dem befindet sich alles, was das Programm angelegt hat oder (via BuildScript oder Importieren ins Projekt) dort hineinkopiert wurde.

Ein GetOpenFolderItem schaut nicht ins Bundle, das ist ja nach außen hin ohne Tricks gar nicht sichtbar. Was aber üblicherweise mit GetOpenFolderItem geöffnet wird, und ob das systemübergreifend immer so ist, weiß ich nicht. Ich denke, darauf sollte man auch nicht vertrauen, da z.B. der MacUser sowas wie DefaultFolder installiert haben könnte, das den Standard frei verändern kann. Insofern absolut sinnvoll, entweder wie von dir geschildert oder per Definition über SpecialFolder einen expliziten Pfad zu definieren.
Und dann am besten erst mal prüfen, ob die Datei existiert. Das hilft einem schon mal auf die Sprünge, was die Gründe eines solchen Problems angeht.

Und Tutorial-Anregungen: Also ich bin mir durchaus bewusst, dass es noch viel Verbesserungspotenizal gibt. Die audiovisuelle Repräsentation ist nicht so mein Ding; meine Schnittlisten sehen aus wie die eines Hollywood-Blockbusters, und doch bin ich oftmals eher so mittel begeistert. Ich sehe Kritik lange nicht nur unter dem negativen Aspekt; eigentlich ist sie doch ein hilfreiches, konstruktives Mittel zur Verbesserung. Und solange ich das alles nicht mit der Ansicht mache, mich zu präsentieren, sondern möglichst hilfreiche Hinweise zu liefern, wären wir dann ja schon mal zwei, die der Meinung sind, dass etwas mehr oder minder Gutes noch besser werden kann :wink:

Offiziell bin ich hier unter ulrich@xojo.com zu erreichen, oder natürlich auch einfach per privater Forums-Nachricht.

Das steht auf documentation.xojo.com:

Bei einem kompilierten Programm ist mir klar wo das ist, aber bei einem Programm im Debugger weiss ich es nicht.

@Eli: Danke für die Info. Ausgangspunkt ist offenbar der Debug-Ordner, den Xojo automatisch unterhalb des Projektordners anlegt. Ich hab’s jetzt so gemacht:

Dim dbDateiPfad, dbDatei as FolderItem dbDateiPfad = GetFolderItem("").Parent dbDatei = GetFolderItem(dbDateiPfad.NativePath+"dateiname.sqlite")

Funktioniert und ist zweifellos schon einiges eleganter als meine ‘Hardcore’-Variante. :wink:

@Ulrich:
Also, technisch und dramaturgisch, um es mal hochtrabend zu formulieren, empfinde ich deine Video-Tutorials durchaus als professionell. Die können sich wirklich hören und sehen lassen, da gibt es m. E. überhaupt nichts zu mäkeln.

Neues Problem (also, eines davon):

Tabelle hat zwei Felder: “CLT_ID” und “CLT_LABEL”

Zunchst hatte ich nur das Label in die Listbox eingelesen, funktionierte problemlos:

ListClients.AddRow (rsClients.Field("CLT_LABEL").StringValue)

Nun wollte ich auch die ID einlesen:

ListClients.AddRow (rsClients.Field("CLT_LABEL").StringValue, _
rsClients.Field("CLT_ID").IntegerValue)

Funktioniert nicht. Fehlermeldung:

[quote]“There is more than one item with this name and it’s not clear to which it refers.”
[/quote]
Wobei ListClients.AddRow gelb unterlegt ist.

Verstehe ich nicht. Wo sind da mehrere Elemente selben Namens? berhaupt: Welchen Namens?

An anderer Stelle habe ich denselben Aufbau mit mehreren Feldern/Spalten. Einziger Unterschied: CLT_ID ist das einzige Schlsselfeld. Kann es damit was zu tun haben? Oder habe ich einfach wieder mal Tomaten auf den Augen und sehe das Offensichtliche nicht?

Jemand eine Idee?

Hallo Axel,
Addrow erwartet ein ParamArray of String. Du musst also den StringValue des zweiten Fields übergeben oder eine Typumwandlung des Integervalues nach String oder Text vornehmen.
Die Fehlermeldung ist irreführend. Das ist ein bekannter Bug, der hoffentlich bald durch eine klarere Fehlermeldung beseitigt wird. Aktuell: Siehst du etwas dieser Art, überprüfe die Datentypen. Meistens liegt es daran.

Herrjeh … Klingt durchaus logisch, aber als Dummy habe ich mich von der Fehlermeldung komplett in die Irre führen lassen.

Danke für die wieder mal schnelle Hilfe!

Kein Grund, dein Licht unter den Scheffel zu stellen. Die Fehlermeldung führt einen in die Irre, ganz egal, wieviel Programmiererfahrung man besitzt. Ist man ein paarmal davon aufs Glatteis geführt orden, weiß man sie für sich zu übersetzen – aber keine Frage, dass das auch einfacher ginge :wink:

Klar, die Fehlermeldung selbst ist natürlich irreführend, keine Frage, aber mit etwas mehr Erfahrung wäre ich wahrscheinlich gar nicht erst auf die Idee gekommen, da einen Integer-Wert reinschreiben zu wollen. :slight_smile:

Ich bin alt und selbstbewusst genug, um gerne zuzugeben, dass ich (immer noch) nicht alles kann, weiß und habe. :wink:

Und bisher fühle ich mich hier auch als bekennender Anfänger mit meinen “dummen Fragen” durchaus ernst genommen.

Ich habe wohl mal wieder Tomaten auf den Augen. Suche seit geraumer Zeit vergeblich nach einer Möglichkeit, beim Befüllen einer Listbox je nach Bedingung die Farbe des Textes und/oder des Hintergrundes der betreffenden Zelle/Zeile zu ändern.

Eigentlich ne ganz simple Sache. Dachte ich …

Für sachdienliche Hinweise wie immer dankbar.

Ist auch gar nicht so schwer, aber ganz anders aufgebaut als man vermuten würde. Du musst dazu die jeweiligen Event Handler benutzen, nämlich CellBackgroundPaint und CellTextPaint. Dort liest du deinen Text mittels Cell (row, column) aus, analysierst ihn und setzt je nachdem die ForegroundColor für das Graphicobjekt und DrawStringst dann deinen Text in der gewünschten Farbe.

CellBackgroundPaint ganz ähnlich, nur dass du hier ein FillRect in der Größe des Grafikobjekts nach vorheriger Festlegung der Farbe machst. Gerne benutzt man ja auch abwechselnde Zeilenfarben – entsprechend würde dann hier nicht der Zellinhalt das Kriterium sein, sondern die Row (Gerade/Ungerade Zeilennummer z.B.).

EDIT: Und wichtig noch: Beide Methoden ggf. mit Return True beenden. Das ist für Xojo das Zeichen, dass du dich um die Gestaltung gekümmert hast. Dann musst du dich allerdings um das Highlighting selbst kümmern.

Danke für die Hinweise. Aber: Event Handler, Grafikobjekt, DrawString - hä?

Auf CellBackgroundPaint und CellTextPaint war ich in der Referenz auch schon gestoßen, verstehe aber die dahinter stehende Logik nicht. Nicht mal ansatzweise. Auch nach einer weiteren vergeudeten Stunde des Auf-die-Beispiele-Starrens nicht.

Gibt es vielleicht irgendwo ein für Normalsterbliche verständliches Tutorial zum Thema “Ich befinde mich in einer Schleife zum Befüllen einer Listbox und will den nächsten zu schreibenden Eintrag in grauer statt schwarzer Schrift haben (PS: in Xojo)”?

Ansonsten verbuche ich das erst mal unter “Geht nicht”, gedanklich ergänzt um den Zusatz “(Also, irgendwie wohl schon, aber nicht mit der Aufgabe angemessenem Aufwand)”.

Ich wei, das ist ein ziemlich komplexes Thema. Ich hab zwar krzlich was dazu auf meinem Blog geschrieben, das von den Grundlagen her nicht nur fr iOS gilt (http://xojoblog.me/2015/07/10/ios-grafiken-fuer-fortgeschrittene-teil-i-iosgraphics-aka-cgcontext/), aber der Beitrag erschlgt wiederum auch schnell.

Kurz gesagt: All grafisch sichtbaren Objekte bernehmen ja, dank OOP und Betriebssystemen, ihr Zeichnen selbsttndig fr dich. Du setzt evtl. irgendwo ein ImageWell hin, weist diesem ein Bild zu und musst dich nicht mehr kmmern. Das wirkt so, als ob es statisch wre, ist es aber berhaupt nicht. Sobald ein Teil verdeckt und wieder freigeben wird, oder gescrollt, oder was auch immer: Ziemlich hufig ist das Betriebssystem dabei, diverse Elemente neu zu malen.

Dazu benutzt es eine virtuelle Leinwand. Wenn intern ein DrawRect-Befehl ankommt, also der Hinweis, dieses Rechteck neu zu zeichnen, dann wird eine solche in der gewnschten Gre frisch erzeugt. Das ist mehr oder weniger nur Speicher, hat also keine visuelle Erscheinungsform. Und dann malt das OS brav alles dort hinein, was hineingehrt schaut z.B. nach BorderWidth, Image, Backgroundcolor und zeichnet sie in richtiger Reihenfolge. Zum Schluss wird das Ergebnis an die richtige Bildschirmposition kopiert.

Das machen auch deine Tabellenzellen. Normalerweise mit den Vorgaben, die du im Inspector oder programmatisch festgelegt hast.

Die oben erwhnten Events sind deine Hintertrchen dafr. Du kannst dich dort selbst drum kmmern, was, in welcher Farbe und wie erscheinen soll. Dazu wird dir das frische Grafikobjekt also deine Leinwand geliefert und noch ein paar Angaben mehr. Die Angaben berprfst du auf Relevanz fr dich, eben durch Nachschauen im Text oder durch Bestimmen von Zeile oder Spalte, durch Lesen der Tags und entweder sagst du dann “N, das ist nichts Besonderes, das soll mal das System machen” dann verabschiedest du dich mit Return False, und das OS bernimmt, als wr nichts gewesen , oder du bernimmst die Innengestaltung der Zelle selbst. Dafr stehen dir jede Menge Grafikbefehle zur Verfgung, von Farben ber geometrische Objekte bis zu Bildern und Texten. Du hast z.B. hier die Mglichkeit, einen Datenbanktext auszulesen und stattdessen ein Symbol in die Zelle zu malen.

Ich vermute, du hast eher nach einer Mglichkeit wie bedingten Formatierungen gesucht. Ich wei nicht, ob es irgendein cleveres Projekt gibt, das so etwas macht. Im Prinzip und das wird auch z.B. bei FileMaker im Grunde nicht viel anders sein sind das aber immer Convenience-Methoden, die im Kern doch das Handling des Grafikobjekts bernehmen. Denn das geben die Betriebssysteme so vor: Eine leere Leinwand und dann ein “soll ich oder willst du?” via Event-Handler.

EDIT: P.S.: Ein Demo-Projekt findest du bei den Programmbeispielen, im Desktop-Folder/Controls/Listbox/ListBoxExample