German Wieso werden die Routinen von unten nach oben abgearbeitet?

Midimaster

Active Member
Licensed User
Es ist total wichtig, dass ich eine Datei angeben kann. Schließlich will man ja wissen, ob eine Datei eine Datei oder ein weiterer Unterordner ist.

Du weißt ja in deinem Fall schon, dass es ein Verzeichnis ist und möchtest nur noch mal nachfragen. Aber im Regelfall habe ich sowas wie "Daten.txt" in einem Verzeichnis gefunden und nun will ich wissen, ob es sich wirklich um eine Datei handelt. Schließlich könnte auch ein Ordner so eine Extension ".TXT" haben.

Daher gehen beide Syntax:
B4X:
    Log(File.IsDirectory("C:\","Basic"))
    Log(File.IsDirectory("C:\Basic",""))

beides ergibt TRUE als Antwort.

Du musst, wenn du ein Verzeichnis auflisten lässt immer davon ausgehen, dass einige der gefundenen Namen weitere Unterverzeichnisse sind.
Beispiel: nur wirkliche Dateien in eine Liste aufnehmen:
B4X:
    Dim Result As List= File.ListFiles("C:\")
    Dim EchteListe As List 
    EchteListe.Initialize
    For Each Name As String In Result
        If File.IsDirectory("C:\",Name)=False   Then
            EchteListe.Add(Name)
        End If
    Next
    For Each Name As String In EchteListe
        Log(Name)
    Next
 
Last edited:

Lothar Kriegerow

Active Member
Hallo Midimaster,

Sorry - Dein Posting hätte ich fast überlesen. Auch Dir herzlichen Dank! Die Ausführung war Spitze, nur eine kleine Frage: In Sub Button1_Click steht

log(BAS.Startzeit)

müsste dort nicht:

log(BAS.StartzeitHeute)

stehen?

Ich denke, das mit dem Modul werde ich auch so handhaben. In anderen Programmierungen tue ich es ja auch so.

Danke
 

Midimaster

Active Member
Licensed User
ja du hast recht. danke ich hab es gleich geändert.

hab schon wieder was zum thema File.IsDirectory() für dich geschrieben. siehe oben

wenn dir eine Antwort von Usern hier gefällt kannst Du gerne immer dort LIKE anklicken. Das sehen wir hier gerne!
 

Lothar Kriegerow

Active Member
Das obere Posting kann weg!
Abbruch wegen Zeitüberschreitung


Hallo Midimaster,

Sorry - Dein oberes Posting hätte ich fast überlesen. Auch Dir herzlichen Dank! Die Ausführung war Spitze, nur eine kleine Frage: In Sub Button1_Click steht

log(BAS.Startzeit)

müsste dort nicht:

log(BAS.StartzeitHeute)

stehen?

Ich denke, das mit dem Modul werde ich auch so handhaben. In anderen Programmierungen tue ich es ja auch so.

Zu: Log(File.IsDirectory("C:\","Basic")) - ich bin soooo doof. Auf diese Variante bin ich nicht gekommen.

Ich wollte, dass ein Benutzer den Pfad zu den Bilder selbst definieren kann. Als Beispiel.

/storage/0815/DCIM/Bilder

Meine Überlegung wäre mittels einer Splitfunktion, die gibt es sicher, den String zu zerlegern

DAS IST KEIN B4A Code, aber so stelle ich es mir vor.

Dim Verz As String
Verz= /storage/0815/DCIM/Bilder
S()=Split(Verz,"/")
Verz=Left(Verz, Len(Verz)- Len( S(LastIdx))

If File.IsDirectory(Verz,S(LastIdx) Then
Log("Verzeichnis existiert")

Die ganze Prüfung wäre dann natürlich optimal in dem Modul untergebracht, welches man auch für weitere Projekte einsetzt.



Gruß Lothar
 
Last edited:

OliverA

Expert
Licensed User
Longtime User
Ich wollte, dass ein Benutzer den Pfad zu den Bilder selbst definieren kann. Als Beispiel.

/storage/0815/DCIM/Bilder

Meine Überlegung wäre mittels einer Splitfunktion, die gibt es sicher, den String zu zerlegern

DAS IST KEIN B4A Code, aber so stelle ich es mir vor.

Dim Verz As String
Verz= /storage/0815/DCIM/Bilder
S()=Split(Verz,"/")
Verz=Left(Verz, Len(Verz)- Len( S(LastIdx))

If File.IsDirectory(Verz,S(LastIdx) Then
Log("Verzeichnis existiert")
Auch ganz einfach
B4X:
Dim Verz As String
Verz= /storage/0815/DCIM/Bilder
If File.IsDirctory(Verz, "") Then Log("Verzeichnis existiert")

Note:
@Midimaster zeigte das schon mit:
B4X:
Log(File.IsDirectory("C:\","Basic"))
Log(File.IsDirectory("C:\Basic",""))
 

Lothar Kriegerow

Active Member
Hallo OliverA,

Oh mein Gott! Das habe ich übersehen. Natürich ist genau das die Variante, welche ich brauche. DANKESCHÖN!

(Wer lesen kann ist klar im Vorteil) :)

B4A gefällt mir immer besser.

Gruß Lothar
 

Midimaster

Active Member
Licensed User
Es existiert auch schon ein Befehl um einen DateiPfad in seine Einzelteile zu zerlegen:
File.GetFileParent()
B4X:
Dim Pfad as String= "C:\Basic\BildProject\Img\Foto.jpg"
Dim EineEbeneHoeher as String =File.GetFileParent(Pfad)
Dim NurDerLetzteTeil as String= File.GetName(Pfad)
Log(EineEbeneHoeher)
Log(NurDerLetzteTeil)
gibt folgendes zurück:
C:\Basic\BildProject\Img
Foto.jpg


das kannst du auch mehrfach machen:
B4X:
Dim Pfad as String= "C:\Basic\BildProject\Img\Foto.jpg"
Do While Pfad.Length>3
    log(File.GetName(Pfad))
    Pfad=File.GetFileParent(Pfad)
Loop
gibt folgendes zurück:
Foto.jpg
Img
BildProject
Basic
 
Last edited:

OliverA

Expert
Licensed User
Longtime User
Ich dachte, ich können nun von allen weiteren Modulen auf diese Variable zugreifen können.

Ich war der Annahme, dass in einem weiteren Modul Log(Verzeichnis)
funktioniert. Muss ich wirklich mit Log(main.Verzeichnis)
auf die Variable zugreifen?
Dies hat mit "Namespaces" (Namensraeume) und das verhindern von "Namespace pollution" (Namensraum Verschmutzung) zu tun.
Links:
 

Lothar Kriegerow

Active Member
Hallo MidiMaster,
GENIAL!
Hier gibt es Funktionen, für welche ich Funktionen schreiben würde. :cool:

Das ist natürlich großartig. 100%ig gibt es hier 100te Funktionen, welche ich brauche, aber noch keine Ahnung habe. Gern würde ich mich einlesen - aber wo?
So, das ist für heute genug Brot. Ich schaue mir das Ganze diesen Abend noch mal genau an und verinnerliche mir das. (Diesmal werde ich genauer lesen)

Gruß Lothar
 

Lothar Kriegerow

Active Member
Hallo,

ich habe mal eine kleine App geschrieben. (Nichts überwätligendes. Da fehlen natürlich noch Designs etc.) Die App soll eine Art Tagebuch werden. Um Bilder hinzuzufügen, lasse ich mir meine Bilder anzeigen. Bei einem Klick auf ein Bild soll dieses übernommen werden können. Dazu soll es vor dem Abspeichern gedreht werden können. Ebenso wäre es cool, wenn ich ein kleines Thumbnail erstellen könnte. Wobei, wenn ich ein zuvor gedrehtes Bild abspeichern könnte, wäre das mit dem Thumbnail kein Problem - denke ich.
Nun ist die Methode in dem Modul Galerie grottenschlecht - das weiß ich, nur bekomme ich es noch nicht besser hin!

Sicher bekomme ich einige gute Tipps.
Übrigens, beim (noch nicht funktionierenden) Button übernehmen verwende ich die alte Messagebox, da die Asyncrone in dem Kontext nicht funktioniert. Vielleicht gib es ja eine Alternative?

Gruß Lothar
 

Attachments

  • MyDiary.zip
    12.8 KB · Views: 232

OliverA

Expert
Licensed User
Longtime User
FYI: Das alte MessageBox blockiert die Ereigniswarteschlange (event queue) und Android stoppt / stürzt die Anwendung ab
 

Lothar Kriegerow

Active Member
Hallo OliverA,

ja, ich weiß, aber hast Du eine Alternative? Die MsgBoxAsync ist meiner Meinung eher unbrauchbar. Ist ja auch nicht so, dass ich sie auf Dauer einsetzen will, nur brauche ich irgend eine andere Möglichkeit.

Gruß Lothar
 

Midimaster

Active Member
Licensed User
Respekt! Das ist ja schon ganz schön umfangreich. Natürlich könnte man noch vieles optimieren... Sollen wir es Dir zerpfücken? Oder willst du lieber erst mal richtig stolz drauf sein?

Die asynchronen Funktionen sind ja im Grunde die gleichen wie die alten synchronen Funktionen. Nur das Betriebssystem nicht mehr anhält, bis die Antwort vorliegt. Deshalb hält auch Deine eigene App nicht mehr an.

Natürlich kannst Du deinen Code zwingen trotzdem anzuhalten und zu "warten" bis eine Rückmeldung vorliegt. Dann arbeitet (von Dir aus gesehen) die asynchrone Funktion genauso wie eine alte Funktion.

Im Grunde "wartet" aber keiner mehr irgendwo. Sondern es läuft so:

In einer deiner SUBs kommt der Befehl einer asynchr. Messagebox dran.
Die Messagebox wird gerufen und dargestellt.
Das Betriebsystem macht aber gleich weiter.
Es verlässt Deine SUB, merkt sich aber wo es raus ist.
Dein Programm kann sofort mit anderen SUBs weiterlaufen. z.b. der Timer tickt weiterhin. Die Buttons sind anklickbar. Ein Bild wird bereits bearbeitet oder gedreht, etc...
Nun klickt der User endlich auf die Messagebox.
Das Betriebsystem springt wieder in Deine SUB und arbeitet den Rest des Codes ab.

Du hast das auch so schon in Deinem Code angewendet:
B4X:
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Titel")
    rp.CheckAndRequest(rp.PERMISSION_WRITE_EXTERNAL_STORAGE)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
    If Result = True Then Verzeichnis = File.DirRootExternal
CheckAndRequest() is asynchron und Deine SUB Activity_Create wartet auf das Ergebnis der Rechteerteilung. Erst danach wird diese SUB zuendegearbeitet.

Bei der Messagebox geht das genauso:
B4X:
Sub btnSpeichern_Click
    MsgboxAsync( "Das ausgewählte Bild wurde zum aktuellen Eintrag hinzugefügt.","Speichern")
    Wait For MsgBox_Result (Result As Int)
    Activity.Finish
End Sub
 

Lothar Kriegerow

Active Member
Hallo MidiMaster,

(Stolz drauf? Mach dich bitte nicht lustig - ich weiß dass es im Grunde genommen Schrott ist)

Genau zum Zerpflücken hab ich es ja gepostet. Nur so kann ich lernen. Bei Syncron und Asyncron müssen wir uns nicht aufhalten. Das habe ich vollständig begriffen.

Auch habe ich nicht vor, die Messagebox einzusetzen. In meinem konkreten Beispiel war das aber erst mal ein simpler Weg. Wenn ich die asyncrone Messagebox verwende und danach das Objekt zerstöre, beendet sich die Activity und dementsprechend auch die Box. (Keine Ahnung ob das Wort Objekt und zerstöre in dem Fall richtig ist, weiß es aber noch nicht besser.)

Ich könnte eine Variable bemühen und diese setzen und diese im Resize-Event der anderen Activity auswerten - aber macht man das so?
Sieht für mich eher tricky aus, da aus der Activity ja auch weitere Activitys aufgerufen werden sollen.


Mich würde interessieren, wie ich die ganze "GALERIE" ordentlich hinbekomme. Natürlich sind meine Zahlen erst mal fix und müssten durch Variable ersetzt werden, damit die Activity auf allen Geräten korrekt dargestellt wird. Auch habe ich noch nirgends was über grafische Darstellungen gelesen. Die langweiligen Standardbuttons können es ja wohl nicht sein. Das erinnert mich an DOS-Programme aus Quick-Basic Zeiten.

Gruß Lothar
 

Midimaster

Active Member
Licensed User
Neinnein. Wenn mal eine App läuft ist es auch OK so. Jeder hat seinen eigenen Programmierstil wie er zum Ergebnis kommt. Also wenn es läuft kannst Du stolz drauf sein. Fertig!

zur Messagebox
Die asynchrone Messagebox, die ich Dir geschrieben habe kann eben nicht durch die App beendet werden. Sie wartet wirklich bis der User klickt, dann wird die Activity beendet. Schau Dirs noch mal an!

Jetzt die erste Nörgelei:

EINRÜCKEN
Wenn andere Deine Programme lesen können sollen (und auch du selbst) ist es von großer Wichtigkeit, das IF und sein ENDIF genau untereinander stehen. Das Einrücken muss immer die Logik des Ablaufs widerspiegeln:

Du:
B4X:
Sub btnSave_Click
    If File.IsDirectory (txtBild.Text , "") Then
    File.WriteString(File.DirInternal,"Setup.txt",txtBild.text)
    Main.Verzeichnis=txtBild.Text
    Main.OK=True
        xui.MsgboxAsync("Der neue Pfad wurde gespeichert","Erfolgreich")
    Else
        Main.OK=False
        xui.MsgboxAsync("Ungültiges Verzeichnis","Bitte erneut versuchen")
    End If
End Sub

Besser so:
B4X:
Sub btnSave_Click
    If File.IsDirectory (txtBild.Text , "") Then
        File.WriteString(File.DirInternal,"Setup.txt",txtBild.text)
        Main.Verzeichnis=txtBild.Text
        Main.OK=True
        xui.MsgboxAsync("Der neue Pfad wurde gespeichert","Erfolgreich")
    Else
        Main.OK=False
        xui.MsgboxAsync("Ungültiges Verzeichnis","Bitte erneut versuchen")
    End If
End Sub
Ist Dir an vielen Stellen passiert. Machst es aber Dritten sehr schwer das zu lesen.


EINE DIM-ZEILE FÜR VIELE:
So schreibst Du schneller:
B4X:
Sub Globals
    Public bmpFoto As B4XBitmap
    Public FotoB, FotoH As Int
    Private btndown, btnUp As Button
    Private iv1, iv2, iv3, iv4, iv5, iv6, iv7, iv8 As B4XView
End Sub

Galerie.Bas Activity_Create
Dein MaxAnz berechnest Du falsch. "i" entspricht Liste.Size. du willst aber sicher DateiListe.Size merken.

Galerie.Bas Foto_oeffnen
Das mit dem 8 Bilder geht eleganter. Du erstellts eine weitere Sub und dort erledigst du alles für jeweils ein Bild:
B4X:
    For I=Bildnummer To  Bildnummer +7
        BNr=BNr+1
        Bild=Dateiliste.Get(I)
        Select BNr
            Case 1
                BildSetzen(Bild,iv1)
            Case 2
                BildSetzen(Bild,iv2)
            ...
        End Select

Sub BildSetzen(Datei as String, ivx as B4XView)
    Bildpara (Datei)
    bmpFoto = LoadBitmapSample(Verzeichnis, Datei,  FotoB,  FotoH)

    ivx.SetBitmap(bmpFoto)
    ivx.Width = FotoB
    ivx.Height = FotoH
    ivx.Tag =  Datei
End Sub

Galerie.Bas Btn_Up/Down
Sowas löst du mit einer Gemeinsamen Routine für beide Aktionen. Dabei musst Du beachten, dass Bildnummer immer 8 unter MaxAnz bleiben muss:
B4X:
Sub btndown_Click
    ChangeBildNummer 8
End Sub

Sub btnUp_Click
    ChangeBildNummer -8
End Sub

Sub ChangeBildNummer(Richtung as INT)
    Bildnummer =Bildnummer + Richtung
    btnDown.Enabled=True
    btnUp.Enabled=True
    If Bildnummer <0 Then
        Bildnummer=0
        btnDown.Enabled=False
    Else If BildNummer>MaxAnz-8 Then
        BildNummer=MaxAnz-8
        btnUp.Enabled=False
    End If
    Foto_oeffnen
End Sub

Galerie.Bas iv1_Click, iv2...
Du kannst allen Views des selben Typs im Designer auch den selben Event zuweisen. z.b. "ImageEvent". Danach kannst Du die Events im Code mit einer gemeinsamen Routine erledigen:
B4X:
Sub ImageEvent_Click
    Dim ivx as B4xView= Sender
    gBild=ivx.Tag
    StartActivity("Viewer")
End Sub
die anderen 7 SUBs fallen dann weg
 
Last edited:

Lothar Kriegerow

Active Member
Hallo Midimaster,

ohne unnötig auf Der Messagebox rumzureiten:
B4X:
Sub btnSpeichern_Click
    xui.MsgboxAsync( "Das ausgewählte Bild wurde zum aktuellen Eintrag hinzugefügt.","Speichern")
    Activity.Finish
End Sub
Hier passiert auf meinem Handy folgendes: Ich sehe für Sekundenbruchteile die Box aufploppen. Danach wird as aktive Fenster geschlossen und die Box auch.

EINRÜCKEN: Ich hatte in jedem Modul mehrmals ALT-F betätigt. - Komisch - ich werde mehr darauf achten.

EINE DIM-ZEILE FÜR VIELE: Ok, wenn es in dieser Programmiersprache so gewünscht wird, mach ich das. In anderen Sprachen gehört das wieder zum schlechten Programmierstil und in anderen ist Das so richtig falsch.
In VisualBasic z.B.
Dim A,B,C As Integer
Bedeutet:
Dim A As Variant
Dim B As Variant
Dim C As Integer

Natürlich werde ich mich an die für diese Sprache üblichen Gepflogenheiten halten.

MaxAnz schaue ich mir noch mal an. Da es mit mehreren Verzeichnissen geklappt hat und nie ein Fehler auftrat, hab ich es nicht bemerkt.

Galerie.Bas Foto_oeffnen: Mache ich. Für mich war das erst mal übersichtlicher. Auch hätte ich nicht gewußt, wie ich eine View übergeben kann. Jetzt weiß ich es. DANKE

Galerie.Bas Btn_Up/Down OK...

Galerie.Bas iv1_Click, iv2... Das ist eine feine Sache. Das muss ich mir noch mal genau anschauen und verinnerlichen. Das Prinzip habe ich erkannt.

Ich habe so was das 1. Mal mit den Buttons zum Drehen des Bildes verwendet. Hatte ich im Beispiel von Klaus gefunden. (Also geklaut). Das ist so richtig Tricky, den Tag dafür zu vergewaltigen. Ich hatte anfangs Indizierungen für Views gesucht. Das ist nämlich eine feine Sache. Das Ansprechen eines Events mittels SUB ohne Click zu verwenden, aber mittels Sender ist für mich Neuland. Hab es aber begriffen. Ist fast so gut wie Indizierte Buttons in anderen Sprachen.

Vielen Dank Lothar
 

Midimaster

Active Member
Licensed User
Messagebox
Dir fehlt noch die Wait For-Zeile
B4X:
Sub btnSpeichern_Click
    MsgboxAsync( "Das ausgewählte Bild wurde zum aktuellen Eintrag hinzugefügt.","Speichern")
    Wait For MsgBox_Result (Result As Int)
    Activity.Finish
End Sub

Einrücken
Nach nachträglichen Änderungen am Code solltes Du immer nochmals kurz das Erscheinungsbild prüfen. Oft wird das Einrücken durch Kopieren von Code-Zeilen gestört. Die automatik schafft es nicht immer von alleine.

EINE DIM-ZEILE FÜR VIELE:
Neinnein, das kannst Du machen wie Du es für sinnvoll hältst. Deine Argumente sind ja sinnvoll. Ich wollte dir nur zeigen, dass das auch geht (wenn dir sowas gefällt). Es gibt hier keine Vorgaben von Seite der Sprache. Wenn Dir eine meiner Ideen mal nicht gefällt, dann mach es gerne so wie du es bisher gemacht hast. Das ist total gut so!!! Ich würde von einem "Fehler" schreiben, wenn ich der Auffassungung bin: "so kann man es nicht machen". Alles andere sind immer nur "schau mal, das geht auch..."
Hier hatte es sich halt angeboten, weil die Views alle (fast) gleich heissen und auch noch für das selbe zuständig sind.

Generell was zu kurzem Code
Je kürzer und kompakter dein Code ist, desto weniger Fehler können drin sein, bzw die Fehler werden schneller in der App entdeckt, weil ja ein gemeinsame SUB von vielen Stellen im Programm aufgerufen wird und so der Fehler früher sichtbar würde.

Ein Event für alle
Der gemeinsame Event ist trotzdem auf den Click angewiesen. Der Event hat immer einen Namen und ein Ereignis. Wenn Du im Designer nichts eigenes angibst, heißt der Event halt zufällig so wie der Button. Bei 8 Button gibt es dann 8 unterschiedliche Events
B4X:
Sub Button1_Click
...
Sub Button2_Click
....
Das Ereignis ist das _Click!!!

Auch wenn Du jetzt einen gemeinsamen Event-Namen für alle 8 Buttons (Button1, Button2, etc...) verwendest: "MeinButtonEvent" muss die SUB dazu das Wort "_Click" erhalten:

B4X:
Sub MeinButtonEvent_Click


Und wer nun von den acht Buttons der Versender des Events war erfährst Du eben über den Befehl Sender

B4X:
Sub MeinButtonEvent_Click
    Dim Btn As Button =Sender
    log(Btn.Text)
 

Lothar Kriegerow

Active Member
Hallo Midimaster,

Wait For MsgBox_Result (Result As Int)
Wieder was gelernt. Das ändert natürlich alles.


Neinnein, das kannst Du machen wie Du es für sinnvoll hältst. Deine Argumente sind ja sinnvoll. Ich wollte dir nur zeigen, dass das auch geht

Ich bin für jeden Tipp und Rat dankbar. Auf alle Fälle richte ich mich nach den Gepflogenheiten hier und B4A. Ich muss sie nur kennen.

Für Ratschläge, Korrekturen und Tipps, wie es anders geht, bin ich immer offen. Wenn ich anderer Meinung bin, sag ich das.

Gruß Lothar
 

klaus

Expert
Licensed User
Longtime User
Ich habe so was das 1. Mal mit den Buttons zum Drehen des Bildes verwendet. Hatte ich im Beispiel von Klaus gefunden. (Also geklaut).
Wieso geklaut, Ich habs Dir doch geschickt :).

Die ImageViews könntest Du auch im Code einfügen mit Indizierungen der Views.
Als Anregung, eine geänderte Version von Deinem Projekt.

In welcher Grösse willst Du das Bild speichern?
 

Attachments

  • MyDiary1.zip
    14 KB · Views: 225

Lothar Kriegerow

Active Member
Hallo Klaus,
ich habe mir Deine Variante soeben angeschaut. Die Idee wirkt professioneller und ist zudem schneller. Daran hätte ich mich am Anfang NIE gewagt. Zu viele für mich unbekannte Befehle. Ich muss nur noch die Maximalzahl der Bilder abfangen, wegen des Überlaufs, aber das ist ein Klacks. Ich habe soeben die ganzen Verbesserungen von Midimaster eingepflegt. Ich muss schon sagen, viel professioneller als meine Variante. Na ja, ich versuche es erst mal überhaupt hinzubekommen und dann zu optimieren.

Also mein Ziel ist es, ein ausgewähltes Bild, wenn nötig zu drehen und in das Projekt zu speichern, Zur gleichen Zeit soll ein kleines Thumb. abgespeichert. Diese sollen dann zum bestehenden Eintrag mit abgespeichert werden. Ich verwende dazu eine Datenbank. (Dazu brauche ich erst mal keine Hilfe. Ich denke, das stellt kein Problem dar.)

Meine jetzigen Probleme sind:

- Drehen eines Bildes und dieses abspeichern.
- Abspeichern eines Thumbs
- Erstellen einer ordentlichen grafischen Oberfläche.

Das jetzige Aussehen kann man ja keinem anbieten. Ich denke dass das mit B4A sicher kein Problem darstellt. Bisher werde ich immer mehr positiv überrascht.
Die Programmierung erinnert mich immer mehr an .NET. Also eine absolute Hochsprache. Ich denke, B4A ist keine Einbahnstraße. Die hatte ich in den letzten 30 Jahren genug.


Viele Grüße und Vielen Dank für den einmalig guten Support.

Lothar
 
Top