天道酬勤,学无止境

Trying to render fields in threepenny-gui with special behaviour

What I want to do is set up fields which show detail when they're in focus, but summary when they're not. eg.

a). when it loses focus (gets blur?), I save the value in a (State?) Map and then change the value to a function of the old value (ie. the summary value)

b). when it gets focus - I replace the summary value with the old value that I saved in the Map

I cant' figure out how to do this, but I think I probably need a state monad and the UI monad. My try is:

renderField :: Map->Int->UI (Element, Map)
renderField vs ix = do
    input <- UI.input  
    on UI.blur input $ \_ -> void $ do
        fieldValue <- get value input
        let newVs = insert ix fieldValue vs
        return input # set UI.value (calcNewValue fieldValue)
    on UI.focus input $ \_ -> void $ do
        let savedValue = findWithDefault "" ix vs
        return input # set UI.value savedValue
    return (input, newVs)

but I can't get this map to work - because it needs to track all the calls.... I guess it should be State monad or something?

Thanks.

N

评论

Indeed, you need to keep track of state.

However, the usual pattern s -> (a,s) (the state monad) does not apply here, as you are working with callback functions. For these, you need a different pattern.

In the traditional imperative style, one would use a mutable variable here, for instance an IORef. Note that it is no longer necessary to keep track of indices -- you can think of an IORef as being an index in a large mutable map.

renderField :: UI Element
renderField = do
    input <- UI.input
    state <- liftIO $ newIORef

    on UI.blur input $ \_ -> do
        fieldValue <- get value input
        liftIO $ writeIORef state fieldValue    
        element input # set UI.value (calcNewValue fieldValue)

    on UI.focus input $ \_ -> do
        savedValue <- liftIO $ readIORef state
        element input # set UI.value savedValue

    return input

Alternatively, you can also use functional reactive programming (FRP) in Threepenny. Note that the API is still somewhat preliminary, the following code is specific to threepenny-gui version 0.4.*:

renderField :: UI Element
renderField = do
    input  <- UI.input

    bValueUser <- stepper "" $ UI.valueChange input
    bState     <- stepper "" $ bValueUser <@ UI.blur input
    bValue     <- stepper "" $ fmap head $ unions
        [ (calcNewValue <$> bValueUser) <@ UI.blur input
        , bState <@ UI.focus input
        ]
    element input # sink UI.value bValue 

Again, there are still a couple of subtleties and warts in this code, but this is the general direction I want to head in. Some preliminary information about FRP and how it applies to GUI development can be found in the documentation.

My recommendation is to use the familiar solution (IORef) when you need to get something done quickly, and explore the FRP solution when you have plenty of free time. The example code mainly uses the FRP style.

(Disclosure: I'm the author of Threepenny.)

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • Dynamic Elements based on Behaviour in threepenny-gui
    To put it simple, I am looking for a way to display a Behaviour (UI Element). My actual use-case is displaying a table, which can be filtered. So I have a function tableElement :: String -> UI Element (the String parameter being the filter condition) and an input field filterElement :: Element, which represents the filter. The most natural way for me to combine these would be something like this: bFilter <- stepper "" (valueChange filterElement) displaySomehow (fmap tableElement bFilter) This is also the way it is done in Elm. The closest thing I have found so far is using sink children, but
  • using threepenny-gui/reactive in client/server programming
    I am trying to figure out how to use Haskell threepenny-gui with its reactive functionality to write a program that lets the user select an item from a listBox send the selection to an external server get back a list of results from the server populate the listBox with the results repeat It seems I will need to use Handler, newEvent and register to do the above. If someone could point me to some existing code that does something like the above that would be great. The closest I have found is GameThing.hs in the threepenny-gui samples directory (but it doesn't use register). UPDATE: I am asking
  • 在客户端/服务器编程中使用threepenny-gui/reactive(using threepenny-gui/reactive in client/server programming)
    问题 我试图弄清楚如何使用 Haskell Threepenny-gui 及其反应性功能来编写一个程序,让 用户从列表框中选择一个项目将选择发送到外部服务器从服务器获取结果列表用结果填充列表框重复 看来我需要使用Handler 、 newEvent和register来完成上述操作。 如果有人能指点我一些现有的代码来做类似上面的事情,那就太好了。 我发现最接近的是GameThing.hs -gui samples目录中的 GameThing.hs (但它不使用register )。 更新: 我在问我是否应该使用Handler 、 newEvent和register --- 如果是的话,对这些函数进行一些说明或示例。 另外,要清楚的是,大局是: browser --> threepenny-gui (on localhost) --> backend server (anywhere on network) <-- <-- 换句话说,我需要做一些 IO(基于用户选择)然后显示该 IO 的结果。 更新:这是我的解决方案(基于@Taldykin 的回应):https://github.com/haroldcarr/rdf-triple-browser/tree/master/haskell/src 回答1 这是一段代码。 稍后我会添加说明。 {-# LANGUAGE LambdaCase
  • 模板不会将接口类型的字段评估为基础类型(template won't evaluate fields that are interface type as the underlying type)
    问题 使用 golang html/template (与text/template相同的行为)。 如果我有一个带有接口类型成员的结构,我将无法访问底层类型的成员(特别是尝试访问实现接口InnerInterface但通过InnerInterface接口类型返回的结构上的字段,而不是结构类型)。 http://play.golang.org/p/ZH8wSK83oM package main import "fmt" import "os" import "html/template" type InnerInterface interface{ InnerSomeMethod() } type MyInnerStruct struct { Title string } func (mis MyInnerStruct)InnerSomeMethod() { fmt.Println("Just to show we're satisfying the interface") } type MyOuterStruct struct { Inner InnerInterface } func main() { fmt.Println("Starting") arg := MyOuterStruct{Inner:MyInnerStruct{Title:"test1"}} err :=
  • Mixing Threepenny-Gui and StateT
    I have a question on the interaction of Threepenny-Gui with StateT. Consider this toy program that, every time the button is clicked, adds a "Hi" item in the list: import Control.Monad import Control.Monad.State import qualified Graphics.UI.Threepenny as UI import Graphics.UI.Threepenny.Core hiding (get) main :: IO () main = startGUI defaultConfig setup setup :: Window -> UI () setup w = void $ do return w # set title "Ciao" buttonAndList <- mkButtonAndList getBody w #+ map element buttonAndList mkButtonAndList :: UI [Element] mkButtonAndList = do myButton <- UI.button # set text "Click me!"
  • 混合 Threepenny-Gui 和 StateT(Mixing Threepenny-Gui and StateT)
    问题 我有一个关于 Threepenny-Gui 与 StateT 交互的问题。 考虑这个玩具程序,每次单击按钮时,都会在列表中添加一个“Hi”项: import Control.Monad import Control.Monad.State import qualified Graphics.UI.Threepenny as UI import Graphics.UI.Threepenny.Core hiding (get) main :: IO () main = startGUI defaultConfig setup setup :: Window -> UI () setup w = void $ do return w # set title "Ciao" buttonAndList <- mkButtonAndList getBody w #+ map element buttonAndList mkButtonAndList :: UI [Element] mkButtonAndList = do myButton <- UI.button # set text "Click me!" myList <- UI.ul on UI.click myButton $ \_ -> element myList #+ [UI.li # set text "Hi"]
  • React Formik bind the external button click with onSubmit function in <Formik>
    I'm trying to submit the form by using the external buttons which are located outside of <Form> or <Formik> tags As shown in the following screenshot, my button is in Bootstrap > Modal Footer section and they are outside of form tag. I'm trying to submit the form when the user clicks on the Submit button. Please see the similar code as the following. I uploaded it onto CodeSandbox. function App() { return ( <div className="App"> <Formik initialValues={{ date: '10/03/2019', workoutType: "Running", calories: 300 }} onSubmit={values => { console.log(values); }} render={({ values }) => { return (
  • App Engine-为什么会有PhoneNumber,Link,Rating等类?(App Engine - why are there PhoneNumber, Link, Rating etc classes?)
    问题 我还没有发现存在某些App Engine类的任何原因。 有一个电话号码,一个链接,一个邮政地址,一个GeoPt,一个评分等。为什么要给予这些特殊待遇? 他们似乎没有任何智慧-例如地理搜索。 我知道Link比String属性具有更多的空间,但是其余的空间呢? 请参阅:http://code.google.com/appengine/docs/java/datastore/dataclasses.html 回答1 这些类型是“语义”类型。 它们存在于Java API中,以与Python API保持一致。 在Python API中,它们针对.to_xml()方法定义了特殊的行为-例如,PhoneNumberProperty的序列化如下: <property name="foo" type="gd:phonenumber"><gd:phoneNumber>12345-678</gd:phoneNumber></property> 回答2 我认为它们只不过是用来解决常见问题并节省开发人员时间的。 如果很多应用程序都使用电话号码字段,为什么要求每个开发人员都必须编写它们? 如果需要/愿意,开发人员仍然可以编写自己的代码。 回答3 不确定Java,但在python中,以下模型/代码(在开发服务器上进行了测试)将引发BadValueError,并显示消息“无效的URL
  • 我可以使用 ngModelController 的 $formatter 来完全控制输入字段的呈现方式吗?(Can I use ngModelController's $formatter to fully control how an input field is rendered?)
    问题 我正在尝试制作一个模拟type="number"的输入,但我想向其中添加我自己的按钮。 基本上我已经做了 <form name="fasdf"> <button class="btn" ng-click="decrement()">◄</button> <input type="text" ng-model="model" display-as-number /> <button class="btn" ng-click="increment()">►</button> </form> 我使用input type="text"因为我不希望用户代理将它自己的按钮添加到字段中。 应该可以使用input本身来输入值以及使用按钮来增加或减少值。 angular.module('app',[]) .controller('Ctrl', ['$scope', function($scope) { $scope.model = 0; $scope.decrement = function() { $scope.model--; }; $scope.increment = function() { $scope.model++; }; }]) 该值最初为0但是当用户开始输入文本时,我希望在他们键入时删除任何前导零(嗯,实际上西装想要那个,但你明白我的意思)。 我的理论是,我可以使用
  • Can I use ngModelController's $formatter to fully control how an input field is rendered?
    I am trying to make an input that simulates type="number" but I want to add my own buttons to it. Basically I've made <form name="fasdf"> <button class="btn" ng-click="decrement()">◄</button> <input type="text" ng-model="model" display-as-number /> <button class="btn" ng-click="increment()">►</button> </form> I'm using input type="text" because I don't want the user agent to add it's own buttons to the field. It should be possible to use the input itself to enter a value as well as using the buttons to increment or decrement the value. angular.module('app',[]) .controller('Ctrl', ['$scope'
  • ASP MVC Razor在输入占位符中编码特殊字符(ASP MVC Razor encode special characters in input placeholder)
    问题 这是我的代码: 模型: [Required] [DataType(DataType.Text)] [Display(Name = "Your company's name")] public string CompanyName { get; set; } 看法: @Html.TextBoxFor(m => m.CompanyName, new { @class = "account-input", @placeholder = @Html.DisplayNameFor(m => m.CompanyName), @id = "companyname" }) 它将像这样渲染: 您公司的名称 html输出: <input class="account-input" data-val="true" data-val-required="The Your company's name field is required." id="companyname" name="CompanyName" placeholder="Your company&#39;s name" type="text" value=""> 它应该看起来像这样: 贵公司的名字 为什么文本显示不正确?如何防止这种情况? 我已经尝试过了: @Html.TextBoxFor(m => m.CompanyName
  • 从C#中的继承类转换数据类型(Convert data type from inherited classes in C#)
    问题 我正在尝试了解我的统一项目的继承,但似乎发现了对我的设置的限制。 由于我仍在学习正确地理解C#,因此在编写它时感到困惑。 我有一组继承的类,并且它们基于两种不同的行为进行拆分,因此我有正确的引用。 然后,我需要强制转换它们,以便可以访问这些类之一中的方法。 所以我的结构看起来像这样: public class Behaviour : Position { public Handler reference; public Behaviour(int tx, int ty, Handler refer) : base (tx,ty){ reference = refer; } // overload public Behaviour(int tx, int ty) : base (tx,ty){} } public class Behaviour2 : Position { public SettingsHandler reference; public Behaviour2(int tx, int ty, SettingsHandler refer) : base (tx,ty) { reference = refer; } } public class SettingsHandler : Handler { public Settings level {get;set;} }
  • 尝试在 Three.js 中为立方体着色(Trying to color a cube in Three.js)
    问题 我正在尝试用 3 种不同颜色在three.js 中为立方体着色,但似乎我对可以添加到场景中的 THREE.DirectionalLight 对象的数量达到了上限。 在文档中,我没有看到任何提到这样的限制,所以我想知道这是真的还是我遗漏了其他东西? http://jsfiddle.net/ZMwfc/ var renderer = new THREE.WebGLRenderer(); renderer.setSize( 800, 600 ); document.body.appendChild( renderer.domElement ); var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 35, // Field of view 800 / 600, // Aspect ratio 0.1, // Near plane 10000 // Far plane ); camera.position.set( -15, 10, 10 ); camera.lookAt( scene.position ); scene.add( camera ); var cube = new THREE.Mesh( new THREE.CubeGeometry( 5, 5, 5 ), new THREE
  • 尝试在 Three.js 中为立方体着色(Trying to color a cube in Three.js)
    问题 我正在尝试用 3 种不同颜色在three.js 中为立方体着色,但似乎我对可以添加到场景中的 THREE.DirectionalLight 对象的数量达到了上限。 在文档中,我没有看到任何提到这样的限制,所以我想知道这是真的还是我遗漏了其他东西? http://jsfiddle.net/ZMwfc/ var renderer = new THREE.WebGLRenderer(); renderer.setSize( 800, 600 ); document.body.appendChild( renderer.domElement ); var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 35, // Field of view 800 / 600, // Aspect ratio 0.1, // Near plane 10000 // Far plane ); camera.position.set( -15, 10, 10 ); camera.lookAt( scene.position ); scene.add( camera ); var cube = new THREE.Mesh( new THREE.CubeGeometry( 5, 5, 5 ), new THREE
  • Java:对于每个循环,扩展对象的迭代(Java: For each loop , Iteration over extended objects)
    问题 我的问题可能很简单, 我有一个带有一些内部字段、setter 和 getter 的类Result 。 此外,我有类Special1Result ,它扩展了Result并包含更多的字段和带有更多数据的Special2Result 。 在不同的类Dispatcher ,我编写了以下方法: processResults(List<? extends Result> results) ,它只熟悉Result (我需要这个方法来查询扩展 Result 对象中是否有特定字段 - 我正在使用注释)。 所以我决定使用扩展的 for-each 循环: for (Result res : results) {} 那么我的问题是什么? 我试图在网上找到如何为扩展对象编写这个 for 循环,例如像这样的for (? extends Results res: results){} 是否有可能? 正确的写法是怎样的? 回答1 我试图在网上找到如何为扩展对象编写这个 for 循环,例如这样的东西 for (? extends Results res: results){} 不,这是不可能的:您不能静态键入在运行时动态提供的项目。 正确的写法是怎样的? 你已经在这样做了: for (Results res: results) { } 如果您想在该循环中测试Special2Result ,您可以这样做
  • 设置 __Renderings 字段未在 Sitecore 结果中共享?(Setting __Renderings field not shared in Sitecore consequences?)
    问题 有没有人有将 Sitecore 中的__Renderings字段设置为不共享的经验? 我们正在构建一个多站点多语言解决方案,并且需要不同语言的(子)布局不同。 例如,英语站点可能具有相同项目的瑞典语版本所没有的子布局,并且所有演示组件对于不同语言并不总是具有相同的数据源。 一个比较简单的解决方案是在/sitecore/templates/System/Templates/Sections/Layout template中的__Renderings字段上简单地取消选中“共享”,但这是否有任何其他后果? 或者有没有更好的方法来处理这个要求? 回答1 当需要根据语言、原籍国等交换视觉元素时,我自己的偏好是使用 Sitecore 的个性化规则编辑来交换数据源并以这种方式更改演示文稿。 它不涉及更改 Sitecore 的默认行为,并允许您利用内置的 Sitecore 功能。 如果您的不同“子布局”实际上只是通过各种个性化规则引入的数据源,您可以使用 OMS/DMS 配置所有这些,并依靠 Sitecore 引擎在给定当前状态的情况下呈现您需要的组件。 对于性能,使用最新版本的 DMS 可能是最好的(我相信 6.5 Update 5 现在是推荐的版本)。 回答2 以这种方式修改 Sitecore 的默认行为通常不是一个好主意。 对于将来可能使用该系统的其他人来说,它是不透明的
  • Lift webapp has directory and resource with the same name, but gives 302
    I deployed example.war to Tomcat 6.0.32 (latest at time of writing), and the deployed webapp contains the following: $ find example | egrep -v "WEB-INF/lib|WEB-INF/classes" example example/_items.html example/_share_link.html example/all_items.html example/images example/images/ajax-loader.gif example/index.html example/item example/item/star.html example/item.html example/js example/js/c-jquery-1.4.2.js example/js/c-jquery-ui-1.8.2.js example/js/jquery-1.4.2.js example/js/jquery-1.4.4.min.js example/js/jquery-ui-1.8.2.js example/js/jquery-ui-1.8.8.custom.min.js example/js/jquery.blockUI.js
  • 在MVC 3视图模型上使用Editable属性(Using Editable attribute on MVC 3 view model)
    问题 我希望使用属性将视图模型属性标记为只读,以便在渲染的视图中仅读取视图字段。 应用System.ComponentModel.DataAnnotations.EditableAttribute似乎是我需要的确切属性,但它似乎无法正常工作,即文本框字段仍可编辑。 我四处张望,找不到答案,只有几个相关的问题。 渲染视图时,下面应用的editable属性不起作用。 [Display(Name = "Last Name")] [Editable(false, AllowInitialValue = true)] public string LastName { get; set; } 我可以使用这样的视图帮助器函数来实现只读行为,但我的偏爱是在model属性上使用属性。 @functions { object getHtmlAttributes() { if (@ViewBag.Mode == "Edit") { return new {style = "width:100px;background:#ff6;", @readonly = "readonly"}; } return new { style = "width:100px;" }; } } @Html.TextBoxFor(model => model.FirstName, getHtmlAttributes())
  • 具有行为和 ORM 的丰富领域模型(Rich domain model with behaviours and ORM)
    问题 在观看了 Jimmy Bogard (http://ndcoslo.oktaset.com/Agenda) 的 NDC12 演示文稿“制作邪恶的域模型”后,我一直在徘徊如何坚持这种域模型。 这是演示文稿中的示例类: public class Member { List<Offer> _offers; public Member(string firstName, string lastName) { FirstName = firstName; LastName = lastName; _offers = new List<Offer>(); } public string FirstName { get; set; } public string LastName { get; set; } public IEnumerable<Offer> AssignedOffers { get { return _offers; } } public int NumberOfOffers { get; private set; } public Offer AssignOffer(OfferType offerType, IOfferValueCalc valueCalc) { var value = valueCalc.CalculateValue(this, offerType)
  • Qt QOpenGLWidget wheelEvent 奇怪的行为(Qt QOpenGLWidget wheelEvent strange behaviour)
    问题 我有以下课程: class Curve2DOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core { Q_OBJECT public: Curve2DOpenGLWidget( QWidget* parent = nullptr ); ~Curve2DOpenGLWidget(); void initializeGL() override; void resizeGL(int width, int height) override; void paintGL() override; void NativePaintGL(); protected: void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void wheelEvent(QWheelEvent *event) override; }; 我想使用wheelEvent 在我的场景中放大/缩小。 这是代码: void Curve2DOpenGLWidget::wheelEvent(