PureBasic - GUI Yanıt Vermiyor
Resimde, pencerenin başlık bölümünde (Yanıt Vermiyor) yazdığını fark etmemiş olabilirsiniz. Aşağıda yanlış kodlanmış bir program örneği göreceksiniz. Bu programı, çalıştırıp, Check me kutucuğuna tıklarsanız veya pencereyi başlık kısmından tutup sürüklerseniz (taşırsanız) herhangi bir sorun olmayacaktır. Start butonuna tıkladıktan sonra bir şey yapmadan beklerseniz yine bir sorun olmayacaktır.
Amma velakin, Start butonuna tıkladıktan sonra aynı işlemleri yapmayı denerseniz, yapamadığınızı görürsünüz. Program size tepki veremeyecek ve çakılacaktır. Program, 20 saniye sonra loop (döngü) bittiğinde normale dönecektir. Start butonuna tıklayınca program Test_LongLoop() prosedürüne gider. Orada zaman alan bir For-Next döngüsüne girer. Bu esnada pencerede veya formda oluşan olaylarla ilgilenemez ve çakılır. Formda oluşan, butona tıklama veya pencereyi taşıma olayları'nı ihmal etmemek gerekiyor. Program yazarken sürekli olarak, oluşan olayları tüketmemiz gerekiyor. Tüketmez, ihmal edersek, form donuyor.
Yanlış kodlanmış program örneği
Enumeration Gadget
#GADGET_btnStart
#GADGET_btnStop
#GADGET_chkTest
#GADGET_txtLoopOutput
#GADGET_lbTrace
EndEnumeration
#WINDOW_Main = 0
#WINDOW_Main_Flags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
#LOOP_MaxLoops = 200
#LOOP_SlowDownDelay = 100
Global ApplicationQuit = #False
Global LoopRunningState = #False ; init --> not running
Macro Trace(MessageText)
AddGadgetItem(#GADGET_lbTrace, -1, MessageText)
SetGadgetState(#GADGET_lbTrace, CountGadgetItems(#GADGET_lbTrace) -1)
EndMacro
OpenWindow(#WINDOW_Main, 0, 0, 400, 320, "Event handling example...", #WINDOW_Main_Flags)
StickyWindow(#WINDOW_Main, 1) ; show test app always above the PB_IDE
ButtonGadget(#GADGET_btnStart, 8, 4, 192, 32, "Start Looping")
ButtonGadget(#GADGET_btnStop, 200, 4, 192, 32, "Stop Looping")
CheckBoxGadget(#GADGET_chkTest, 8, 40, 384, 24, "Check me -- (see the event handling while the loop is running)")
TextGadget(#GADGET_txtLoopOutput, 8, 72, 384, 20, "Loop is stopped.")
SetGadgetColor(#GADGET_txtLoopOutput, #PB_Gadget_BackColor, RGB(0,200,0))
ListViewGadget(#GADGET_lbTrace, 8, 104, 384, 208, $4000) ; #LBS_NOSEL == 0x4000
Procedure Test_LongLoop()
Protected index, msg$
For index = 0 To #LOOP_MaxLoops
Delay(#LOOP_SlowDownDelay) ; spend some time with nothing
msg$ = " Item " + Str(index) + "/" + Str(#LOOP_MaxLoops) + " | Checkbox.State == " + GetGadgetState(#GADGET_chkTest)
SetGadgetText(#GADGET_txtLoopOutput, msg$)
If Not LoopRunningState
Trace("LoopRunningState == FALSE ")
Break
EndIf
Next index
If index >= #LOOP_MaxLoops
SetGadgetText(#GADGET_txtLoopOutput, "Loop finished.")
Trace("Loop finished (reached MaxLoops == " + index + ")")
EndIf
LoopRunningState = #False
EndProcedure
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_MoveWindow
Trace(" New Window Pos == " + WindowX(#WINDOW_Main) + ", " +WindowY(#WINDOW_Main))
Case #PB_Event_CloseWindow
ApplicationQuit = #True
Case #PB_Event_Gadget
Select EventGadget()
Case #GADGET_btnStart
LoopRunningState = #True
ClearGadgetItems(#GADGET_lbTrace)
SetGadgetText(#GADGET_txtLoopOutput, "Loop is running")
Test_LongLoop()
Case #GADGET_btnStop
SetGadgetText(#GADGET_txtLoopOutput, "Loop stopped.")
LoopRunningState = #False
Case #GADGET_chkTest
Trace("Gadget = #GADGET_chkTest == " + GetGadgetState(#GADGET_chkTest))
EndSelect
EndSelect
Until ApplicationQuit
End
Burada Macro-EndMacro bloğu kullanılmış. Kullanımı prosedüre benziyor ama prosedür değil. Derleme esnasında Trace(..) yazan yerlerde, macro bloğunun içindeki satırları kopyala yapıştır yapıyor.Çözüm yolu
Enumeration Gadget
#GADGET_btnStart
#GADGET_btnStop
#GADGET_chkTest
#GADGET_txtLoopOutput
#GADGET_lbTrace
EndEnumeration
#WINDOW_Main = 0
#WINDOW_Main_Flags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
#LOOP_MaxLoops = 200
#LOOP_SlowDownDelay = 100
Global ApplicationQuit = #False
Global LoopRunningState = #False ; init --> not running
Declare EventHandler()
Declare Test_LongLoop()
Macro Trace(MessageText)
AddGadgetItem(#GADGET_lbTrace, -1, MessageText)
SetGadgetState(#GADGET_lbTrace, CountGadgetItems(#GADGET_lbTrace) -1)
EndMacro
OpenWindow(#WINDOW_Main, 0, 0, 400, 320, "Event handling example...", #WINDOW_Main_Flags)
StickyWindow(#WINDOW_Main, 1) ; show test app always above the PB_IDE
ButtonGadget(#GADGET_btnStart, 8, 4, 192, 32, "Start Looping")
ButtonGadget(#GADGET_btnStop, 200, 4, 192, 32, "Stop Looping")
CheckBoxGadget(#GADGET_chkTest, 8, 40, 384, 24, "Check me -- (see the event handling while the loop is running)")
TextGadget(#GADGET_txtLoopOutput, 8, 72, 384, 20, "Loop is stopped.")
SetGadgetColor(#GADGET_txtLoopOutput, #PB_Gadget_BackColor, RGB(0,200,0))
ListViewGadget(#GADGET_lbTrace, 8, 104, 384, 208, $4000) ; #LBS_NOSEL == 0x4000
BindEvent(#PB_Event_MoveWindow, @EventHandler(), #WINDOW_Main)
BindEvent(#PB_Event_CloseWindow, @EventHandler(), #WINDOW_Main)
BindGadgetEvent(#GADGET_btnStart, @EventHandler())
BindGadgetEvent(#GADGET_btnStop, @EventHandler())
BindGadgetEvent(#GADGET_chkTest, @EventHandler())
Procedure EventHandler()
Select Event()
Case #PB_Event_MoveWindow
Trace(" New Window Pos == " + WindowX(#WINDOW_Main) + ", " +WindowY(#WINDOW_Main))
Case #PB_Event_CloseWindow
ApplicationQuit = #True
End
Case #PB_Event_Gadget
Select EventGadget()
Case #GADGET_btnStart
LoopRunningState = #True
ClearGadgetItems(#GADGET_lbTrace)
SetGadgetText(#GADGET_txtLoopOutput, "Loop is running")
Case #GADGET_btnStop
SetGadgetText(#GADGET_txtLoopOutput, "Loop stopped.")
LoopRunningState = #False
Case #GADGET_chkTest
Trace("Gadget = #GADGET_chkTest == " + GetGadgetState(#GADGET_chkTest))
EndSelect
EndSelect
EndProcedure
Procedure Test_LongLoop()
Protected index, msg$
For index = 0 To #LOOP_MaxLoops
Delay(#LOOP_SlowDownDelay) ; spend some time with nothing
msg$ = " Item " + Str(index) + "/" + Str(#LOOP_MaxLoops) + " | Checkbox.State == " + GetGadgetState(#GADGET_chkTest)
SetGadgetText(#GADGET_txtLoopOutput, msg$)
While WindowEvent(): Wend
If Not LoopRunningState
Trace("LoopRunningState == FALSE ")
Break
EndIf
Next index
If index >= #LOOP_MaxLoops
SetGadgetText(#GADGET_txtLoopOutput, "Loop finished.")
Trace("Loop finished (reached MaxLoops == " + index + ")")
EndIf
LoopRunningState = #False
EndProcedure
Repeat
WaitWindowEvent(10)
If LoopRunningState = #True
If first = #False
Test_LongLoop() ; <-- cannot called by EventHandler()
first = #True
EndIf
Else
first = #False
EndIf
Until ApplicationQuit
End
Burada Test_LongLoop (uzun döngü) prosedürü içinde olayları tüketmek için While WindowEvent(): Wend satırını kullandık. Yine aynı amaçla, Repeat-Until döngüsünde de WaitWindowEvent(10) komutunu kullandık. EventHandler() prosedürünün ilk satırında yazan Event(), PB'nin kendi prosedürü veya fonksiyonudur. Bir başka çözüm yolu
Enumeration Gadget
#GADGET_btnStart
#GADGET_btnStop
#GADGET_chkTest
#GADGET_txtLoopOutput
#GADGET_lbTrace
EndEnumeration
#WINDOW_Main = 0
#WINDOW_Main_Flags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
#LOOP_MaxLoops = 200
#LOOP_SlowDownDelay = 100
Global ApplicationQuit = #False
Global LoopRunningState = #False ; init --> not running
Declare EventHandler()
Declare Test_LongLoop()
Macro Trace(MessageText)
AddGadgetItem(#GADGET_lbTrace, -1, MessageText)
SetGadgetState(#GADGET_lbTrace, CountGadgetItems(#GADGET_lbTrace) -1)
EndMacro
OpenWindow(#WINDOW_Main, 0, 0, 400, 320, "Event handling example...", #WINDOW_Main_Flags)
StickyWindow(#WINDOW_Main, 1) ; show test app always above the PB_IDE
ButtonGadget(#GADGET_btnStart, 8, 4, 192, 32, "Start Looping")
ButtonGadget(#GADGET_btnStop, 200, 4, 192, 32, "Stop Looping")
CheckBoxGadget(#GADGET_chkTest, 8, 40, 384, 24, "Check me -- (see the event handling while the loop is running)")
TextGadget(#GADGET_txtLoopOutput, 8, 72, 384, 20, "Loop is stopped.")
SetGadgetColor(#GADGET_txtLoopOutput, #PB_Gadget_BackColor, RGB(0,200,0))
ListViewGadget(#GADGET_lbTrace, 8, 104, 384, 208, $4000) ; #LBS_NOSEL == 0x4000
Procedure EventHandler()
Select Event()
Case #PB_Event_MoveWindow
Trace(" New Window Pos == " + WindowX(#WINDOW_Main) + ", " +WindowY(#WINDOW_Main))
Case #PB_Event_CloseWindow
ApplicationQuit = #True
End
Case #PB_Event_Gadget
Select EventGadget()
Case #GADGET_btnStart
LoopRunningState = #True
ClearGadgetItems(#GADGET_lbTrace)
SetGadgetText(#GADGET_txtLoopOutput, "Loop is running")
Test_LongLoop()
Case #GADGET_btnStop
SetGadgetText(#GADGET_txtLoopOutput, "Loop stopped.")
LoopRunningState = #False
Case #GADGET_chkTest
Trace("Gadget = #GADGET_chkTest == " + GetGadgetState(#GADGET_chkTest))
EndSelect
EndSelect
EndProcedure
Procedure Test_LongLoop()
Protected index, msg$
For index = 0 To #LOOP_MaxLoops
Delay(#LOOP_SlowDownDelay) ; spend some time with nothing
msg$ = " Item " + Str(index) + "/" + Str(#LOOP_MaxLoops) + " | Checkbox.State == " + GetGadgetState(#GADGET_chkTest)
SetGadgetText(#GADGET_txtLoopOutput, msg$)
While WindowEvent() : EventHandler() : Wend
If Not LoopRunningState
Trace("LoopRunningState == FALSE ")
Break
EndIf
Next index
If index >= #LOOP_MaxLoops
SetGadgetText(#GADGET_txtLoopOutput, "Loop finished.")
Trace("Loop finished (reached MaxLoops == " + index + ")")
EndIf
LoopRunningState = #False
EndProcedure
Repeat
WaitWindowEvent(10)
EventHandler()
Until ApplicationQuit
End
Thread ile çözüm
EnableExplicit
CompilerIf Not #PB_Compiler_Thread
CompilerError "Enable thread safe in compiler options!"
CompilerEndIf
#WINDOW_Main = 0
#WINDOW_Main_Flags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
#LOOP_MaxLoops = 200
#LOOP_SlowDownDelay = 100
Enumeration Gadget
#GADGET_btnStart
#GADGET_btnStop
#GADGET_chkTest
#GADGET_txtLoopOutput
#GADGET_lbTrace
EndEnumeration
Enumeration OwnEvent #PB_Event_FirstCustomValue
#OwnEvent_ThreadStarted
#OwnEvent_SetGadgetText
#OwnEvent_ThreadFinished
EndEnumeration
Structure Parameter_Structure
Thread.i
Exit.i
EndStructure
Macro Trace(MessageText)
AddGadgetItem(#GADGET_lbTrace, -1, MessageText)
SetGadgetState(#GADGET_lbTrace, CountGadgetItems(#GADGET_lbTrace) -1)
EndMacro
Procedure Test_LongLoop(*Parameter.Parameter_Structure)
Protected index.i, *msg
PostEvent(#OwnEvent_ThreadStarted)
For index = 0 To #LOOP_MaxLoops
If *Parameter\Exit
Break
EndIf
Delay(#LOOP_SlowDownDelay) ; spend some time with nothing
*msg = UTF8(" Item " + Str(index) + "/" + Str(#LOOP_MaxLoops) + " | Checkbox.State == " + GetGadgetState(#GADGET_chkTest))
PostEvent(#OwnEvent_SetGadgetText, #WINDOW_Main, #GADGET_txtLoopOutput, 0, *msg)
Next index
*msg = UTF8("Loop finished (reached MaxLoops == " + Str(index) + ")")
PostEvent(#OwnEvent_ThreadFinished, #WINDOW_Main, #GADGET_lbTrace, 0, *msg)
EndProcedure
Define.i Event, ApplicationQuit, Exit
Define *msg
Define Parameter.Parameter_Structure
OpenWindow(#WINDOW_Main, 0, 0, 400, 320, "Event handling example...", #WINDOW_Main_Flags)
StickyWindow(#WINDOW_Main, 1) ; show test app always above the PB_IDE
ButtonGadget(#GADGET_btnStart, 8, 4, 192, 32, "Start Looping")
ButtonGadget(#GADGET_btnStop, 200, 4, 192, 32, "Stop Looping")
DisableGadget(#GADGET_btnStop, #True)
CheckBoxGadget(#GADGET_chkTest, 8, 40, 384, 24, "Check me -- (see the event handling while the loop is running)")
TextGadget(#GADGET_txtLoopOutput, 8, 72, 384, 20, "Loop is stopped.")
SetGadgetColor(#GADGET_txtLoopOutput, #PB_Gadget_BackColor, RGB(0,200,0))
ListViewGadget(#GADGET_lbTrace, 8, 104, 384, 208, $4000) ; #LBS_NOSEL == 0x4000
Repeat
Event = WaitWindowEvent()
Select Event
Case #OwnEvent_ThreadStarted
DisableGadget(#GADGET_btnStart, #True)
DisableGadget(#GADGET_btnStop, #False)
SetGadgetText(#GADGET_txtLoopOutput, "Loop is running")
Case #OwnEvent_SetGadgetText
*msg = EventData()
SetGadgetText(EventGadget(), PeekS(*msg, -1, #PB_UTF8))
FreeMemory(*msg)
Case #OwnEvent_ThreadFinished
DisableGadget(#GADGET_btnStart, #False)
DisableGadget(#GADGET_btnStop, #True)
*msg = EventData()
If *msg
Trace(PeekS(*msg, -1, #PB_UTF8))
FreeMemory(*msg)
EndIf
SetGadgetText(#GADGET_txtLoopOutput, "Loop stopped.")
If ApplicationQuit
Exit = #True
EndIf
Case #PB_Event_MoveWindow
Trace(" New Window Pos == " + WindowX(#WINDOW_Main) + ", " +WindowY(#WINDOW_Main))
Case #PB_Event_CloseWindow
ApplicationQuit = #True
If IsThread(Parameter\Thread)
Parameter\Exit = #True
Else
PostEvent(#OwnEvent_ThreadFinished)
EndIf
Case #PB_Event_Gadget
Select EventGadget()
Case #GADGET_btnStart
ClearGadgetItems(#GADGET_lbTrace)
Parameter\Exit = #False
Parameter\Thread = CreateThread(@Test_LongLoop(), @Parameter)
Case #GADGET_btnStop
If IsThread(Parameter\Thread)
Parameter\Exit = #True
EndIf
Case #GADGET_chkTest
Trace("Gadget = #GADGET_chkTest == " + GetGadgetState(#GADGET_chkTest))
EndSelect
EndSelect
Until Exit
Yorumlar
Yorum Gönder