Toon posts:

[Delphi]messageDlg reageert pas na enkele keer klikken.

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben bezig met het aanpassen/uitbreiden van een applicatie die geschreven is in Delphi 7.
Heel in het kort doet de applicatie het volgende.
Elke twee seconden wordt een string door de compoort gestuurd waarop het aangesloten apparaat data terug stuurt.
Deze data wordt in een logfile opgeslagen.
Omdat het apparaat via een externe batterij van stroom wordt voorzien kan het voorkomen (en dat gebeurd in de praktijk regelmatig) dat de batterij leeg raakt. Er wordt daardoor geen data meer gestuurd door het apparaat.
De applicatie reageert daarop door de status op 'Pauze' te zetten en te pauzeren met het wegschrijven in de logfile. De timer gaat wel gewoon door en blijft vragen om data.
Een messageDlg wordt getoond met de mededeling dat er geen data meer door de poort komt.
Vervolgens kan de gebruiker de batterij verwisselen, de messageDlg wegklikken en het loggen hervatten door op de 'Hervat'-knop te klikken. De status wordt dan weer 'Loggen' en de data wordt gelogd.
Dit werkt allemaal prima, behalve het wegklikken van de messageDlg. Er dient een aantal keren op de OK-knop geklikt te worden alvorens er wordt gereageerd.
Zet ik nu een breakpunt op de messageDlg, waardoor de execution stopt en ik klik dan op OK dan verdwijnt messageDlg gelijk.
Ik heb al Application.ProcessMessages; toegevoegd maar zonder resultaat.
Hier is de code:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
procedure TfrmMain.OnFout(Sender: TObject; Msg, Error: String);
var t: textFile;
var regel: String;
var crlf : string;
var msg2: string;
begin
  crlf := Chr(13)+Chr(10);

  If not (Status = idle) and not (Status = LoggenOppauze) then
  Begin

    btnPauzeClick(nil);   //Pauzeer de meting

    //Schrijf de fout weg in een log file.
    Try
    begin
      //Zet maar gewoon bij de logfiles:
      if not FileExists('Error.log') then
      begin
        try
        begin
          AssignFile(t, 'Error.log');
          Rewrite(t);
          CloseFile(t);
        end
        except end;
      end;
      AssignFile(t, 'Error.log');
      Append(t);
      regel := DateToStr(Date) + ' ' + TimeToStr(Time);
      regel := regel + ':  ' + Msg + ': ' + Error;
      writeln(t, regel);
      Closefile(t);
    end
    except
      on E: Exception do
      begin
        OutputDebugString(PChar('Exception in TfrmMain.OnFout: ' + E.Message));
        ShowMessage(E.Message);
      end;
    end;
    sndPlaySound('sirene.wav', 1);             //laat sirene horen
    //Zet tijd erbij om te kijken of het wel om dezelfde box gaat:
    msg2 := TimeToStr(now) + 'OnFout! Status: ' + inttostr(ord(status)) + FError + Msg + Error;
    OutputDebugString(PChar(msg2));
    Application.ProcessMessages;
    messageDlg(msg2, mtError, [mbOk], 0);
    Application.ProcessMessages;
  end;
end;


Wie kan mij vertellen wat ik vergeet.
Misschien wel al duidellijk, maar ik heb (nog) weinig kennis van Delphi ;)

Alvast bedankt.

Verwijderd

heb je je timer uitgezet?

timer1.enabled := false;

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 01-12 21:29

Tomatoman

Fulltime prutser

Wat er volgens mij gebeurt is het volgende:
  1. Er worden geen data ontvangen, waardoor er een timer event optreedt.
  2. De timer event zet de applicatie op pauze en er verschijnt een dialoogvenster.
  3. De gebruiker heeft nog geen tijd gehad om op de dialoog te reageren (want hij is bijvoorbeeld niet in de buurt), maar er wordt wel weer een nieuwe timer event gegenereerd. En nog een en nog een. Deze worden allemaal in de message queue van de applicatie geplaatst, maar nog niet afgehandeld. De applicatie wacht immers op input van de gebruiker bij het dialoogvenster.
  4. Nu komt de gebruiker in actie en drukt op OK.
  5. De applicatie werkt de message queue af (Application.ProcessMessages), net zolang tot hij leeg is. Stap 2 t/m 4 worden net zolang herhaald totdat er geen timer events meer zijn. Het lijkt dat het drukken op OK geen resultaat heeft, maar in werkelijkheid verschijnt er vlak nadat het dialoogvenster is gesloten weer een nieuw dialoogvenster.
Conclusie: de opbouw van je programma deugt niet. Zet gewoon de timer stop zodra er een event is geweest en zet hem pas weer aan als de gebruiker het dialoogvenster heeft gesloten. Probleem opgelost. :)

Een goede grap mag vrienden kosten.


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 01-12 21:29

Tomatoman

Fulltime prutser

Of het verhaal van die opnieuw verschijnende dialoogbox ook echt zo is kun je trouwens heel makkelijk zien. Versleep het dialoogvenster naar een andere locatie en druk op OK. Als het een nieuw dialoogvenster is dat terugkeert, zal het weer op de standaardlocatie in het midden van je scherm staan. Verschijnt het op dezelfde plek, dan heb je goede kans dat het het oude venster is.

Een goede grap mag vrienden kosten.


  • The Fox NL
  • Registratie: Oktober 2004
  • Laatst online: 10:15
Verander je de status wel in 'LoggenOpPauze'/'idle' in je procedure btnPauzeClick, of zet je hem ergens anders weer op iets anders dan 'idle' of 'LoggenOpPauze'? In je post heb je het ook over de status 'Pauze' ipv 'LoggenOpPauze'. Anders zal je zeker last hebben van dat probleem dat Tomatoman aankaart.

[ Voor 14% gewijzigd door The Fox NL op 19-01-2007 18:04 ]


Verwijderd

Topicstarter
Ik had zelf al gedacht dat de messagebox meerdere keren werd getoont. Daarom heb ik
OutputDebugString(PChar(msg2));
toegevoegd en ook de tijd aan msg2 en later ook nog eens een sleep(1000)
Maar OutputDebugString wordt maar 1 keer uitgevoerd, de tijd in msg2 wordt niet aangepast.
messageDlg komt netjes in het midden, als ik die verplaats en op OK klik dan zou de nieuwe messageDlg ook weer in het midden moeten komen, maar die blijft op dezelfde plek.
Ik heb wat geprobeerd met de timer, maar dat geeft weer nieuwe problemen. Oa. dat de tijdsduur van 2 seconden verloren gaat en dat een andere, kortere tijdsduur (default waarde?) wordt gebruikt als ik de timer weer enable.
Al met al is het nog al een uitzoekwerk. Ik ga weer verder met debuggen, mocht iemand nog een andere oplossing weten dan hoor ik het graag.

Edit:
Door de cache :? de laatste twee berichten gemist.
In mijn verhaal gebruik ik Pauze en LoggenOpPauze door elkaar maar in mijn code is het wel dezelde, sorry.
De status bij de messageDlg is LoggenOpPauze dat is correct, want daar is die net opgezet. Zoals ik hierboven al zeg, is het volgens mij dezelfde box omdat na het verplaatsen van de box, de 'nieuwe' op de verplaatste plek blijft staan.

Paul

[ Voor 19% gewijzigd door Verwijderd op 22-01-2007 11:01 ]


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 01-12 21:29

Tomatoman

Fulltime prutser

Haal om te testen eerst eens de regels met Application.ProcessMessages weg. Die regels beïnvloeden zoals gezegd de afhandelvolgorde van messages en daarmee ook timer events.

Plaats ook eens wat breakpoints en loop dan stap voor stap door je code heen. Dan zie je vanzelf wat er gebeurt. Je kunt ook kijken naar de call stack, dan zie je of er geneste aanroepen van de OnFout procedure plaatsvinden. Het is allemaal een kwestie van gestructureerd debuggen. Daarmee kom je een stuk verder dan zomaar wat proberen en gokken wat er fout gaat. :)

Een goede grap mag vrienden kosten.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
tomatoman schreef op maandag 22 januari 2007 @ 13:46:
Het is allemaal een kwestie van gestructureerd debuggen. Daarmee kom je een stuk verder dan zomaar wat proberen en gokken wat er fout gaat. :)
En als je dat maar lang genoeg gedaan hebt kom je erachter dat met gestuctureerd programmeren ook niets mis is omdat je dan niet zolang hoeft te debuggen. :)

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1