|
Class: BlockValue
Object
|
+--Model
|
+--ValueModel
|
+--BlockValue
|
+--BooleanBlockValue
- Package:
- stx:libview2
- Category:
- Interface-Support-Models
- Version:
- rev:
1.42
date: 2023/07/15 18:33:51
- user: cg
- file: BlockValue.st directory: libview2
- module: stx stc-classLibrary: libview2
BlockValues depend on one or more other objects (typically valueHolders)
and recompute a value whenever one of them changes.
If the recomputed new value is different, it triggers itself a change to its dependents.
A typical example use is to base an enableChannel's value on multiple other
boolean (or non-boolean) values. (See example for how this is done)
Notice, that a BlockValue can also be created without depending on any other
object (i.e. BlockValue with:aBlock). In this case, a recomputation must be explicitly
triggered by sending #recomputeValue to the blockValue instance.
BlockValues cannot be used to write into an aspect; they are typically used
in GUI components to present an alternative view on some other aspect.
Notice:
this class was implemented using protocol information
from alpha testers - it may not be complete or compatible to
the corresponding ST-80 class.
If you encounter any incompatibilities, please forward a note
describing the incompatibility verbal (i.e. no code) to the ST/X team.
Warning:
BlockValues only work ine one direction; changing the blockValue's value
does not affect the original model's value.
copyrightCOPYRIGHT (c) 1995 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
initialization
-
initialize
-
(comment from inherited method)
called only once - initialize signals
instance creation
-
block: aBlock arguments: aCollectionOfValueModels
-
return a new BlockValue computing aBlock whenever one of aCollectionOfValueModels changes.
Same as #with:arguments: for ST80 compatibility
-
with: aBlock
-
return a new BlockValue computing aBlock
-
with: aBlock argument: aValueModel
-
return a new BlockValue computing aBlock whenever aValueModel changes
-
with: aBlock argument: valueModel1 argument: valueModel2
-
return a new BlockValue computing aBlock whenever one of the value models changes
-
with: aBlock argument: valueModel1 argument: valueModel2 argument: valueModel3
-
return a new BlockValue computing aBlock whenever one of the value models changes
-
with: aBlock argument: valueModel1 argument: valueModel2 argument: valueModel3 argument: valueModel4
-
return a new BlockValue computing aBlock whenever one of the value models changes
-
with: aBlock arguments: aCollectionOfValueModels
-
return a new BlockValue computing aBlock whenever one of the value models changes
instance creation - useful BlockValues
-
forLogical: valueModel1 and: valueModel2
-
return a new BlockValue computing the logical AND of its args
(which are usually other valueHolders)
-
forLogical: valueModel1 and: valueModel2 and: valueModel3
-
return a new BlockValue computing the logical AND of its args
(which are usually other valueHolders)
-
forLogical: valueModel1 or: valueModel2
-
return a new BlockValue computing the logical OR of its args
(which are usually other valueHolders)
-
forLogical: valueModel1 or: valueModel2 or: valueModel3
-
return a new BlockValue computing the logical OR of its args
(which are usually other valueHolders)
-
forLogicalAndAll: arrayOfValueModels
-
return a new BlockValue computing the logical AND of all elements
in the passed argArray (which are usually other valueHolders)
-
forLogicalNot: aValueModel
-
return a new BlockValue computing the logical NOT of its arg
(which is usually another valueHolder)
Usage example(s):
|v1 v2|
v1 := ValueHolder new.
v1 value:true.
v2 := BlockValue forLogicalNot:v1.
v2 onChangeEvaluate:[ Transcript showCR:v2 value].
Transcript showCR:v2 value. 'shows a false already'.
v1 value:true. 'no change signalled here'.
v1 value:false.
v1 value:true.
|
-
forLogicalOrAll: arrayOfValueModels
-
return a new BlockValue computing the logical OR of all elements
in the passed argArray (which are usually other valueHolders)
-
forTrueIfNotNil: valueModel
-
return a new BlockValue generating true of valueModel holds on a non-nil value,
false otherwise.
-
forValue: someValueModel equalTo: someConstant
-
return a new BlockValue generating a true,
if someValue (usually another holder) contains a value equal to someConstant.
Useful, if the other valueHolder is a radioButton group model,
and you want to automatically enable/disable other items based on the value
(i.e. via the enableChannel)
Usage example(s):
|v1 v2|
v1 := ValueHolder new.
v1 value:'blah'.
v2 := BlockValue forValue:v1 equalTo:'hello'.
v2 onChangeEvaluate:[ Transcript showCR:v2 value].
Transcript showCR:v2 value. 'shows a false already'.
v1 value:'blah'. 'no change signalled here'.
v1 value:'oops'. 'remains false'.
v1 value:'hello'. 'changes to true'.
v2 value
|
accessing
-
setArguments: aCollectionOfArguments
-
set the receiver's arguments to be passed to it.
A change in any of the arguments will force reevaluation of the action
block - possibly generating another change from myself
-
setBlock: aBlock
-
set the receiver's action block
-
setBlock: aBlock argumentArray: anArgumentCollection
-
set the receiver's action block, and define an arguments collection
to be passed to it.
A change in any element of the collection will force reevaluation of the
action block (passing the collection as a single argument)
- possibly generating another change from myself
-
setBlock: aBlock arguments: aCollectionOfArguments
-
set the receiver's action block, and define arguments to be passed to it.
A change in any of the arguments will force reevaluation of the action
block - possibly generating another change from myself
-
setValue: newValue
-
physically set my value, without change notifications.
This is a noop here, since my value is computed.
-
value
-
retrieve my value - this does not always evaluate the action block,
since the returned value is cached internally
change & update
-
recomputeValue
-
force reevaluation of my actionBlock,
and possibly send a change notification to my dependents
-
update: something with: aParameter from: someone
-
the one I depend on has changed - reevaluate my actionBlock,
and possibly send a change notification to my dependents
dependents access
-
release
-
release any dependencies upon the arguments
misc
-
computeValue
-
evaluate the receiver's action block
-
dependOn: someObject
-
arrange for the blockValue to be reevaluated, whenever someObject
changes (i.e. sends a change notification)
-
resetValue
-
evaluate the receiver's action block
printing
-
displayOn: aStreamOrGC
-
(comment from inherited method)
Compatibility
append a printed desription on some stream (Dolphin, Squeak)
OR:
display the receiver in a graphicsContext at 0@0 (ST80).
This method allows for any object to be displayed in some view
(although the fallBack is to display its printString ...)
Notice: displayString and displayOn: are for developers, debugging and inspectors,
whereas printString and printOn: are for the program to print data.
checkToggle 3 shows the value of toggle1 AND toggle2
|val1 val2 both box|
val1 := false asValue.
val2 := false asValue.
both := BlockValue
with:[:v1 :v2 |
Transcript showCR:'evaluating ...'.
v1 value and:[v2 value]
]
arguments:(Array with:val1 with:val2).
box := Dialog new.
box addCheckBox:'one' on:val1.
box addCheckBox:'two' on:val2.
box addHorizontalLine.
box addCheckBox:'both' on:both.
box addOkButton.
box open
|
the same, using a convenient instance creation message:
|val1 val2 both box|
val1 := false asValue.
val2 := false asValue.
both := BlockValue forLogical:val1 and:val2.
box := Dialog new.
box addCheckBox:'one' on:val1.
box addCheckBox:'two' on:val2.
box addHorizontalLine.
(box addCheckBox:'both' on:both) disable.
box addOkButton.
box open
|
logical or:
|val1 val2 both box|
val1 := false asValue.
val2 := false asValue.
both := BlockValue forLogical:val1 or:val2.
box := Dialog new.
box addCheckBox:'one' on:val1.
box addCheckBox:'two' on:val2.
box addHorizontalLine.
box addCheckBox:'both' on:both.
box addOkButton.
box open
|
example use: enabling an element depending on two others:
|val1 val2 enabler val3 box|
val1 := false asValue.
val2 := false asValue.
val3 := false asValue.
enabler := BlockValue forLogical:val1 and:val2.
box := Dialog new.
box addCheckBox:'one' on:val1.
box addCheckBox:'two' on:val2.
box addHorizontalLine.
(box addCheckBox:'three (both of the above)' on:val3) enableChannel:enabler.
box addOkButton.
box open
|
like above, using a logical-or block:
|val1 val2 enabler val3 box|
val1 := false asValue.
val2 := false asValue.
val3 := false asValue.
enabler := BlockValue forLogical:val1 or:val2.
box := Dialog new.
box addCheckBox:'one' on:val1.
box addCheckBox:'two' on:val2.
box addHorizontalLine.
(box addCheckBox:'three (any of the above)' on:val3) enableChannel:enabler.
box addOkButton.
box open
|
like above, using a bunch of toggles:
|values anyValue box|
values := (1 to:10) collect:[:i | false asValue].
anyValue := BlockValue forLogicalOrAll:values.
anyValue onChangeSend:#value to:[Transcript showCR:'any is true'].
box := Dialog new.
values keysAndValuesDo:[:index :aValueHolder |
box addCheckBox:index printString on:aValueHolder.
].
box addHorizontalLine.
(box addOkButton) enableChannel:anyValue.
box open
| a logical-not block:
|val1 valNot box|
val1 := false asValue.
valNot := BlockValue forLogicalNot:val1.
box := Dialog new.
box addCheckBox:'one' on:val1.
box addHorizontalLine.
(box addCheckBox:'not one' on:valNot) enabled:false
box addOkButton.
box open
|
|