Debugger hängt

Für allgemeine Fragen zur Programmierung mit PureBasic.
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Debugger hängt

Beitrag von Salafat »

Hallo,

ich habe ein Programmfenster erstellt, dessen Hauptelement ein Listenfeld (ListView) mit ca. 800 Zeilen ist. Darunter habe ich einige Bildschaltflächen (Imagebuttons) angeordnet, mit deren Hilfe die Einträge des Listenfelds manipuliert werden können. Eine dieser Schaltflächen soll nach dem Anklicken bestimmte Zeilen löschen – in Abhängigkeit davon, ob sie einen bestimmten Text enthalten.

Mein Problem ist jetzt nicht so sehr, daß das Programm das nicht tut, sondern vielmehr, daß der Debugger "hängt" (ein Problem, das ich in Visual Basic nie hatte). Der Ablauf ist in etwa folgender:
1. Das Hauptfenster mit dem Listenfeld wird geöffnet. Das Listenfeld wird mit dem Inhalt einer Textdatei "befüllt".
2. Die Schaltfläche "Fach" des Hauptfensters wird angeklickt.
3. Es öffnet sich ein Unterfenster mit mehreren Checkboxen. Durch Setzen einer oder mehrerer Checkboxen des Unterfensters wird festgelegt, welche Zeilen des Listenfelds gelöscht werden sollen. Nach Betätigen der Schaltfläche "OK" des Unterfensters wird dieses korrekt geschlossen (bis hierhin läuft alles perfekt).
4. Nun sollen alle Zeilen des Listenfelds durchsucht werden, ob sie das Stück Text enthalten, das in 3. per Checkbox festgelegt wurde. Falls nicht, soll die betreffende Listenfeldzeile mittels RemoveGadgetItem gelöscht werden.

Es folgt die Repeat-Until-Ereignisschleife für das Unterfenster mit den Checkboxen. Ich habe sie der Vollständigkeit halber komplett eingefügt, es kommt aber nur auf den Teil nach der Kommentarzeile "3. Zeichenkette aus der Benutzerauswahl bilden" an. Diese Repeat-Until-Schleife ist natürlich Teil der Repeat-Until-Ereignisschleife des Hauptfensters. Der Kode nach "4. Alle Einträge löschen, deren Fach nicht in F enthalten ist" ist die Schleife, die die Zeilen aus dem Listenfeld löschen soll:

Code: Alles auswählen

        Repeat
          Et=WaitWindowEvent()
          If Et=#PB_Event_Gadget

            Select EventGadget()
              Case #Bs_aaw  ; alle auswählen
                For Zl=0 To AdF
                  SetGadgetState(#Fe_Fa+Zl+1, #PB_Checkbox_Checked)
                Next  
              Case #Bs_ads  ; alle deselektieren
                For Zl=0 To AdF
                  SetGadgetState(#Fe_Fa+Zl+1, #PB_Checkbox_Unchecked)
                Next  

;       3. Zeichenkette aus der Benutzerauswahl bilden
              Case #Sf_F
                F=#NULL$
                For Zl=0 To AdF
                  If GetGadgetState(#Fe_Fa+Zl+1)=#PB_Checkbox_Checked ; wenn angehakt,
                    F+GetGadgetText(#Fe_Fa+Zl+1)+#US$ ; wird der Text der Checkbox
                  EndIf                         ; zur Zeichenkette ’F’ hinzugefügt,
                Next                            ; die am Ende alle angehakten Fächer
                CloseWindow(#Fe_Fa)             ; enthält
            EndSelect
          EndIf  
        Until Et=#PB_Event_CloseWindow

;       4. Alle Zeilen löschen, deren Fach nicht in F enthalten ist
        For Zl=0 To Ix
          TxdZl=GetGadgetItemText(#Lf_Li, Zl)
          eF=StringField(TxdZl, 4, #US$)      ;
          If Not FindString(F, eF)
            RemoveGadgetItem(#Lf_Li, Zl)
          EndIf
        Next
3. scheint noch absolut korrekt abgearbeitet zu werden – das Unterfenster wird ja geschlossen, auch die Zeichenkette F wird korrekt gebildet –, aber der Programmfluß scheint nicht mehr bei 4. anzukommen. Jedenfalls wird der Haltepunkt, der sich in der ersten Zeile der Schleife (TxdZl=GetGadgetItemText(#Lf_Li, Zl)) befindet, nicht wie üblich mit einem kleinen Dreieck markiert – der Debugger "hängt" vor 4. fest. Während der gesamten Zeit ist natürlich das Hauptfenster mit dem Listenfeld geöffnet.

Ich hoffe, ich habe es einigermaßen verständlich erklärt. Was kann die Ursache dafür sein, daß der Debugger abbricht?

Vielen Dank
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Re: Debugger hängt

Beitrag von Salafat »

Hallo NickTheQuick,

ich bin Deiner Aufforderung gefolgt und habe einen maximal vereinfachten Kode geschrieben. In die Liste werden per Zufall Fächer hineingeschrieben, mit einer Nummer davor. Drückt man auf die Schaltfläche "Fach", sollen sämtliche Zeilen mit dem Fach "Geschichte" aus der Liste gelöscht werden (im richtigen Programm gibt es ein extra Fenster, wo man das zu löschende Fach auswählen kann). Das passiert zwar nicht, aber immerhin werden schon bestimmte Zeilen gelöscht, wenn auch die falschen. Das liegt wohl daran, daß ich nach wie vor die For-Next-Schleife verwendet habe, anstatt Deine While-Wend-Schleife. Das spielt hier aber keine Rolle, weil auch in diesem kurzen Programm der Debugger hängt:

Code: Alles auswählen

EnableExplicit

#Fe_Li=100
#Lf_Li=101
#Sf_F =102

Define.i Ix, Zl, Et ; Index, Zeile, Ereignistyp
Define.s Zf, TxdZl  ; Zufallsfach, Text der Zeile
Dim F.s(3)
F(0)="Englisch"
F(1)="Geschichte"
F(2)="Philosophie"
F(3)="Video"

OpenWindow(#Fe_Li, 0, 0, 375, 320, "Lerninhalte", #PB_Window_SystemMenu|
  #PB_Window_ScreenCentered)
ListViewGadget(#Lf_Li, 15, 15, 345, 235, #PB_ListView_MultiSelect|
  #PB_ListView_ClickSelect)
  While Ix<15
    Zf=Str(Ix+1)+". "+F(Random(3))
    AddGadgetItem(#Lf_Li, Ix, Zf)
    Ix+1
  Wend
ButtonGadget(#Sf_F, 115, 265, 42, 42, "Fach")

Repeat
  Et=WaitWindowEvent()
  If Et=#PB_Event_Gadget
    Select EventGadget()
      Case #Sf_F
        For Zl=0 To Ix
          TxdZl=GetGadgetItemText(#Lf_Li, Zl)
          If Not FindString(TxdZl, "Geschichte")
            RemoveGadgetItem(#Lf_Li, Zl)
          EndIf
        Next
    EndSelect
  EndIf
Until Et = #PB_Event_CloseWindow
Ich habe einen Haltepunkt in der Zeile

Code: Alles auswählen

  TxdZl=GetGadgetItemText(#Lf_Li, Zl)
gesetzt. Der Debugger hält aber dort nicht an, folglich läßt sich die Bearbeitung von dort auch nicht per Einzelschritt fortsetzen. Das ist zunächst einmal mein Hauptproblem (daß die falschen Listenzeilen gelöscht werden, ist erst einmal sekundär). Weißt Du, warum der Debugger hängt?

Vielen Dank
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Debugger hängt

Beitrag von NicTheQuick »

Ich Schlaumeier habe gerade statt deines Doppelposts meinen Post gelöscht. Naja, gibt schlimmeres.
Bei mir gibt es kein Problem mit deinen Haltepunkten. Sie halten genau dort an, wo sie sollen und sonst bleibt auch nichts stehen.
Kann es vielleicht sein, dass dein Antivirenprogramm da irgendwie dazwischen funkt? Die mögen Debugger nicht besonders.

Achja, hier mal der verbesserte Code:

Code: Alles auswählen

EnableExplicit

#Fe_Li = 100
#Lf_Li = 101
#Sf_F  = 102

Define.i Ix, Zl, Et ; Index, Zeile, Ereignistyp
Define.s Zf, TxdZl	; Zufallsfach, Text der Zeile
Dim F.s(3)
F(0) = "Englisch"
F(1) = "Geschichte"
F(2) = "Philosophie"
F(3) = "Video"

OpenWindow(#Fe_Li, 0, 0, 375, 320, "Lerninhalte", #PB_Window_SystemMenu|
                                                  #PB_Window_ScreenCentered)
ListViewGadget(#Lf_Li, 15, 15, 345, 235, #PB_ListView_MultiSelect|
                                         #PB_ListView_ClickSelect)
While Ix < 15
	Zf = Str(Ix + 1) + ". " + F(Random(3))
	AddGadgetItem(#Lf_Li, Ix, Zf)
	Ix + 1
Wend
ButtonGadget(#Sf_F, 115, 265, 42, 42, "Fach")

Repeat
	Et = WaitWindowEvent()
	If Et = #PB_Event_Gadget
		Select EventGadget()
			Case #Sf_F
				Ix = CountGadgetItems(#Lf_Li)
				Zl = 0
				While (Zl < Ix)
					TxdZl = GetGadgetItemText(#Lf_Li, Zl)
					If FindString(TxdZl, "Geschichte")
						RemoveGadgetItem(#Lf_Li, Zl)
						Ix - 1
					Else
						Zl + 1
					EndIf
				Wend
		EndSelect
	EndIf
Until Et = #PB_Event_CloseWindow
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Re: Debugger hängt

Beitrag von Salafat »

Hallo NicTheQuick,

erst einmal noch ein ausdrückliches Danke für Deine Verbesserungen (ich habe selbstverständlich auch auf den Danke-Button gedrückt). Bei einem zweiten Durchlauf funktionierte auch bei mir der Haltepunkt – keine Ahnung, was beim ersten Mal los war (am Anti-Viren-Programm lag es aber sicher nicht).

Aufgrund des erfolgreichen Durchlaufs dieses sehr minimalistischen Programms dachte ich mir, daß man, um dem Problem auf die Spur zu kommen, einen Quellkode schreiben muß, der näher am ursprünglichen Programm ist. Der kann dann notwendigerweise nicht mehr so minimalistisch sein. Ich habe nämlich den Verdacht, daß es irgendetwas mit dem Unterfenster, in dem man die auszusondernden Fächer festlegt, zu tun hat.

Da ich Dir die Datei, mit der das Listenfeld befüllt wird, nicht übermitteln kann, habe ich nach guter alter Basic-Manier eine Data-Sektion ans Ende des Quellkodes gesetzt. Die Strings nach Data.s haben exakt dasselbe Format, wie jeweils eine Zeile in meiner Textdatei. Der Read-Befehl liest also die Zeilen aus der Data-Sektion genau so aus, wie es der ReadString-Befehl im ursprünglichen Programm aus der Textdatei tut. Möglicherweise mußt Du, wenn Du den Quelltext in Deine IDE kopierst, die Umbrüche bei den Data-Strings entfernen, denn die Strings sind sehr lang. Es müssen exakt 20 nichtumbrochene Data-Zeilen sein.

Bei dieser zweiten Version, die sehr nah am Original ist, wird auch der Haltepunkt nach der Kommentarzeile

Code: Alles auswählen

;       4. Alle Einträge löschen, deren Fach nicht in F enthalten ist
also die For-Next-Schleife, definitiv nicht erreicht (ich habe es mehrmals getestet). Bis zum Ende von

Code: Alles auswählen

;       3. Zeichenkette aus der Benutzerauswahl bilden
läuft alles perfekt:

Code: Alles auswählen

EnableExplicit

Enumeration 100
  #Fe_Li
  #Lf_Li
  #Sf_F
  #Fe_Fa=200
  #Sf_a =291
  #Sf_k
  #Sf_OK
EndEnumeration

Define.i AaLi=20, HLf=AaLi*15+21, HFe=HLf+70
OpenWindow(#Fe_Li, 0, 0, 375, HFe, "Lerninhalte", #PB_Window_SystemMenu|
  #PB_Window_ScreenCentered)
ListViewGadget(#Lf_Li, 10, 10, 355, HLf, #PB_ListView_MultiSelect|
  #PB_ListView_ClickSelect)
ButtonGadget(#Sf_F, 10, HFe-50, 42, 42, "Fach")

Define.i GrLf, Gk, GrLfzs
Define.i brE, Ix, Zl, AdF, Et
Define.s TxdZl, eF, F
Define.size Lw

GrLf=GadgetID(#Lf_Li)
Gk=GetDC_(GrLf)
LoadFont(1, "Arial", 10)
GrLfzs=FontID(1)

SetGadgetFont(#Lf_Li, GrLfzs)
SelectObject_(Gk, GrLfzs)

ReadFile(1, "D:\Lernen\gesamte Lerninhalte.txt")
  Repeat 
    Read.s TxdZl
    TxdZl=ReplaceString(TxdZl, "|", ", "+#US$)
    GetTextExtentPoint32_(Gk, @TxdZl, Len(TxdZl), Lw)
    If brE<Lw\cx
      brE=Lw\cx
    EndIf
    AddGadgetItem(#Lf_Li, Ix, TxdZl)
    Ix+1
  Until Ix=20
CloseFile(1)
SendMessage_(GrLf, #LB_SETHORIZONTALEXTENT, brE+8, 0)
ReleaseDC_(GrLf, Gk)

Repeat
  Et=WaitWindowEvent()
  If Et=#PB_Event_Gadget
    Select EventGadget()
      Case #Sf_F
        Ix=CountGadgetItems(#Lf_Li)-1
;       1. Welche Fächer sind in der Liste enthalten? 
        For Zl=0 To Ix
          TxdZl=GetGadgetItemText(#Lf_Li, Zl)
          eF=StringField(TxdZl, 4, #US$)  ; Fach des Einzeleintrags eF zuweisen
          If Not FindString(F, eF)        ; Zeichenkette F bilden, die aus allen          
            F+eF+"|"                      ; im Feld enthaltenen Fächern besteht
          EndIf
        Next

;       2. Fenster anzeigen, das die enthaltenen Fächer auflistet
        AdF=CountString(F, "|")-1  ; Anzahl der Fächer minus 1
        Dim Fl.s(AdF)                       ; Feld ’Fächerliste’
        For Zl=0 To AdF                     
          Fl(Zl)=StringField(F, Zl+1, "|")  ; Fächer aus der Zeichenkette ’F’ ins
        Next                                ; Feld ’Fächerliste’ einlesen
        SortArray(Fl(), 0)                  ; Feld ’Fächerliste’ alphabetisch ordnen

        LoadFont(2, "Segoe UI", 10)
        GrLfzs=FontID(2)
        
        OpenWindow(#Fe_Fa, 0, 0, 160, AdF*20+90, "Fachauswahl",
          #PB_Window_WindowCentered, WindowID(#Fe_Li))
        GrLf=WindowID(#Fe_Fa)
        Gk=GetDC_(GrLf)
        SelectObject_(Gk, GrLfzs)
        SetGadgetFont(#PB_Default, GrLfzs)

        For Zl=0 To AdF                   
          GetTextExtentPoint32_(Gk, @Fl(Zl), Len(Fl(Zl)), Lw)
          CheckBoxGadget(#Fe_Fa+Zl+1, 10, Zl*20+10, Lw\cx+18, 20, Fl(Zl))
        Next
        ReleaseDC_(GrLf, Gk)
        ButtonGadget(#Sf_a, 10, AdF*20+38, 42, 42, "alle")
        ButtonGadget(#Sf_k, 60, AdF*20+38, 42, 42, "keins")
        ButtonGadget(#Sf_OK, 110, AdF*20+38, 42, 42, "OK")

        Repeat
          Et=WaitWindowEvent()
          If Et=#PB_Event_Gadget
            Select EventGadget()
              Case #Sf_a  ; alle auswählen
                For Zl=0 To AdF
                  SetGadgetState(#Fe_Fa+Zl+1, #PB_Checkbox_Checked)
                Next  
              Case #Sf_k  ; alle deselektieren
                For Zl=0 To AdF
                  SetGadgetState(#Fe_Fa+Zl+1, #PB_Checkbox_Unchecked)
                Next  

;       3. Zeichenkette aus der Benutzerauswahl bilden
              Case #Sf_OK
                F="|"
                For Zl=0 To AdF
                  If GetGadgetState(#Fe_Fa+Zl+1)=#PB_Checkbox_Checked ; wenn angehakt,
                    F+GetGadgetText(#Fe_Fa+Zl+1)+"|" ; wird der Text der Checkbox
                  EndIf                         ; zur Zeichenkette ’F’ hinzugefügt,
                Next                            ; die am Ende alle angehakten Fächer
                CloseWindow(#Fe_Fa)             ; enthält
            EndSelect
          EndIf  
        Until Et=#PB_Event_CloseWindow


;       4. Alle Einträge löschen, deren Fach nicht in F enthalten ist
        Zl=0
        While Zl<Ix
          eF="|"+StringField(GetGadgetItemText(#Lf_Li, Zl), 4, #US$)+"|"
          If Not FindString(F, eF)
            RemoveGadgetItem(#Lf_Li, Zl)
          EndIf

          If StringField(GetGadgetItemText(#Lf_Li, Zl), 4, #US$)=F
            RemoveGadgetItem(#Lf_Li, Zl)
            Ix-1
          Else
            Zl+1
          EndIf
        Wend
    EndSelect
  EndIf
Until Et=#PB_Event_CloseWindow

DataSection
Data.s "Hewings Martin|Advanced Grammar in Use, 3. Aufl. 2013|20 Should, ought to and had better|Englisch"
Data.s "Hewings Martin|Advanced Grammar in Use, 3. Aufl. 2013|21 Linking verbs: be, appear, seem; become, get, etc.|Englisch"
Data.s "Hewings Martin|Advanced Grammar in Use, 3. Aufl. 2013|22 Forming passive sentences 1|Englisch"
Data.s "Hewings Martin|Advanced Grammar in Use, 3. Aufl. 2013|23 Forming passive sentences 2: verb + -ing or to-infinitive|Englisch"
Data.s "Hewings Martin|Advanced Grammar in Use, 3. Aufl. 2013|24 Using passives|Englisch"
Data.s "Roland Vocke|Deutsche Geschichte (hg. v. Heinrich Pleticha), Bd. 1|Cluny und Gorze und ihre Reformen, S. 246–254|Geschichte"
Data.s "Hanswernfried Muth, Günter Merwald|Deutsche Geschichte (hg. v. Heinrich Pleticha), Bd. 1|Die romanische Kunst der Salierzeit–Literatur in der salischen Zeit, S. 255–67|Geschichte"
Data.s "Siegfried Grißhammer|Deutsche Geschichte (hg. v. Heinrich Pleticha), Bd. 1|Die Zeit des Investiturstreits, Bischöfliches Kidnapping: Entführung des jungen Königs und Ende der Regentschaft–Der Streit zwischen Kaiser und Papst: Spaltung der Einheit der mittelalterlichen Welt, S. 268–78|Geschichte"
Data.s "Siegfried Grißhammer|Deutsche Geschichte (hg. v. Heinrich Pleticha), Bd. 1|Die Zeit des Investiturstreits, „Dictatus papae“: Päpstlicher Machtwille–Der Gang nach Canossa Unterwerfung oder Kalkül?, S. 279–92|Geschichte"
Data.s "Siegfried Grißhammer|Deutsche Geschichte (hg. v. Heinrich Pleticha), Bd. 1|Die Zeit des Investiturstreits, Erneute Fürstenopposition: Rudolf von Rheinfelden zum Gegenkönig gewählt–Weitere Erfolge für Papst Urban II., S. 292–303|Geschichte"
Data.s "Hirschberger Johannes|Geschichte der Philosophie, Band 1|II. Abschnitt: Die Philosophie des Mittelalters, 1. Kapitel: Die Philosophie der Patristik, 3. Augustinus: Der Lehrer des Abendlandes, Leben–A. Wahrheit|Philosophie"
Data.s "Hirschberger Johannes|Geschichte der Philosophie, Band 1|II. Abschnitt: Die Philosophie des Mittelalters, 1. Kapitel: Die Philosophie der Patristik, 3. Augustinus: Der Lehrer des Abendlandes, B. Gott|Philosophie"
Data.s "Hirschberger Johannes|Geschichte der Philosophie, Band 1|II. Abschnitt: Die Philosophie des Mittelalters, 1. Kapitel: Die Philosophie der Patristik, 3. Augustinus: Der Lehrer des Abendlandes, C. Schöpfung|Philosophie"
Data.s "Hirschberger Johannes|Geschichte der Philosophie, Band 1|II. Abschnitt: Die Philosophie des Mittelalters, 1. Kapitel: Die Philosophie der Patristik, 3. Augustinus: Der Lehrer des Abendlandes, D. Seele|Philosophie"
Data.s "Hirschberger Johannes|Geschichte der Philosophie, Band 1|II. Abschnitt: Die Philosophie des Mittelalters, 1. Kapitel: Die Philosophie der Patristik, 3. Augustinus: Der Lehrer des Abendlandes, E. Das Gute–F. Gottesstaat|Philosophie"
Data.s "Pascoe Graham|Englisch für Anfänger (1982)|30. The Editor's Office|Video"
Data.s "Pascoe Graham|Englisch für Anfänger (1982)|31. The Election Campaign|Video"
Data.s "Pascoe Graham|Englisch für Anfänger (1982)|32. The Helpful Neighbour|Video"
Data.s "Pascoe Graham|Englisch für Anfänger (1982)|33. At the Police Station|Video"
Data.s "Pascoe Graham|Englisch für Anfänger (1982)|34. Mail Order Shopping|Video"
Das Fenster wird nach dem CloseWindow(#Fe_Fa)-Befehl geschlossen, aber die Repeat-Until-Ereignisschleife des Unterfensters nicht verlassen, so daß es dort offenbar zu einer Endlos-Schleife kommt.

Nur für den Fall, daß Du mit GetTextExtentPoint32 nichts anfangen kannst: Das ist eine API-Funktion, mit der man die Länge von Texten auf dem Bildschirm ausmessen kann. So wird z.B. bei Listenfeldern nur dann ein waagerechter Scrollbalken angezeigt, wenn man dem Listenfeld durch SendMessage_(Handle des Listenfeldes, #LB_SETHORIZONTALEXTENT, Breite, 0) mitgeteilt hat, wie breit die längste Zeile in ihm ist. GetTextExtentPoint32 benötigt als Parameter 1. den Gerätekontext (Gk), 2. einen Zeiger auf den auszumessenden String, 3. die Anzahl der Zeichen, aus denen der String besteht und 4. eine Size-Struktur, in die dann die Breite (cx) und Höhe (cy) des Strings geschrieben werden. Mit SelectObject_(Gerätekontext, Handle des Fonts) wird der Font des Strings in den Gerätekontext geladen.

Vielen Dank
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
matbal
Beiträge: 261
Registriert: 30.03.2011 20:53

Re: Debugger hängt

Beitrag von matbal »

Dein Programm hängt in der inneren Schleife fest. Du schließt zwar das Auswahlfenster, verläßt aber nicht die Schleife.

noch zwei Fragen:
1. Warum verwendest du überhaupt ineinander verschachtelte Event-Loops? Das macht das Ganze ziemlich unübersichtlich.
2. Wäre es nicht einfacher, die Liste nach dem Filtern einfach mit den gefilterten Daten neu zu befüllen?
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Re: Debugger hängt

Beitrag von Salafat »

Hallo Mathal,
1. Warum verwendest du überhaupt ineinander verschachtelte Event-Loops? Das macht das Ganze ziemlich unübersichtlich.
Deine Frage ist sicherlich berechtigt. Ich weiß schlicht nicht, wie ich es sonst machen soll, und wäre für einen Rat dankbar. Ich programmiere erst seit kurzem in PureBasic, und die Verarbeitung von Ereignissen unterscheidet sich in PureBasic sehr von der in Visual Basic oder Power Basic.
Wäre es nicht einfacher, die Liste nach dem Filtern einfach mit den gefilterten Daten neu zu befüllen?
Die Frage ist, an welcher Stelle man die Daten filtert. D.h., ob man sie zuerst in ein Array oder eine LinkList einliest, diese dann "filtert", und das Ergebnis der Filterung in das Listenfeld zurückschreibt. Mir ist aber nicht klar, was der Vorteil dieser Vorgehensweise gegenüber der direkten Bearbeitung des Listenfeldes ist.
Bedauerlicherweise liegt PureBasic, was die Manipulation von Strings, Arrays, Listenfeldern usw. angeht, weit hinter den Möglichkeiten von VB oder PowerBasic zurück. Es ist, um nur ein Beispiel zu nennen, in PureBasic nicht möglich, die Anzahl der Zeilen einer Textdatei, aus der man Daten auslesen will, festzustellen, zumindest nicht mit einem einzelnen Befehl, was man aber für die Dimensionierung eines Arrays mit einem Arrayelement pro Textzeile bräuchte. Zwar gibt es das Lof()-Schlüsselwort, aber das liefert nur die Länge der Datei in Bytes, nicht die Anzahl der Zeilen. In PowerBasic z.B. gibt es dafür den Befehl FileScan.
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Debugger hängt

Beitrag von NicTheQuick »

Salafat hat geschrieben:
1. Warum verwendest du überhaupt ineinander verschachtelte Event-Loops? Das macht das Ganze ziemlich unübersichtlich.
Deine Frage ist sicherlich berechtigt. Ich weiß schlicht nicht, wie ich es sonst machen soll, und wäre für einen Rat dankbar. Ich programmiere erst seit kurzem in PureBasic, und die Verarbeitung von Ereignissen unterscheidet sich in PureBasic sehr von der in Visual Basic oder Power Basic.
Ich denke, wenn du dir mal die Befehle 'BindEvent()' und 'BindGadgetEvent()' anschaust, wirst du verblüfft sein wie ähnlich das zu VB sein kann.
Salafat hat geschrieben:
Wäre es nicht einfacher, die Liste nach dem Filtern einfach mit den gefilterten Daten neu zu befüllen?
Die Frage ist, an welcher Stelle man die Daten filtert. D.h., ob man sie zuerst in ein Array oder eine LinkList einliest, diese dann "filtert", und das Ergebnis der Filterung in das Listenfeld zurückschreibt. Mir ist aber nicht klar, was der Vorteil dieser Vorgehensweise gegenüber der direkten Bearbeitung des Listenfeldes ist.
Bedauerlicherweise liegt PureBasic, was die Manipulation von Strings, Arrays, Listenfeldern usw. angeht, weit hinter den Möglichkeiten von VB oder PowerBasic zurück. Es ist, um nur ein Beispiel zu nennen, in PureBasic nicht möglich, die Anzahl der Zeilen einer Textdatei, aus der man Daten auslesen will, festzustellen, zumindest nicht mit einem einzelnen Befehl, was man aber für die Dimensionierung eines Arrays mit einem Arrayelement pro Textzeile bräuchte. Zwar gibt es das Lof()-Schlüsselwort, aber das liefert nur die Länge der Datei in Bytes, nicht die Anzahl der Zeilen. In PowerBasic z.B. gibt es dafür den Befehl FileScan.
Um die Textzeilen einer Datei festzustellen, muss man sie gezwungenermaßen einmal komplett scannen. Dabei gibt es zwei Möglichkeiten. Eine leichte und möglicherweise langsamere und eine kompliziertere und wahrscheinlich schnellere.
Die einfachere Methode wäre einmal die Textdatei mit 'ReadLine()' zu lesen und zu zählen wie oft man es hat aufrufen müssen. Dann öffnet man sie erneut oder setzt mit 'FileSeek()' den Dateizeiger wieder an den Anfang, dimensioniert sein Array passend und liest sie wieder ein. Nichts anderes wird der Befehl 'FileScan' bei PowerBasic machen.
Hier mal ein Beispiel wie man es implementieren könnte:

Code: Alles auswählen

Procedure.q CountLines(id.i)
	; Merke dir die aktuelle Position
	Protected position.q = Loc(id)
	Protected lines.q = 0
	
	; Springe an den Anfang der Datei
	FileSeek(id, 0)
	
	; Lies solange einzelne Zeilen aus wie möglich und zähle mit
	While Not Eof(id)
		ReadString(id)
		lines + 1
	Wend
	
	; Springe wieder zu alten Position zurück
	FileSeek(id, position)
	
	; Gib die Anzahl an Zeilen zurück
	ProcedureReturn lines
EndProcedure

If ReadFile(0, "Datei.txt")
	; Bestimme die Anzahl an Zeilen
	Define lines.q = CountLines(0)
	
	; Dimensioniere das Array, was die Zeilen speichern soll, entsprechend
	Dim zeile.s(lines - 1)
	
	; Lies die Zeilen nacheinander in das Array ein
	Define i.i
	For i = 0 To lines - 1
		zeile(i) = ReadString(0)
	Next
	
	; Gib beispielhaft die letzte Zeile aus
	Debug "Letzte Zeile: " + zeile(lines - 1)
EndIf
Die komplizierte Methode kann ich dir gerne auch noch schreiben, aber ich denke die passt jetzt auch nicht so gut ins Anfänger-Forum.
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Re: Debugger hängt

Beitrag von Salafat »

Hallo,

matbal hatte die Frage gestellt, wieso ich ineinander verschachtelte Repeat-Until-Ereignisschleifen verwende. Genau das ist ja der Kern des Problems: Der Debugger kommt aus der inneren Repeat-Until-Schleife nicht heraus, obwohl das Fenster, das das Ereignis ausgelöst hatte, geschlossen wurde. Und das ist es, was ich nicht verstehe. Die Schleife müßte doch eigentlich verlassen werden, weil es gar keine mehr zu verarbeitenden Ereignisse mehr geben kann (eben weil das Fenster nicht mehr existiert).

Darf man in PureBasic überhaupt keine Ereignisschleifen schachteln? Falls ja, wie handelt man dann meinen Fall eines Hauptfensters, in dem auf eine Schaltfläche geklickt wird, und das daraufhin seinerseits ein (Unter-)Fenster öffnet, das seine eigene (Unter-)Repeat-Until-Schleife benötigt? Schachteln darf man offenbar nicht. Aber wie macht man es dann richtig, oder, noch besser, "mustergültig"?

Vielen Dank
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Debugger hängt

Beitrag von NicTheQuick »

Das Problem ist eigentlich nur, dass du zwar 'CloseWindow(#Fe_Fa)' aufrufst, wenn der OK-Button geklickt wurde, aber dann die Schleife nicht verlässt. Die innere Schleife wird bei dir nur dann verlassen, wenn man auf das X klickt und somit der Event '#PB_Event_CloseWindow' ausgelöst wird. Da du nach dem "OK" aber das Fenster schließt, wird dieser Event gar nicht mehr ausgelöst. Die Lösung ist deshalb einfach: Hinter dem 'CloseWindow(#Fe_Fa)' muss noch ein 'Break' stehen, damit die innere Schleife verlassen wird.

Allerdings hat matbal auch damit Recht, dass es unschön ist die Ereignis-Schleife zu verschachteln. Mit 'EventWindow()' kann man feststellen in welchem Fenster ein Ereignis statt gefunden hat. Wenn man das weiß, kann man auch mit einer einzigen Schleife einfach feststellen in welchem Fenster gerade ein Ereignis statt gefunden hat und entsprechend reagieren. Das kann man dann z.B. mit einem nochmal übergeordneten 'Select EventWindow()' regeln.

Hier mal ein simples Beispiel. Ich hoffe das bedarf keiner besonderen Erklärung.

Code: Alles auswählen

EnableExplicit

Enumeration Windows
	#WIN_MAIN
	#WIN_DIALOG
EndEnumeration

Enumeration Gadgets
	#BTN_DIALOG
	#TXT_INFO
	#BTN_YES
	#BTN_NO
EndEnumeration

Procedure OpenMainWindow()
	If OpenWindow(#WIN_MAIN, 0, 0, 640, 480, "Hauptfenster", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
		ButtonGadget(#BTN_DIALOG, 5, 5, 100, 25, "Öffne Dialog")
		TextGadget(#TXT_INFO, 5, 35, 400, 20, "Es ist noch nichts passiert")
	EndIf
EndProcedure

Procedure OpenDialogWindow()
	; Damit verhindern wir, dass man das Hauptfenster noch nutzen kann, während das Dialogfenster auf ist.
	DisableWindow(#WIN_MAIN, 1)
	If OpenWindow(#WIN_DIALOG, 0, 0, 400, 300, "Dialogfenster", #PB_Window_WindowCentered | #PB_Window_SystemMenu, WindowID(#WIN_MAIN))
		ButtonGadget(#BTN_YES, 0, 0, 200, 300, "Ja")
		ButtonGadget(#BTN_NO, 200, 0, 200, 300, "Nein")
	EndIf
EndProcedure

Procedure CloseDialogWindow()
	CloseWindow(#WIN_DIALOG)
	; Und hier das Gegenteil von oben.
	DisableWindow(#WIN_MAIN, 0)
EndProcedure

OpenMainWindow()

Repeat
	Define event.i = WaitWindowEvent()
	
	Select EventWindow()
		; Wenn im Hauptfenster etwas passiert ist, verarbeiten wir diese Events entsprechend
		Case #WIN_MAIN
			Select event
				Case #PB_Event_CloseWindow
					Break
				Case #PB_Event_Gadget
					If (EventGadget() = #BTN_DIALOG)
						OpenDialogWindow()
					EndIf
			EndSelect
			
		; Und ab hier verarbeiten wir die Events vom Dialogfenster
		Case #WIN_DIALOG
			Select event
				Case #PB_Event_CloseWindow
					SetGadgetText(#TXT_INFO, "'X' wurde geklickt")
					CloseDialogWindow()
				
				Case #PB_Event_Gadget
					Select EventGadget()
						Case #BTN_YES
							SetGadgetText(#TXT_INFO, "'Ja' wurde geklickt")
						
						Case #BTN_NO
							SetGadgetText(#TXT_INFO, "'Nein' wurde geklickt")
					EndSelect
			EndSelect
	EndSelect	
ForEver

CloseWindow(#WIN_MAIN)
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Debugger hängt

Beitrag von ts-soft »

@NicTheQuick

Du solltest besser, erst Fenster erstellen, und dann erst anderes Fenster disablen, bzw. umgekehrt.
Ansonsten wird Deine Anwendung den Fokus verlieren, und das wollen wir ja nicht.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Antworten