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/
当然,在窗口
上,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);
这段代码是用户端.底部
,加数据控制器小部件(addDataControllerWidget)
是使用UDA
创建UI
并拼接起来的必要
的事件处理器
.
第一,构上的@Container
,UDA
允许定义布局
.如果没有该布局
,它就用给定父控件
的默认容器
(在此窗口中,垂直排列子控件
).
工作原理
是按模板参数
覆盖类名和/或风格
,然后把串名和子项列表
作为其他参数
,可任意改造树
.
然后,构内部,有普通方法和数据成员
,但又有额外的UDA
.因为它是枚举,Algorithm
有默认的组件(下拉式
选取器).
我用@控件由!按钮(@ControlledBy!Button)
代码覆盖
了方法的默认值
,指示按钮
小部件应触发
此调用.在此,按模板参数
再次传递
一个类,然后传递其构造器的一些参数
.注意,没有传递parent
参数,稍后调用添加数据控制器小部件(addDataControllerWidget)
会处理.类似,没有设置事件处理器
,因为稍后
库会设置它.
小部件
位置当前与名字关联
.叫"volume"
的Container
接收小部件
的体积
变量.由于其他
文件没有指定位置
,因此位于"默认
"容器中(或如果未指定
默认值,就使用最后
).
未来发展
方向是从静态反射
中提取
越来越多的数据,并在自动默认
不充分时,使其容易自定义
.
小提示
:
Container!(Style.maxWidth(32))
是特例.我没有定义类,而是给予列举了我想在模板基类
上覆盖的各个方法
的一个列表.风格只是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() {}
}
可用调用操作(opCall)
重载,但这表明改造
所有的旧类.(哦,我希望static opCall(this This)()
工作).
所以添加了外部项
,容器(Container)和控制由(ControlledBy)
,但保持了相同的调用操作
接口.有趣的是,也可在过程代码中新建容器(new Container!(...))!(...)
,及潜在
地在更多
环境中重用
它.
静态调用操作(static opCall)
返回ContainerMeta
.这里没有模板
,所有运行时数据
都是在编译时
创建的.可用简单
可变函数语法
创建树,并在稍后处理它.不值得创建完整编译时布局器
,使用运行时
数据表,让我重用
现有代码,并可能用(如UI
设计器工具)运行时
文件和脚本
语言链接
起来.
一个开放
问题是,不用设置
数据值,如何改变UI
,及反之.目前,UI
可改变构,但构不能改变UI
.我正在考虑使DataControllerWidget
接口,在代码
中提供它,及手动
属性来额外
定制其他勾挂
.
D在GUI
方面的真实的潜力并不在于实现底层原语和小部件
,而是在于利用D的内省功能
来创建新的方便的API
.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现