Question about implementation of a delay

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Question about implementation of a delay

CyrilFerlicot
Hi,

I am building a widget for fast table in order to filter them for
Synectique and Pharo.

For now I have a Rubric editor where we can write a pattern and I use a
Rubric announcement to update the Fast Table. So each time the rubric is
update the method #update is call.

At the beginning #update was:

----
pattern := self patternFromString: filterField getText asString trimBoth.
fastTable dataSource: (initialDataSource newDataSourceMatching: pattern).
fastTable refresh
-----

But this will update the Fast Table at each character, so I want to add
a delay.
For example I want to let the user type and update the table if he don't
type for 0.2second.

The only way I found is this:

----
update: anAnnoucement
        | pattern timeStamp |
        timeStamp := DateAndTime now.
        timestamp := timeStamp copy.
        [
        (Delay forMilliseconds: 200) wait.
        timeStamp = timestamp
                ifTrue: [
                        pattern := self patternFromString: filterField getText asString trimBoth.
                        fastTable dataSource: (initialDataSource newDataSourceMatching: pattern).
                        fastTable refresh ] ] fork
----

But I think that create a new process a each update is really too heavy…
So I would like to have some advices from experienced people to know if
there is a better way to implement a delay.

If you want to check the code you can execute:

----
Gofer new
    smalltalkhubUser: 'estebanlm' project: 'FastTable';
    configuration;
    load.
(Smalltalk globals at: #ConfigurationOfFastTable) loadDevelopment.
FTFastTableComposer browse
----

--
Cyril Ferlicot

http://www.synectique.eu

165 Avenue Bretagne
Lille 59000 France


signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Question about implementation of a delay

Henrik Nergaard
delay := [ :msToWait |
| t |
t := Time millisecondClockValue.
[ (Time millisecondClockValue - t) < msToWait ]
      whileTrue: [ World doOneCycle ].
].

delay value: 200.


Best regards,
Henrik

-----Original Message-----
From: Pharo-dev [mailto:[hidden email]] On Behalf Of Ferlicot D. Cyril
Sent: Tuesday, October 13, 2015 9:03 PM
To: Pharo <[hidden email]>
Subject: [Pharo-dev] Question about implementation of a delay

Hi,

I am building a widget for fast table in order to filter them for Synectique and Pharo.

For now I have a Rubric editor where we can write a pattern and I use a Rubric announcement to update the Fast Table. So each time the rubric is update the method #update is call.

At the beginning #update was:

----
pattern := self patternFromString: filterField getText asString trimBoth.
fastTable dataSource: (initialDataSource newDataSourceMatching: pattern).
fastTable refresh
-----

But this will update the Fast Table at each character, so I want to add a delay.
For example I want to let the user type and update the table if he don't type for 0.2second.

The only way I found is this:

----
update: anAnnoucement
        | pattern timeStamp |
        timeStamp := DateAndTime now.
        timestamp := timeStamp copy.
        [
        (Delay forMilliseconds: 200) wait.
        timeStamp = timestamp
                ifTrue: [
                        pattern := self patternFromString: filterField getText asString trimBoth.
                        fastTable dataSource: (initialDataSource newDataSourceMatching: pattern).
                        fastTable refresh ] ] fork
----

But I think that create a new process a each update is really too heavy… So I would like to have some advices from experienced people to know if there is a better way to implement a delay.

If you want to check the code you can execute:

----
Gofer new
    smalltalkhubUser: 'estebanlm' project: 'FastTable';
    configuration;
    load.
(Smalltalk globals at: #ConfigurationOfFastTable) loadDevelopment.
FTFastTableComposer browse
----

--
Cyril Ferlicot

http://www.synectique.eu

165 Avenue Bretagne
Lille 59000 France

Reply | Threaded
Open this post in threaded view
|

Re: Question about implementation of a delay

Henrik Sperre Johansen
In reply to this post by CyrilFerlicot
If you by some chance don't like UILoops, and so don't want to make a spinning UILoop inside your UILoop, you could also use a single background thread, something like;

FilteredDataSource (to be used as dataSource for FastTable, polymorphic api to normal dataSource but redirecting to filteredDataSource variable)
class protocol
filter: aFilter source: aDataSource
        ^self new initializeFilter: aFilter source: aDataSource
inst protocol, update related
initializeFilter: aFilterField source: aDataSource

        initialDataSource := filteredDataSource := aDataSource
        filterChangeSemaphore := Semaphore new.
        self spawnFilterUpdateThread
        aFilterField when: ValueChanged send: #updateFilter: to self

updateFilter: aChangeAnnouncement
        "(Probably) runs on UI thread"
        pattern := aChangeAnnouncement newValue.
        filterChangeSemaphore signal.

spawnFilterUpdateThread
        "Runs in background"
        [ | oldPattern |
        oldPattern := pattern.
        [ filterChangeSemaphore wait.
        "If pattern has changed, see if we need to filter.
        If not, it's probably an extraneous signal received while we were waiting for 0.2 seconds, and we discard then till we end up waiting for filterChangeSemaphore again"
        oldPattern ~= pattern
                ifTrue: [
                        oldPattern := pattern.
                        0.2 seconds wait.
                        "Pattern still the same? If not, just loop again and end up waiting for another 0.2 secs"
                        oldPattern = pattern
                                ifTrue: [
                                        filteredDataSource := initialDataSource newDataSourceMatching: pattern.
                                        self announce: WhateverChangeAnnouncementBasedOnWhichFastTableSchedulesAViewUpdateForItsDatasource ]]] repeat ]
                forkAt: Processor userBackgroundPriority

Cheers,
Henry

> On 13 Oct 2015, at 9:02 , Ferlicot D. Cyril <[hidden email]> wrote:
>
> Hi,
>
> I am building a widget for fast table in order to filter them for
> Synectique and Pharo.
>
> For now I have a Rubric editor where we can write a pattern and I use a
> Rubric announcement to update the Fast Table. So each time the rubric is
> update the method #update is call.
>
> At the beginning #update was:
>
> ----
> pattern := self patternFromString: filterField getText asString trimBoth.
> fastTable dataSource: (initialDataSource newDataSourceMatching: pattern).
> fastTable refresh
> -----
>
> But this will update the Fast Table at each character, so I want to add
> a delay.
> For example I want to let the user type and update the table if he don't
> type for 0.2second.
>
> The only way I found is this:
>
> ----
> update: anAnnoucement
> | pattern timeStamp |
> timeStamp := DateAndTime now.
> timestamp := timeStamp copy.
> [
> (Delay forMilliseconds: 200) wait.
> timeStamp = timestamp
> ifTrue: [
> pattern := self patternFromString: filterField getText asString trimBoth.
> fastTable dataSource: (initialDataSource newDataSourceMatching: pattern).
> fastTable refresh ] ] fork
> ----
>
> But I think that create a new process a each update is really too heavy…
> So I would like to have some advices from experienced people to know if
> there is a better way to implement a delay.
>
> If you want to check the code you can execute:
>
> ----
> Gofer new
>    smalltalkhubUser: 'estebanlm' project: 'FastTable';
>    configuration;
>    load.
> (Smalltalk globals at: #ConfigurationOfFastTable) loadDevelopment.
> FTFastTableComposer browse
> ----
>
> --
> Cyril Ferlicot
>
> http://www.synectique.eu
>
> 165 Avenue Bretagne
> Lille 59000 France
>


signature.asc (859 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Question about implementation of a delay

CyrilFerlicot
Le 14/10/2015 09:01, Henrik Johansen a écrit :

> If you by some chance don't like UILoops, and so don't want to make a spinning UILoop inside your UILoop, you could also use a single background thread, something like;
>
> FilteredDataSource (to be used as dataSource for FastTable, polymorphic api to normal dataSource but redirecting to filteredDataSource variable)
> class protocol
> filter: aFilter source: aDataSource
> ^self new initializeFilter: aFilter source: aDataSource
> inst protocol, update related
> initializeFilter: aFilterField source: aDataSource
>
> initialDataSource := filteredDataSource := aDataSource
> filterChangeSemaphore := Semaphore new.
> self spawnFilterUpdateThread
> aFilterField when: ValueChanged send: #updateFilter: to self
>
> updateFilter: aChangeAnnouncement
> "(Probably) runs on UI thread"
> pattern := aChangeAnnouncement newValue.
> filterChangeSemaphore signal.
>
> spawnFilterUpdateThread
> "Runs in background"
> [ | oldPattern |
> oldPattern := pattern.
> [ filterChangeSemaphore wait.
> "If pattern has changed, see if we need to filter.
> If not, it's probably an extraneous signal received while we were waiting for 0.2 seconds, and we discard then till we end up waiting for filterChangeSemaphore again"
> oldPattern ~= pattern
> ifTrue: [
> oldPattern := pattern.
> 0.2 seconds wait.
> "Pattern still the same? If not, just loop again and end up waiting for another 0.2 secs"
> oldPattern = pattern
> ifTrue: [
> filteredDataSource := initialDataSource newDataSourceMatching: pattern.
> self announce: WhateverChangeAnnouncementBasedOnWhichFastTableSchedulesAViewUpdateForItsDatasource ]]] repeat ]
> forkAt: Processor userBackgroundPriority
>
> Cheers,
> Henry
>
Thank you really much!
I tried to get a working version of the widget with the UILoop but that
was terrible.
But the semaphore work fine. I still need to learn a lot of things about
fork, semaphore & co.

Thank you for your precious help :)


--

Cyril Ferlicot

http://www.synectique.eu

165 Avenue Bretagne
Lille 59000 France


signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Question about implementation of a delay

Henrik Sperre Johansen

On 14 Oct 2015, at 1:32 , Ferlicot D. Cyril <[hidden email]> wrote:

Le 14/10/2015 09:01, Henrik Johansen a écrit :
If you by some chance don't like UILoops, and so don't want to make a spinning UILoop inside your UILoop, you could also use a single background thread, something like;

FilteredDataSource (to be used as dataSource for FastTable, polymorphic api to normal dataSource but redirecting to filteredDataSource variable)
class protocol
filter: aFilter source: aDataSource
^self new initializeFilter: aFilter source: aDataSource
inst protocol, update related
initializeFilter: aFilterField source: aDataSource

initialDataSource := filteredDataSource := aDataSource
filterChangeSemaphore := Semaphore new.
self spawnFilterUpdateThread
aFilterField when: ValueChanged send: #updateFilter: to self

updateFilter: aChangeAnnouncement
"(Probably) runs on UI thread"
pattern := aChangeAnnouncement newValue.
filterChangeSemaphore signal.

spawnFilterUpdateThread
"Runs in background"
[ | oldPattern |
oldPattern := pattern.
[ filterChangeSemaphore wait.
"If pattern has changed, see if we need to filter.
If not, it's probably an extraneous signal received while we were waiting for 0.2 seconds, and we discard then till we end up waiting for filterChangeSemaphore again"
oldPattern ~= pattern
ifTrue: [
oldPattern := pattern.
0.2 seconds wait.
"Pattern still the same? If not, just loop again and end up waiting for another 0.2 secs"
oldPattern = pattern
ifTrue: [
filteredDataSource := initialDataSource newDataSourceMatching: pattern.
self announce: WhateverChangeAnnouncementBasedOnWhichFastTableSchedulesAViewUpdateForItsDatasource ]]] repeat ]
forkAt: Processor userBackgroundPriority

Cheers,
Henry


Thank you really much!
I tried to get a working version of the widget with the UILoop but that
was terrible.
But the semaphore work fine. I still need to learn a lot of things about
fork, semaphore & co.

Thank you for your precious help :)

No problem!
I also tried to show how to avoid the FilteredDataSource model referencing GUI elements directly, hope you picked up on that as well :)

Cheers,
Henry

signature.asc (859 bytes) Download Attachment