Κυριακή 13 Μαρτίου 2016

Τρία Μικρά Νήματα για Τρία Παράθυρα σε Μ2000 (αλλαγή)

Για μερικές αναθεωρήσεις από 199 και μέχρι 204 είχε Bug το οποίο διοθρώθηκε.

Στο παράδειγμα με τα πολλά παράθυρα μπορούμε να βάλουμε τρία νήματα, που το παράγουμε σε επανάληψη. Κάθε φορά που παράγουμε ένα νήμα, αποδίδεται αριθμός, και αντιγράφεται ο κώδικας σε ένα αντικείμενο τύπου thread. Τέτοιου τύπου είναι το Task,Main (που μπορεί να υπάρχει ένα στο τμήμα) και όσα After θέλουμε (που είναι νήματα μιας φοράς εκτέλεσης). Κάθε φορά που δημιουργούμε ένα νήμα, εγγράφεται στο αντικείμενο εκτέλεσης το αντικείμενο εξόδου, ως αναφορά.
Άρα στην ουσία έχουμε επιπλέον μια αναφορά στο κάθε παράθυρο. Το παράθυρο είναι αντικείμενο με αριθμημένες αναφορές (μια κρατάει το σύστημα για να το κάνει unload). Μόλις τερματίσει η Task.Main, καθαρίζει τα νήματα, άρα καθαρίζουν τα αντικείμενα εκτέλεσης και αφαιρούνται οι αναφορές!

Τα τρία παράθυρα "ζωγραφίζονται" από τρία νήματα. Έχω αφήσει μια εντολή σε Rem, και μετά την πρώτη άνω κάτω τελεία μπορούμε να πατήσουμε το enter και να πάμε τις εντολές σε νέα γραμμή, και εδώ έχουμε μια που καλεί μια ρουτίνα. Σιγά σιγά η Τύπωσε στα παράθυρα θα φτάσει στο τέρμα και θα αρχίσουν να κυλάνε προς τα πάνω! Τα παράθυρα δουλεύουν όπως η κονσόλα αλλά δεν  κάνουν εισαγωγή και ότι σχετικό όπως διόρθωση κειμένου. Αυτά γίνονται με στοιχεία ελέγχου, όπως TextBox.


Σε ένα πλήκτρο ανοίγει η φόρμα ελέγχου και ειδικά στις τελευταίες εκδόσεις έχει γίνει μια ωραία αλλαγή, μπορούμε να παρακολουθούμε και τα νήματα (και με βηματική εκτέλεση να τα εκτελούμε και αυτά). Η φόρμα ελέγχουν εμφανίζει αντί για Τμήμα και Όνομα, ή Συνάρτηση και Όνομα, το Νήμα(αριθμός νήματος) και Όνομα Τμήματος/Συνάρτησης όπου το νήμα τρέχει.

Δείτε ακόμα πως μέσα στη κλάση Buttons μετέφερα ένα τμήμα και μια συνάρτηση, και όταν χρησιμοποιώ τον πίνακα Controls() μπορώ να γράψω ή να διαβάσω το Caption (το κείμενο του πλήκτρου),  χωρίς να με ενδιαφέρει τι κάνει από μέσα το αντικείμενο..
Η συνάρτηση αυτή: Controls(L).ReadCaption$(K)  θα μου δώσει στη L φόρμα το Caption του K Button. Για να το αλλάξω δεν χρησιμοποιώ την αντικατάσταση αλλά την κλήση μεθόδου (το τμήμα στην κλάση παίζει τον ρόλο της μεθόδου). Και βλέπουμε στο κώδικα εκεί που ορίζω αυτό: Controls(1).SetCaption 1, "Click Me"







ΑΛΛΑΓΗ: Method Form1(K), "Control", 1 As UserControl
Ο τίτλος μπήκε στο 1. Στο 0 είναι ένα μικρό στοιχείο που χρησιμοποιείται για την αλλαγή μεγέθους και το οποίο πάντα βρίσκεται μπροστά από τα άλλα στοιχεία.


ΠΡΟΣΘΗΚΗ WAIT 0 για να δίνουμε χρόνο στο σύστημα να μπορούμε να κινήσουμε τα παράθυρα. Αυτό έγινε γιατί άλλαξε η Task.Main το πώς διαχειρίζεται το χρόνο. Μπορούμε εναλλακτικά να βάλουμε την Refrsesh με η χωρίς παράμετρο (τα millisecond που αυτόματα γίνεται η επόμενη ανανέωση).

Στο παράδειγμα υπάρχει πλήκτο σε φόρμα που ανοίγει την φόρμα διαλόγου και σταματάει την εκτέλεση (παρόλο που δουλεύουν νήματα και γεγονότα). Μπορούμε να εκτελούμε μια προς μια τις εντολές των νημάτων (τα γεγονότα εκτελούνται χωρίς να σταματήσουν,).





Cls,0
\\ using ,0 we switch console to minimize state
\\ any value else or no value restore to normal state
\\Title "Start Up", 0
N=3
\\ we choose to use automatic event object
\\ this event object expect to find Form1() function
\\ using automatic object we can't disable it
\\ also events which expect changes to variables
\\ bypass the stantard callback and resolve to a function
\\ like  Form1.Unload() which get back the Nook value


Declare Form1(N) Form
Class Buttons {
      Dim Butt()
      Module SetCaption { With .Butt(Number), "Caption",Letter$}
      Function ReadCaption$ { With .Butt(Number), "Caption" as Result$ : = Result$}
}
Dim Controls(N)=Buttons() \\ an array of arrays
\\
For i=0 to N-1 {
      For Controls(i) {
            \\ need to be a new name for array
            \\ a For object { } delete any new name
            \\ so each time this block run, starts with no Button1() array
            \\ then make one, then we get a copy (and references to actual objects)
            \\ and then Button1() erased
            \\ but Controls(i).Butt() can't erased because exist before we enter the loop
            Declare Button1(2) button Form Form1(i)
            For j=0 To 1 {
                  Method Button1(j), "move", 1000+4000*j, 2000,3000,1000
            }
            .Butt()=Button1()
      }
     Layer Form1(i) {
            Gradient 1,4
            Cursor 0,2
            Report 2, "Hello There"
     }
      Method Form1(i), "Show"
}
\\ check this. After 6 second we can unload two forms
\\ Ttry to close anything. You can without a problem
\\ and after 3 seconds one more
\\ just press enter after Rem 1: to make lines ready for execution
Rem 1: Wait 6000 : PrintAndRefresh("CloseNow") : For i=1 to 2 : Method Form1(i), "CloseNow" : Next i
Rem 2: Wait 3000 : PrintAndRefresh("Unload") : Refresh : Declare Form1() Nothing
Rem 3: Show \\ get the focus back
Rem 4: Print "ok" : Exit


Form1_1=true
Controls(1).SetCaption 0, "Click Me"
Controls(1).SetCaption 1, "ok"
Controls(2).SetCaption 1, "Test Me"
\\ we make a variable bound to a property
With form1(0), "Visible" As visible


CloseThisForm=0
Function CloseAfter {
      If Ask("Close Form?")=1 Then {
      If CloseThisForm=1 Then Form1_1=false
      Method Form1(CloseThisForm), "CloseNow"
      }
}
Function Form1.Unload {
      Read New index, &Nook
      Nook=True \\ no unload now
      \\ After make an unamed thread
      \\ we use this of async waiting for user to
      \\ provide feedback from a message box
      CloseThisForm=Index
      After 50 { Call Local CloseAfter() }
}
Function Button1.Click {
      Read K, L
      Print "Form:";L,"Button:";K
      Print Controls(L).ReadCaption$(K)
      if k=1 and l=2 then test
}
Function Form1.MouseMove {
      Read K, Button, Shft, X, Y
      If Button=1 Then {
           Layer Form1(K) {
                  move X, Y
                  circle 500, 1, 14-K
            }
      }
}
Function Form1.MouseDown {
      Read K, Button, Shft, X, Y
      If Button=2 Then {
            Method Form1(K), "Control", 1 As UserControl
            \\ we have to use new names if we "call local" a function
            With UserControl, "Visible" As uVisible
            uVisible=Not uVisible \\ we can't use X~ as X = Not X     
      }
}
Function Form1 {
     Read FormMsg$
     \\ we "call local" a function. Some parameters are in string, some other in stack
     \\ when we call that parammeters in string are at the top of stack for values.
     \\ m2000 has stack for values, stack for return from routines, and system stack for
     \\ calling execution objects. Functions and Modules and Threads are execution objects
     \\ also an event is an execution object.
     \\ When we use Call, or when we call a module by name only, we pass Stack for values
     \\ from the caller. Form1() calling with a new Stack for Values
     \\ so any value in stack after Form1() ends are lost with the stack, end the execution object.
     \\ the right event signature is Msg$, &Obj. Obj is a reference to form1 and this erased at the end
     \\ because here we don't use it
     Try { Call Local FormMsg$ }
}
For i=0 to N-1 {
\\ Threads get current layer as starting layer
      Layer Form1(i) {
            \\ so we make the thread inside Form Layer
            Thread {
                  If Form1_1 Then {
                            \\ third parameter is for color, we can use Color(r,g,b) or Colour(r,g,b)
                            \\ for rgb value, or we can give an Html number like #FF0000
                            \\ another way is by using hex 0X80000012 for system colors
                            \\ Here we use values from the range 0 to 15 (here from 7 to 15)
                            \\ and these are the standard colors.
                           Draw To Random(Scale.x), Random(Scale.y), Random(7,15)
                           \\ sub PrintAndRefresh can be run because all threads are in the same module
                           \\ Threads have their execution object and an object to draw, here the form1
                           \\ When thread call sub, sub run on same execution object.
                           \\ modules and functions have own execution object
                           \\ so subs are light and interest because the see every variable as local
                           \\ but we can make temporary anything
                           \\ we can also create threads in a sub, without erase them.
                           \\ Threads erased when parent object erased, or when we send erase command
                           \\ or when we exit Task.Main
                           \\ for the situation of a thread created on a thread we can use Threads Erase
                           \\ too remove all, including these. This we need it because, the second level of thread may
                           \\ end after the erasing of module, where we create it, so can run code with variables which
                           \\ are cleared. So With Threads Erase before exit module we are sure that Threading Pool is empty.
                           \\ But this in not an every day situation.
                           \\  (an after {}  thread creation in a thread execution is an example for a second level thread)
                           Rem 100 :If random(100)<4 then PrintAndRefresh("draw lines")
                  } Else Thread This Erase
            } As OneMore Interval 100
            \\ OneMore is a handler, so we lost first and second handler
            \\ but we dont care, we close thread inside using This
            \\ or we can let the Main Task erase it at the exit
      }
}
Thread {
      PrintAndRefresh(Str$(Now,"hh:mm:ss"))
} As Inform Interval 1000
\\ Inform is the Thread Handler, we don't use it here


\\ Need a thread to run a Main.Task
Main.Task 100 {
      \\ using property  \\
      Rem 1 : Print Type$(Visible), Type$(Form1_1)
      If Not visible Then Exit
      WAIT 0
}


\\  Cleaning;
\\ A control has two objects, one in form (a UserControl, one type for all),
\\ and the other is the wrapper, which serve as an event publisher,
\\ and we can use propertiers and methods
\\ When a Form unloaded not only erase UserControls but becaue hold referencse to wrappers
\\ send deconstruct command to each one, to break any reference to form
\\ and  erase internal collection - just throw references to actual objects
\\ So our last references to wrappers are in Controls(i)
\\ We can let M2000 to destroy the arrays, so the referecses, or we can do the job
\\ and we can reuse it
\\ so we check this with a jump to there
Goto there
For i=0 to N-1 {
      For Controls(i) {
            Dim .Butt()
      }
}
there:
\\ this command unload forms
Declare Form1() Nothing
Title "End"
Show
Sub PrintAndRefresh(A$)
      Print A$
      Refresh
End Sub


Εδώ με Ν=30, δηλαδή 30 παράθυρα όλα μαζί, με 30 νήματα να ζωγραφίζουν και εμείς ζωγραφίζουμε επίσης σε όποιο θέλουμε, παρέα..με τη Μ2000!


Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου

You can feel free to write any suggestion, or idea on the subject.