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 |
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 |
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 |
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 > 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 |
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 |
Free forum by Nabble | Edit this page |