A part ça, tout est thread qui finit thread, avec de la sueur et une pluie de Delay() dans tous les sens...
Code : Tout sélectionner
EnableExplicit
Structure Thread
*Root
*MessageRequester
*InputRequester
*CreateRequester
Title.S
Message.S
InputString.S
*Command
*Result
CIndex.L
No.L[16]
*Mem[16]
Qty.L
EndStructure
Structure Requester
Command.L
Win.L
MessageGdt.L
InputGdt.L
*Result
OkGdt.L
Event.L
EventGdt.L
EndStructure
Structure Alarm
*Root
*ResetAll
*CheckSyntax
*Ack
*AckAll
*InputDate
*CheckAll
*CloseAll
*AvailableOne
*Set
*Reset
*NewOne
Start.L
ListWin.L
ListGdt.L
AckGdt.L
Menu.L
MenuItem.L
Event.L
EventGdt.L
EventType.L
HourSet.S
StatSet.L
DateSys.L
HmsSys.S
HourSys.L
MinuteSys.L
SecondSys.L
MaxQty.L
Index.L
DateError.L
RequestFlag.L
*Hours
EndStructure
Structure AlarmSet
Ymd.S
Year.L
Month.L
Day.L
Hms.S
Hour.L
Minute.L
Second.L
Stat.L
EndStructure
Structure AlarmTable
Get.AlarmSet[256]
EndStructure
Structure Root
*Requester
*Alarm
ShutDown.L
EndStructure
Procedure ThreadRequester(*C.Thread)
Protected *M.Requester
Protected *ResultString
With *C
*M = AllocateMemory(SizeOf(Requester) )
*C\Mem[\CIndex] = *M
*M\Command = \Command
*M\Result = \Result
*M\Win = OpenWindow(-1, 0, 0, 384, 128, \Title, $CF0001)
*M\MessageGdt = TextGadget(-1, 16, 16, 352, 24, \Message, 1)
If \Command = \InputRequester
*M\InputGdt = StringGadget(-1, 16, 56, 352, 24, "")
*M\OkGdt = ButtonGadget(-1, 96, 96, 192, 24, "Ok")
Else
*M\OkGdt = ButtonGadget(-1, 96, 56, 192, 24, "Ok")
ResizeWindow(*M\Win, #PB_Ignore, #PB_Ignore, 384, 88)
EndIf
Repeat
*M\Event = WaitWindowEvent()
Select *M\Event
Case #PB_Event_Gadget
*M\EventGdt = EventGadget()
Select *M\EventGdt
Case *M\OkGdt
If *M\Command = \InputRequester
\InputString = GetGadgetText(*M\InputGdt)
*ResultString = AllocateMemory(Len(\InputString) + 1)
PokeS(*ResultString, \InputString)
PokeL(\Result, *ResultString) ; /!\ Pointeur 32 bits
EndIf
*M\Event = 16
EndSelect
EndSelect
Until *M\Event = 16
CloseWindow(*M\Win)
FreeMemory(*M)
EndWith
EndProcedure
Procedure ThreadMessageRequester(*C.Thread)
ThreadRequester(*C)
Delay(500)
EndProcedure
Procedure ThreadInputRequester(*C.Thread)
ThreadRequester(*C)
Delay(500)
EndProcedure
Procedure StartRequesterThread(*C.Thread)
Protected Index.L
For Index = 0 To 15
If IsThread(*C\No[Index]) = 0
*C\CIndex = Index
*C\No[Index] = CreateThread(*C\Command, *C)
Break
EndIf
Next Index
Repeat
Delay(50)
Until IsThread(*C\No[Index])
EndProcedure
Procedure RequesterMain(*Root.Root)
Protected Index.L
Protected Thread.Thread
Protected *MyString1
*Root\Requester = Thread
With Thread
\MessageRequester = @ThreadMessageRequester()
\InputRequester = @ThreadInputRequester()
Repeat
Delay(100)
Until *Root\ShutDown
EndWith
EndProcedure
Procedure AlarmResetAll(*C.Alarm)
Protected Index.L
Protected i.L
With *C
*C\RequestFlag = 1
\ListWin = OpenWindow(-1, 0, 0, 256, 384, "Alarmes", $CF0001)
\ListGdt = ListIconGadget(-1, 16, 16, 224, 312, "N°", 32, #PB_ListIcon_FullRowSelect)
\AckGdt = ButtonGadget(-1, 16, 342, 224, 24, "Acquitter toutes les alarmes signalées")
AddGadgetColumn(\ListGdt, 1, "Horaires", 128)
AddGadgetColumn(\ListGdt, 2, "Etat", 64)
For Index = 0 To \MaxQty - 1
AddGadgetItem(\ListGdt, Index, Str(Index) )
Next Index
\Hours = AllocateMemory(SizeOf(AlarmSet) * \MaxQty)
\Menu = CreatePopupMenu(-1)
MenuItem(1, "Activer")
MenuItem(2, "Désactiver")
MenuItem(3, "Acquitter")
MenuBar()
MenuItem(4, "Modifier l'horaire")
MenuBar()
MenuItem(7, "Quitter")
For i = 0 To 500
WindowEvent()
Next
EndWith
EndProcedure
Procedure AlarmSet(*C.Alarm)
Protected Index.L
Protected *AlarmTable.AlarmTable
With *AlarmTable\Get[Index]
SetGadgetItemText(*C\ListGdt, *C\Index, Str(*C\Index), 0)
SetGadgetItemText(*C\ListGdt, *C\Index, *C\HourSet, 1)
*AlarmTable = *C\Hours
Index = *C\Index
\Ymd = Left(*C\HourSet, 8)
\Year = Val(StringField(\Ymd, 3, "/") )
\Month = Val(StringField(\Ymd, 2, "/") )
\Day = Val(StringField(\Ymd, 1, "/") )
\Hms = Right(*C\HourSet, 8)
\Hour = Val(StringField(\Hms, 1, ":") )
\Minute = Val(StringField(\Hms, 2, ":") )
\Second = Val(StringField(\Hms, 3, ":") )
\Stat = *C\StatSet
EndWith
EndProcedure
Procedure AlarmCheckSyntax(*C.Alarm)
Protected Error.L
Protected S.S
Protected i.L
Protected j.L
Protected a.L
Protected *Root.Root
Protected *Req.Thread
*Root = *C\Root
*Req = *Root\Requester
*C\DateError = 1
S = Trim(*C\HourSet)
S = Left(S, 8) + " " + Right(S, 8)
If Len(S) = 17
If Mid(S, 3, 1) = "/"
If Mid(S, 6, 1) = "/"
If Mid(S, 9, 1) = " "
If Mid(S, 12, 1) = ":"
If Mid(S, 15, 1) = ":"
*C\DateError = 0
For i = 1 To 16 Step 3
For j = 0 To 1
a = Asc(Mid(S, i + j, 1) )
If (a < 48) Or (a > 57)
*C\DateError = 1
EndIf
Next j
Next i
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
If *C\DateError
If *C\RequestFlag
*Req\Command = *Req\MessageRequester
*Req\Title = "Erreur"
*Req\Message = "La syntaxe de la date est invalide !"
StartRequesterThread(*Req)
EndIf
*C\HourSet = ""
*C\StatSet = 0
Else
*C\HourSet = S
EndIf
EndProcedure
Procedure AlarmAck(*C.Alarm)
Protected DateSet.L
Protected *AlarmTable.AlarmTable
*AlarmTable = *C\Hours
With *AlarmTable\Get[*C\Index]
*C\HourSet = \Ymd + " " + \Hms
DateSet = ParseDate("%dd/%mm/%yy %hh:%ii:%ss", *C\HourSet)
DateSet + 86400
*C\HourSet = FormatDate("%dd/%mm/%yy %hh:%ii:%ss", DateSet)
EndWith
*C\StatSet = 1
AlarmSet(*C)
EndProcedure
Procedure AlarmAckAll(*C.Alarm)
Protected Index.L
Protected DateSet.L
Protected *AlarmTable.AlarmTable
With *C
*AlarmTable = \Hours
For Index = 0 To \MaxQty - 1
If *AlarmTable\Get[Index]\Stat = 2
EndWith
With *AlarmTable\Get[Index]
*C\HourSet = \Ymd + " " + \Hms
DateSet = ParseDate("%dd/%mm/%yy %hh:%ii:%ss", *C\HourSet)
DateSet + 86400
*C\HourSet = FormatDate("%dd/%mm/%yy %hh:%ii:%ss", DateSet)
EndWith
With *C
\Index = Index
\StatSet = 1
AlarmSet(*C)
EndIf
Next Index
EndWith
EndProcedure
Procedure AlarmInputDate(*C.Alarm)
Protected *Root.Root
Protected *Req.Thread
*Root = *C\Root
*Req = *Root\Requester
Protected MyString1.L
Protected *AlarmTable.AlarmTable
With *AlarmTable\Get[*C\Index]
*Req\Command = *Req\InputRequester
*Req\Title = "Modifier l'horaire"
*Req\Message = "Respectez la syntaxe JJ/MM/AA HH:MM:SS"
*Req\Result = @MyString1
StartRequesterThread(*Req)
Repeat
Delay(500)
Until MyString1 <> 0
*C\HourSet = PeekS(MyString1)
FreeMemory(MyString1)
AlarmCheckSyntax(*C)
AlarmSet(*C)
EndWith
EndProcedure
Procedure AlarmCheckAll(*C.Alarm)
Protected *AlarmTable.AlarmTable
Protected Index.L
Protected Field.S
Protected AlarmValue.L
Protected i.L
Protected *Root.Root
Protected *Req.Thread
*Root = *C\Root
*Req = *Root\Requester
*AlarmTable = *C\Hours
Delay(500)
Repeat
With *C
\DateSys = Date()
\HourSys = Hour(\DateSys)
\MinuteSys = Minute(\DateSys)
\SecondSys = Second(\DateSys)
\HmsSys = RSet(Str(\HourSys ), 2, "0") + ":"
\HmsSys + RSet(Str(\MinuteSys), 2, "0") + ":"
\HmsSys + RSet(Str(\SecondSys), 2, "0")
SetWindowTitle(\ListWin, \HmsSys)
EndWith
For Index = 0 To *C\MaxQty - 1
With *AlarmTable\Get[Index]
Select \Stat
Case 1
Field = "Active"
If *C\Start = 0
AlarmValue = ParseDate("%dd/%mm/%yy %hh:%ii:%ss", \Ymd + " " + \Hms)
If AlarmValue <= *C\DateSys
\Stat = 2
*Req\Command = *Req\MessageRequester
*Req\Title = "Avertissement"
*Req\Message = "Alarme n°" + Str(Index) + " !"
StartRequesterThread(*Req)
*C\Start = 1
EndIf
EndIf
Case 0
Field = "Inactive"
Case 2
Field = "Signalée"
EndSelect
SetGadgetItemText(*C\ListGdt, Index, Field, 2)
EndWith
Next Index
*C\Start = 0
Delay(25)
*C\Event = WindowEvent()
If *C\Event = #PB_Event_Gadget
*C\EventGdt = EventGadget()
*C\EventType = EventType()
Select *C\EventGdt
Case *C\AckGdt
AlarmAckAll(*C)
Case *C\ListGdt
If *C\EventType = #PB_EventType_RightClick
*C\Index = GetGadgetState(*C\ListGdt)
If *C\Index <> -1
With *AlarmTable\Get[*C\Index]
For i = 1 To 3
DisableMenuItem(*C\Menu, i, 1)
DisableMenuItem(*C\Menu, i + 3, 1)
Next i
DisableMenuItem(*C\Menu, 4, 0)
If \Stat = 0
*C\HourSet = \Ymd + " " + \Hms
*C\RequestFlag = 0
AlarmCheckSyntax(*C)
*C\RequestFlag = 1
If *C\DateError = 0
DisableMenuItem(*C\Menu, 1, 0)
EndIf
EndIf
If \Stat = 1
DisableMenuItem(*C\Menu, 2, 0)
EndIf
If \Stat = 2
DisableMenuItem(*C\Menu, 3, 0)
EndIf
EndWith
DisplayPopupMenu(*C\Menu, WindowID(*C\ListWin) )
EndIf
EndIf
EndSelect
EndIf
If *C\Event = #PB_Event_Menu
*C\MenuItem = EventMenu()
With *AlarmTable\Get[*C\Index]
Select *C\MenuItem
Case 1
\Stat = 1
Case 2
\Stat = 0
Case 3
AlarmAck(*C)
Case 4
AlarmInputDate(*C)
Case 7
*C\Event = 16
EndSelect
EndWith
EndIf
Until *C\Event = 16
EndProcedure
Procedure AlarmCloseAll(*C.Alarm)
With *C
CloseWindow(\ListWin)
FreeMemory(\Hours)
EndWith
EndProcedure
Procedure AlarmAvailableOne(*C.Alarm)
Protected Index.L
Protected *AlarmTable.AlarmTable
With *C
*AlarmTable = \Hours
For Index = 0 To \MaxQty - 1
If *AlarmTable\Get[Index]\Hms = ""
\Index = Index
Break
EndIf
Next Index
EndWith
EndProcedure
Procedure AlarmReset(*C.Alarm)
Protected Index.L
Protected *AlarmTable.AlarmTable
With *AlarmTable
*AlarmTable = *C\Hours
Index = *C\Index
\Get[Index]\Stat = 0
EndWith
EndProcedure
Procedure AlarmNewOne(*C.Alarm)
With *C
AlarmAvailableOne(*C)
AlarmSet(*C)
EndWith
EndProcedure
Procedure AlarmMain(*Root.Root)
Protected Alarm.Alarm
Alarm\Root = *Root
*Root\Alarm = Alarm
Alarm\ResetAll = @AlarmResetAll()
Alarm\Set = @AlarmSet()
Alarm\CheckSyntax = @AlarmCheckSyntax()
Alarm\Ack = @AlarmAck()
Alarm\AckAll = @AlarmAckAll()
Alarm\InputDate = @AlarmInputDate()
Alarm\CheckAll = @AlarmCheckAll()
Alarm\CloseAll = @AlarmCloseAll()
Alarm\AvailableOne = @AlarmAvailableOne()
Alarm\Reset = @AlarmReset()
Alarm\NewOne = @AlarmNewOne()
; Initialisation
Alarm\MaxQty = 16 ; Nombre max d'alarmes
AlarmResetAll(Alarm)
; On rentre une première alarme inactive
Alarm\HourSet = "21/02/09 21:02:00"
Alarm\StatSet = 0
AlarmNewOne(Alarm)
; On rentre une seconde alarme active
Alarm\StatSet = 1
Alarm\HourSet = "21/02/09 20:03:00"
AlarmNewOne(Alarm)
; On rentre une seconde alarme signalée
Alarm\StatSet = 2
Alarm\HourSet = "21/02/09 20:40:00"
AlarmNewOne(Alarm)
; On rentre une seconde alarme signalée
Alarm\StatSet = 1
Alarm\HourSet = "20/02/09 23:20:00"
AlarmNewOne(Alarm)
Alarm\Start = 1
AlarmCheckAll(Alarm)
AlarmCloseAll(Alarm)
*Root\ShutDown = 1
EndProcedure
Define Root.Root
CreateThread(@RequesterMain(), Root)
WaitThread(CreateThread(@AlarmMain(), Root) )