• d中声明式gui


    原文
    几个月前,我用D展示了白噪声应用并用了一点,但后来想添加其他噪声颜色和图界.
    我在网上搜索了些代码来复制/粘贴噪音(并找到了以下代码:https://noisehack.com/generate-noise-web-audio-api/,D的一个优点是它很容易从其他语言移植代码.复制/粘贴,js几乎可在D中工作,
    并且很容易用minigui.d界面加东西.
    但是,当输入代码来实例化类,并附加事件监听器时,我想使它更自动一些.

    用户端

    所有这些都是预发布,如有更改,恕不通知.
    下面是完整程序(依赖于arsd git master)

    import arsd.simpleaudio;
    import arsd.minigui;
    import std.random;
    
    void main() {
        auto window = new MainWindow("Noise App");
    
        auto ao = AudioOutputThread(true);
    
        enum Algorithm {
            brown,
            pink,
            white
        }
    
        @Container!HorizontalLayout(
            Container!VerticalLayout("default"),
            Container!(Style.maxWidth(32))("volume")
        )
        struct Control {
            private bool paused;
    
            Algorithm algorithm;
    
            @ControlledBy!Button("Start / Stop")
            void pause() {
                if(paused)
                    ao.unpause();
                else
                    ao.pause();
                paused = !paused;
            }
    
            @ControlledBy!VerticalSlider(0, 32000, 800)
            int volume = 3200; // really a short
        }
    
        Control control;
    
        window.addDataControllerWidget(&control);
    
        // 粉红
        float b0 = 0.0, b1 = 0.0, b2 = 0.0, b3 = 0.0, b4 = 0.0, b5 = 0.0, b6 = 0.0;
    
        // 棕色
        float lastOut = 0.0;
    
        ao.addChannel = delegate(short[] buffer) {
            const algorithm = control.algorithm;
            const volume = control.volume;
            foreach(ref item; buffer) {
                final switch(algorithm) with(Algorithm) {
                case white:
                    item = cast(short) uniform(-volume, volume);
                    break;
    
                case pink:
                    float white = uniform(-1.0, 1.0);
                    b0 = 0.99886 * b0 + white * 0.0555179;
                    b1 = 0.99332 * b1 + white * 0.0750759;
                    b2 = 0.96900 * b2 + white * 0.1538520;
                    b3 = 0.86650 * b3 + white * 0.3104856;
                    b4 = 0.55000 * b4 + white * 0.5329522;
                    b5 = -0.7616 * b5 - white * 0.0168980;
                    auto output = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362;
                    output *= 0.11;//(粗略)补偿增益
                    b6 = white * 0.115926;
    
                    item = cast(short) (output * volume);
                    break;
    
                case brown:
                    float white = uniform(-1.0, 1.0);
                    float output = (lastOut + (0.02 * white)) / 1.02;
                    lastOut = output;
                    output *= 3.5; //(粗略)补偿增益
    
                    item = cast(short) (output * volume);
                    break;
                }
            }
            return true;
        };
    
        window.loop();
    }
    
    // https://noisehack.com/generate-noise-web-audio-api/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    当然,在窗口上,minigui使用本地控件,所以它就像它们一样.
    现在,更深入研究代码.

    @Container!HorizontalLayout(
        Container!VerticalLayout("default"),
        Container!(Style.maxWidth(32))("volume")
    )
    struct Control {
        Algorithm algorithm;
    
        @ControlledBy!Button("Start / Stop")
        void pause() {}
    
        @ControlledBy!VerticalSlider(0, 32000, 800)
        int volume = 3200;
    }
    
    Control control;
    
    window.addDataControllerWidget(&control);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    这段代码是用户端.底部,加数据控制器小部件(addDataControllerWidget)是使用UDA创建UI并拼接起来的必要事件处理器.
    第一,构上的@Container,UDA允许定义布局.如果没有该布局,它就用给定父控件默认容器(在此窗口中,垂直排列子控件).
    工作原理是按模板参数覆盖类名和/或风格,然后把串名和子项列表作为其他参数,可任意改造.
    然后,构内部,有普通方法和数据成员,但又有额外的UDA.因为它是枚举,Algorithm有默认的组件(下拉式选取器).
    我用@控件由!按钮(@ControlledBy!Button)代码覆盖了方法的默认值,指示按钮小部件应触发此调用.在此,按模板参数再次传递一个类,然后传递其构造器的一些参数.注意,没有传递parent参数,稍后调用添加数据控制器小部件(addDataControllerWidget)会处理.类似,没有设置事件处理器,因为稍后库会设置它.
    小部件位置当前与名字关联.叫"volume"Container接收小部件体积变量.由于其他文件没有指定位置,因此位于"默认"容器中(或如果未指定默认值,就使用最后).
    未来发展方向是从静态反射提取越来越多的数据,并在自动默认不充分时,使其容易自定义.
    小提示:

    Container!(Style.maxWidth(32))
    
    • 1

    是特例.我没有定义类,而是给予列举了我想在模板基类上覆盖的各个方法的一个列表.风格只是opDispatch构,产生稍后用来插件的方法.
    不应用虚函数来处理.匿名嵌套类,script.d子类和其他各种技巧就够了,但仍然假设每个类都有些合适的静态值,一般是正确的,但并不总是正确的.而且它限制了像运行时加载css等.
    内部,该覆盖列表用来按需生成新类.

    内部

    至少在早期阶段,实现是相当简单的.
    一般想法是UDA分解为简单的运行时构:UI定义表和类工厂函数.复杂工作由处理这些数据普通运行时函数来完成.,也可在运行时数据定义中使用这些工具.(minigui应该既是小库,又允许用少量代码轻松添加gui特性),并且可透明生成并使用附加工厂.
    数据绑定也是自动生成的,同时自动注册必要事件.目前按传统工作:它根据识别小部件设置事件,根据识别类型设置值.需要以后扩展.

    深入了解一下代码.
    加数据控制器小部件(addDataControllerWidget)是个只是数据控制器小部件模板(DataControllerWidget)UFCS函数.它是接受某个数据构父小部件指针的Widget的子类(稍后会添加一些其他接口).它检查指针类型,来提取注释构建数据树.
    控制由(ControlledBy)也是造拥有工厂(私有构建(construct)方法)和参数(构成员)的ControlledBy_构的工厂函数.
    更复杂的是容器(Container).它是继承给定基类,插件进给定类,然后定义调用操作(opCall)模板类.在UDA中调用opCall来返回包括实例化完整容器类的工厂函数指针的静态数据.
    当然可用不同方法来实现该点.开始想法是按UDA,附加类自身,如:

    @VerticalLayout
    struct Control {
        @Button
        void pause() {}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可用调用操作(opCall)重载,但这表明改造所有的旧类.(哦,我希望static opCall(this This)()工作).
    所以添加了外部项,容器(Container)和控制由(ControlledBy),但保持了相同的调用操作接口.有趣的是,也可在过程代码中新建容器(new Container!(...))!(...),及潜在地在更多环境中重用它.
    静态调用操作(static opCall)返回ContainerMeta.这里没有模板,所有运行时数据都是在编译时创建的.可用简单可变函数语法创建树,并在稍后处理它.不值得创建完整编译时布局器,使用运行时数据表,让我重用现有代码,并可能用(如UI设计器工具)运行时文件和脚本语言链接起来.
    一个开放问题是,不用设置数据值,如何改变UI,及反之.目前,UI可改变构,但构不能改变UI.我正在考虑使DataControllerWidget接口,在代码中提供它,及手动属性来额外定制其他勾挂.
    D在GUI方面的真实的潜力并不在于实现底层原语和小部件,而是在于利用D的内省功能来创建新的方便的API.

  • 相关阅读:
    10 Using Implicit Rules
    35 机器学习(三):混淆矩阵|朴素贝叶斯|决策树|随机森林
    Python 爬虫篇#笔记02# | 网页请求原理 和 抓取网页数据
    windows系统安装openssl并且转换证书格式
    Windows 安装 MariaDB 数据库
    车载高速CAN(HighSpeed CAN)通信之CAN Bus Off
    shiro的过滤器和权限控制
    远程开户身份证识别OCR技术:革新传统流程,实现高效身份验证
    【毕业设计】31-基于单片机的农业蔬菜大棚温度自动控制系统设计(原理图工程+源码工程+仿真工程+答辩论文+答辩PPT)
    基于SDN环境下的DDoS异常攻击的检测与缓解--实验
  • 原文地址:https://blog.csdn.net/fqbqrr/article/details/127764587