How to break while-loop in VFP (FoxPro) by button click? - loops

I'm trying to make simple FoxPro application with two buttons. First button starts while-loop and works correctly. Second button must break this loop. But I can't find any correctly working solution.
There are loop code:
DO WHILE !thisForm.cancelpressed
IF thisForm.cancelpressed
EXIT
ENDIF
randNum=VAL(TRIM(STR(ROUND( 3*RAND(), 1))))
&&oneVar=VAL("1")
IF randNum = VAL("1")
ThisForm.shape1.BackColor = greenColor
ThisForm.shape2.BackColor = orangeColor
ThisForm.shape3.BackColor = redColor
ENDIF
cs = seconds()
IF abs(cs - seconds()) >= 15
doevents
cs = seconds()
ENDIF
IF thisForm.cancelpressed
EXIT
ENDIF
DOEVENTS
WAIT TIMEOUT 1
ENDDO
This code is in the first button Click method. Form object have user-defined 'cancelpressed' property. In the second button click method I put this:
thisForm.cancelpressed = .T.
Thisform.Release()
Clear Events
But it not work. When loop started it dont want to listen any commands and clicks, and it dont let to close the program. Please help if you can

You could try setting
Application.AutoYield = .T.
as per https://msdn.microsoft.com/en-us/library/aa977324(v=vs.71).aspx
But if that doesn't work then I think you are stuck as VFP is not a true multithreaded application. You might be able to get around the problem using a timer object as per http://fox.wikis.com/wc.dll?Wiki~TimerExample or using a multi threading workaround from https://blogs.msdn.microsoft.com/calvin_hsia/2006/05/16/create-multiple-threads-from-within-your-application/ but you would be very much on your own.
I have to say that starting a new application in VFP today probably isn't the best idea. There are plenty of current alternatives.

The problem is with your wait window. Remove it.
Local greenColor, orangeColor, redColor
m.greenColor = 0x00FF00
m.orangeColor = 0x3060FF
m.redColor = 0xFF0000
Do While !Thisform.cancelpressed
randNum=Val(Trim(Str(Round( 3*Rand(), 1))))
If m.randNum = Val("1")
Thisform.shape1.BackColor = m.greenColor
Thisform.shape2.BackColor = m.orangeColor
Thisform.shape3.BackColor = m.redColor
Endif
Doevents
Enddo
(I don't understand why you are doing such a weird randNum setting and check nor the purpose of setting the same colours again and again but it is not the point in this question)
Normally you should prefer using a Timer with a code like this.
And BTW this has nothing to do with multithreading neither in VFP nor in another language. You are simply doing a loop with a cancel flag check. Updating the UI, say in C#, with the same approach wouldn't be any easier.

Related

Libreoffice Base - how to call a control event from a macro?

Question: I need to manually call an object listener event (e.g. key pressed) to trigger a function. I used to do it in Access but haven't found the documentation for it in LibreOffice Base.
Context: Having retired from software development 7 years ago, I am doing a favour for a friend by building a database in LibreOffice Base. Previously experienced in Access - but more with Oracle, PL/SQL, APEX, etc! I am struggling a little in getting it to do what I know can be done!
Here is the code I've tried so far.
Sub CauseKeyPressedEventToBeFired
oDoc = ThisComponent
oController = oDoc.getCurrentController()
oVC = oController.getViewCursor()
oForm = oDoc.getDrawpage().getForms().getByName("Form")
oTextBox = oForm.getByName("Text Box 1")
oControlView = oController.getControl(oTextBox)
oControlView.setFocus()
Dim oEvent As New com.sun.star.awt.KeyEvent
oEvent.Source = oControlView
oEvent.KeyCode = com.sun.star.awt.Key.A
oControlView.keyPressed(oEvent)
End Sub
However, it doesn't seem to work on my system (LibreOffice 6.4.3.2 on Windows). I also found this post, but that code doesn't seem to work for me either.
I searched for com.sun.star.awt.XToolkitRobot, but it's not in the API documentation, perhaps because the functionality is not fully supported. Presumably, it can be obtained from com.sun.star.awt.Toolkit.
For more help, post a question on ask.libreoffice.org. I'd suggest explaining why you want to do this, because there may be a different kind of solution. Ratslinger has a lot of experience solving various database problems, and he'll probably direct you toward a simpler solution that doesn't involve this kind of event hacking.
a function (i.e. a procedure that returns a value)
Yes, that is what a function is. But "an object listener event" implies, correctly I think, that we're talking about the method of an object instead. That's what LibreOffice event listeners are in Python or Java, although in Basic, they're a little strange, using the object name as some kind of magic to determine what they apply to. Anyway, that's getting off track, because your question isn't about listening for events, but rather about triggering them.
EDIT:
The following Python code works. The problem with my earlier attempts was that oEvent.KeyChar needs to be set, and that doesn't seem to work in Basic. I can't imagine why, unless I am ignoring some obvious mistake in the Basic code.
def causeKeyPressedEventToBeFired(oEvent=None):
oDoc = XSCRIPTCONTEXT.getDocument()
oController = oDoc.getCurrentController()
oForm = oDoc.getDrawPage().getForms().getByName("Form")
oTextBox = oForm.getByName("Text Box 1")
oControlView = oController.getControl(oTextBox)
oControlView.setFocus()
oEvent = uno.createUnoStruct("com.sun.star.awt.KeyEvent")
oEvent.Source = oControlView
from com.sun.star.awt.Key import A
oEvent.KeyCode = A
oEvent.KeyChar = "a" # works in Python but strangely not in Basic
simulate_KeyPress(oEvent)
def simulate_KeyPress(oKeyEvent):
oDoc = XSCRIPTCONTEXT.getDocument()
oWindow = oDoc.CurrentController.Frame.getContainerWindow()
oKeyEvent.Source = oWindow
oToolkit = oWindow.getToolkit()
oToolkit.keyPress(oKeyEvent)
oToolkit.keyRelease(oKeyEvent)
EDIT 2:
Finally, here is working Basic code. In the earlier attempt, the type was wrong.
Sub CauseKeyPressedEventToBeFired
oDoc = ThisComponent
oController = oDoc.getCurrentController()
oForm = oDoc.getDrawpage().getForms().getByName("Form")
oTextBox = oForm.getByName("Text Box 1")
oControlView = oController.getControl(oTextBox)
oControlView.setFocus()
Dim oEvent As New com.sun.star.awt.KeyEvent
oEvent.KeyCode = com.sun.star.awt.Key.A
oEvent.KeyChar = CByte(97)
simulate_KeyPress(oEvent)
End Sub
Sub simulate_KeyPress(oKeyEvent As com.sun.star.awt.KeyEvent)
oWindow = ThisComponent.CurrentController.Frame.getContainerWindow()
oKeyEvent.Source = oWindow
oToolkit = oWindow.getToolkit()
oToolkit.keyPress(oKeyEvent)
oToolkit.keyRelease(oKeyEvent)
End Sub

How to push a message loop in WinForms?

In WPF, I can push a message loop using Dispatcher.PushFrame.
What is the equivalent in WinForms? I'm familiar with DoEvents but that must be called in a loop which can spin the CPU instead of the very efficient approach of just waiting for a message or for an event to signal to exit (like Dispatcher.PushFrame has).
I was able to include WindowsBase to my project's references and just use Dispatcher.PushFrame and frame.Continue = false as usual.
Any caveats with wpf-winforms interop apply, and it does require part of wpf to be referenced, but it should still be better than DoEvents (which has severe pitfalls).
This is the equivalent:
System.Threading.SendOrPostCallback callback = o =>
{
this.Text = "Hello" + o.ToString(); // "Hello42"
};
WindowsFormsSynchronizationContext.Current.Post(callback, 42);
The 42 is a state parameter that gets past to the callback.
You can also do this:
this.BeginInvoke((Action)(() => this.Text = "Hello"));
BTW, you should never ever ever use DoEvents - it's a great way to introduce bugs in to your code and is really only there for VB6 compatibility.

Creating a visible timer on experiment stimulus in psychopy

New to the forum, thanks in advance for any help you could provide.
I have a series of .jpgs that are being presented to users as they study the info contained within. Instructions state that each jpg can be studied for a max of 120secs. I've already coded it such that the jpg will advance after the 120sec limit:
RespKey= []
RT = []
event.clearEvents()
myClock.reset()
t1example = myClock.getTime()
t2example = t1example
while t2example < (t1example+120): # value added to t1 here is timeout value;
RespKey = event.getKeys(keyList=["space"], timeStamped=myClock) # they are told to press space bar when done studying
if len(RespKey) > 0:
RT = RespKey[0][1]
Resp = RespKey[0][0].lower()
print Resp
print RT
break
else:
t2study = myClock.getTime() # end of timeout loop
myWin.flip()
The problem is, I don't know how to make the Clock/ Timer/ Stopwatch function visible to the user while studying the jpg. Is there a way to superimpose a visible clock onto the stimulus so nobody is surprised when the study time comes to an end?
Note: New to coding, please couch jargon in layman speak if at all possible.
Thank you!
Yes. Before the loop (and before re-setting the clock), create a text stimulus like this:
clockText = visual.TextStim(myWin) # include other parameters if you want to change the default size, font, etc
Then on every frame, you will update the content of that stimulus. i.e. just prior to the myWin.flip() call, do this:
clockText.setText(str(t2study)) # you can format/round this as required
clockText.draw()
Check the face_jpg.py Coder demo for an example of displaying text like this on every frame.

How to make a function wait X amount of time in LUA (Love2d)?

I am very new to programming and coming from a "custom map" background in games like SC2. I am currently trying to make a platformer game in Love2d. But I wonder how I can make something wait X amount of seconds before doing the next thing.
Say I want to make the protagonist immortal for 5 seconds, how should that code look like ?
Immortal = true
????????????????
Immortal = false
As I have understood there is no built in wait in Lua nor Love2d.
It sounds like you're interested in a temporary state for one of your game entities. This is pretty common - a powerup lasts for six seconds, an enemy is stunned for two seconds, your character looks different while jumping, etc. A temporary state is different than waiting. Waiting suggests that absolutely nothing else happens during your five seconds of immortality. It sounds like you want the game to continue as normal, but with an immortal protagonist for five seconds.
Consider using a "time remaining" variable versus a boolean to represent temporary states. For example:
local protagonist = {
-- This is the amount of immortality remaining, in seconds
immortalityRemaining = 0,
health = 100
}
-- Then, imagine grabbing an immortality powerup somewhere in the game.
-- Simply set immortalityRemaining to the desired length of immortality.
function protagonistGrabbedImmortalityPowerup()
protagonist.immortalityRemaining = 5
end
-- You then shave off a little bit of the remaining time during each love.update
-- Remember, dt is the time passed since the last update.
function love.update(dt)
protagonist.immortalityRemaining = protagonist.immortalityRemaining - dt
end
-- When resolving damage to your protagonist, consider immortalityRemaining
function applyDamageToProtagonist(damage)
if protagonist.immortalityRemaining <= 0 then
protagonist.health = protagonist.health - damage
end
end
Be careful with concepts like wait and timer. They typically refer to managing threads. In a game with many moving parts, it's often easier and more predictable to manage things without threads. When possible, treat your game like a giant state machine versus synchronizing work between threads. If threads are absolutely necessary, Löve does offer them in its love.thread module.
I normally use cron.lua for what you're talking about: https://github.com/kikito/cron.lua
Immortal = true
immortalTimer = cron.after(5, function()
Immortal = false
end)
and then just stick immortalTimer:update(dt) in your love.update.
You could do this:
function delay_s(delay)
delay = delay or 1
local time_to = os.time() + delay
while os.time() < time_to do end
end
Then you can just do:
Immortal == true
delay_s(5)
Immortal == false
Of course, it'll prevent you from doing anything else unless you run it in its own thread. But this is strictly Lua as I know nothing of Love2d, unfortunately.
I reccomend that you use hump.timer in your game,like this:
function love.load()
timer=require'hump.timer'
Immortal=true
timer.after(1,function()
Immortal=false
end)
end
instead of using timer.after,you can also use timer.script,like this:
function love.load
timer=require'hump.timer'
timer.script(function(wait)
Immortal=true
wait(5)
Immortal=false
end)
end
don't forget to add timer.updateinto function love.update!
function love.update(dt)
timer.update(dt)
end
hope this helped ;)
Download link:https://github.com/vrld/hump

Visual Studio timer problem

I couldn't find any explanation for the following problem. Hope you to help me to know the solution...
Let's make a new windows appliaction (using any version of VS), and add a button, timer (we modify the interval to become = 10), and a label (with initial text = "0").
write the following code in the timer:
label1.Text =
(Convert.ToInt32(label1.Text) +
1).ToString();
write the following code in the button:
timer1.Enabled = true;
The label should show an incremental counter starting from 0.
Logically, each 100 counts should consume 1 second, but this is NOT the truth.
What happens is that each 100 counts consume a little bit more than 1 second !!!
What is the cause of this behavior????!!!
Thank you very much for your listenning, and waiting for your reply because I really searched for an explenation but I couldn't find anything.
If you are using System.Windows.Forms.Timer, it is limited to an accuracy of 55 ms.
The Windows Forms Timer component is single-threaded, and is limited to an accuracy of 55 milliseconds. If you require a multithreaded timer with greater accuracy, use the Timer class in the System.Timers namespace.
See the Remarks section: System.Windows.Forms.Timer

Resources