Toon posts:

[Alg/Delphi] Hoe GUI en berekening scheiden?

Pagina: 1
Acties:
  • 740 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Ik wil graag in mijn programma GUI en berekeningen scheiden.

Ik hanteer de eenvoudige regel: in de code voor berekeningen staat geen enkele verwijzing naar de GUI.

Voor de invoer is dat eenvoudig. Maar voor de uitvoer is het lastiger, omdat de berekeningen in een loop gebeuren en ik graag elke iteratie, dus realtime, mijn GUI wil updaten (bv de laatst berekende uitvoer aan een tabel of grafiek toevoegen).

Nu doe ik bijvoorbeeld:
code:
1
2
3
4
5
Procedure DoeBerekeningen
Loop 1000x
   waarde := Berekening();
   FormOutput.Grafiek.Add(waarde).    <=== OOPS
End

Dit werkt prima, maar de routine voor de berekeningen schrijft direct naar de GUI. Dat wil ik niet.

Om dit op te lossen dacht ik aan:
1. Zet een timer in je GUI, die om de zoveel tijd kijkt of er nieuwe data is.
2. Schrijf je data weg naar file. GUI leest de file (dit is lastiger dan je denkt, de file is vaak open tijdens lezen, je leest soms half afgebroken uitvoer: bv 3,1 ipv 3,1415...).

Hebben jullie (betere) ideeen, tips, ervaring?

Hoe doen bv virusscanners dat? Dan zie je ook vaak razendsnel de filenamen voorbijkomen die worden gescanned. Maar hoe weet de GUI welke file wordt gescanned?

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:00
Threads.

Je kan een class maken die een 'taak' uitvoert, bv, het uitvoeren van jouw berekening.
Die 'taak-class' heeft ook een event.

In je gui creeër je dan een instance van die 'taak-class', en je hangt een method aan die custom event van jouw custom class. Die method -die zich in jouw gui bevindt- zorgt ervoor dat jouw gui ge-updated wordt.
Jouw 'taak' class moet er dan wel voor zorgen dat zijn 'event' getriggered wordt, wat er dus voor zal zorgen dat jouw gui die method gaat uitvoeren.

Echter: hou er wel rekening mee dat in windows volgende regel geldt:
Enkel de 'thread' die de control gecreeërd heeft, mag die control gaan 'wijzigen'. Je zult dus een Invoke oid moeten doen op die control.

/in-een-notendop-mode, maar ik denk dat je toch wel wat termen hebt waar je kunt op zoeken....

https://fgheysels.github.io/


  • ReallyStupidGuy
  • Registratie: Januari 2002
  • Laatst online: 01-05 10:31
Kun je misschien een berekeningencomponent maken met een OnBerekeningResult event en properties voor resultaten?

code:
1
2
3
property input: tinput read fInput write fInput;
property OutPutList: array of tOutPut read fOutPutList;
property LastOutput: TOutPut read fOutPut;


of eventueel de lastoutput meegeven aan het event, laatste in de array of misschien zelfs geen array bewaren. Dat zijn keuzes die je zelf moet maken.

Duizend wijzen kunnen meer vragen stellen dan één idioot kan beantwoorden.


Verwijderd

Nog een mogelijkheid : Gebruik een callback procedure. Op die manier kun je een procedure in je GUI doorgeven aan je berekeningen, en die tijdens de berekening aanroepen. De windows API werkt hier af en toe ook mee, onder andere de EnumWindows functie.

  • FendtVario
  • Registratie: Januari 2002
  • Laatst online: 12-05-2025

FendtVario

The leader drives Vario!

Callbacks vind ik ook wel een goede mogelijkheid al gebruik ik die meer voor het geven van status berichten dan voor het teruggeven van complete resultaten. Wat je ook zou kunnen doen is zoiets als

code:
1
BerekenMijnInvoer(Invoer; var Uitvoer)


Waarna je de GUI update met de data die in uitvoer staat. Ik heb in- en uitvoer hier geen type gegeven maar ik gebruik daar meestal een record voor.

www.fendt.com | Nikon D7100 | PS5


  • marcelk
  • Registratie: December 2000
  • Niet online
Gebruik maken van Observer design pattern?
Met
Model = berekende data
View = GUI
Controller = calculations

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:00
marcelk schreef op vrijdag 22 april 2005 @ 13:57:
Gebruik maken van Observer design pattern?
Met
Model = berekende data
View = GUI
Controller = calculations
Als je dat doet met 'events', bekom je juist het zelfde hoor.
In fact: als je het zo doet zoals ik in m'n eerste post zei, dan heb je gewoon het observer pattern, maar dan met events geimplmenteerd.

[ Voor 22% gewijzigd door whoami op 22-04-2005 14:42 ]

https://fgheysels.github.io/


Verwijderd

Topicstarter
Een hoop nieuwe ideeen! Bedankt. Kort resume:

1. Timer.
Is eenvoudig. Moet je alleen wel Application.Processmessages in de code voor berekeningen opnemen (anders wordt het timer-event niet op tijd uitgevoerd).

2. Threads.
De basis van threads lijkt me goed te doen, maar ik weet niet wat ik later tegenkom. Kan ingewikkeld worden, lijkt me. Verder lees ik nog wel eens in de Delphi help: "This routine is not thread safe" :o

3. Berekeningencomponent maken met een OnBerekeningResult
Dit kan, maar in OnBerekeningsResult een GUI functie aanroepen ofzo? Dan staat er alsnog een harde verwijzing in naar de GUI. CallBacks lijken erop, maar dan is die functie een parameter (als ik het goed begrijp...).

4. CallBacks
Lijkt me een oplossing, gebruik ik tot nu niet... Dat wordt het weekend lezen...

5. Model, View, Controller (MVC) pattern
Kom ik veel tegen op internet, maar de praktische invulling heb ik nog niet in de vingers :)

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:00
Verwijderd schreef op vrijdag 22 april 2005 @ 16:15:
Een hoop nieuwe ideeen! Bedankt. Kort resume:


3. Berekeningencomponent maken met een OnBerekeningResult
Dit kan, maar in OnBerekeningsResult een GUI functie aanroepen ofzo? Dan staat er alsnog een harde verwijzing in naar de GUI.
Er staat geen 'harde gui verwijzing' in je component.
In je component zeg je dan alleen 'voer nu dit event uit', en in je GUI heb je een method gekoppeld aan dit event.

Bv:
GUI:
(wel geen delphi-code, maar het idee zal je wel snappen)
code:
1
2
3
4
5
6
7
8
9
...
MyCalculationTask t = new MyCalculationTask();
t.OnBerekeningsResult += new EventHandler (UpdateGUI);
...

void UpdateGUI( object sender , EventArgs e )
{
     // update code voor de gui.
}


Jouw component:
code:
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
class MyCalculationTask
{
     public event EventHandler OnBerekeningResult;

     private void TriggerBerekeningResult()
     {
           if( OnBerekeningResult != null )
           {
                 // blabla, dit moet eigenlijk uitgebreid worden om het 'veilig' te maken
                 OnBerekeningResult (this, EventArgs.Empty);
           }
     }

     public void Calculate()
     {
            TriggerBerekeningResult();
            // Do some long calculation
            
            for( ..... ) 
            {
                TrriggerBerekeningResult();
            }
     }

}

etc...


Nog iets waar je moet op letten: zorg ervoor dat je applicatie niet 'blokkeert' (zorg ervoor dat je app responsive blijft, dat de GUI blijft reageren als je een langdurige operatie uitvoert).
Threads kunnen hier een uitkomst bieden.

[ Voor 15% gewijzigd door whoami op 22-04-2005 16:21 ]

https://fgheysels.github.io/


  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 00:44
Ik wil je nog even doorverwijzen nara een topic dat ik zelf opende met een soortgelijk probleem:
[Delphi] Threads en locken
en dan met name het bericht dat tomatoman schreef op donderdag 24 februari 2005 @ 13:30

Het enige dat de berekening moet weten is de Handle van je form, maar die kan je bij het starten van de thread doorgeven aan de thread. De tekenprocedure zit in je form, de data komt uit de berekening.
Pagina: 1