最近做了一个小工具,需要动态创建多个控件,为了方便控件展示,还需要根据窗口尺寸自动分布显示。
这里把这个过程记录下来,中间涉及到的知识点有:
动态创建控件、组件
批量访问动态控件
控件网格布局排版
控件匹配不同DPI屏幕显示
控件容器使用滚动条
动图示意如下:
import win.ui;
import fonts.fontAwesome;
/*DSG{{*/
var winform = win.form(text="动态控件网格布局";right=783;bottom=479)
winform.add(
custom={cls="custom";text="自定义控件";left=16;top=16;right=768;bottom=236;ah=1;aw=1;bgcolor=12639424;border=1;dl=1;dr=1;dt=1;z=1};
custom2={cls="custom";text="自定义控件";left=16;top=248;right=768;bottom=468;ah=1;aw=1;bgcolor=15780518;border=1;db=1;dl=1;dr=1;z=2}
)
/*}}*/
//aardio批量创建动态控件实例,网格布局实例
//https://blog.csdn.net/wuyindesign/article/details/135631340
//创建网格布局
function createGridLayout(container/*容器控件*/, itemCode/*项目代码*/, itemCount/*项目总数*/, itemWidth/*项目宽度*/, itemHeight/*项目高度*/, margin/*项目到容器的边距*/, hgap/*项目间的水平间距*/, vgap/*项目间的垂直间距*/, fillWidth/*单列横向填充*/){
//适配DPI
var _, _, dpiScaleX, dpiScaleY = container.getScale();
itemWidth *= dpiScaleX;
itemHeight *= dpiScaleY;
margin *= dpiScaleX;
hgap *= dpiScaleX;
vgap *= dpiScaleX;
//保存布局选项
var layout = {};
layout.type = "grid";
layout.margin = margin;
layout.hgap = hgap;
layout.vgap = vgap;
layout.fillWidth = fillWidth : false; //是否横向填充
layout.itemHeight = itemHeight;
if (!layout.fillWidth) {
layout.itemWidth = itemWidth;
}
else { //横向填充模式
layout.itemWidth = container.width - margin * 2;
}
container.layout = layout;
//创建滚动条
import win.ui.scrollbar;
container.scrollbar = win.ui.scrollbar(container, true);
//动态生成控件
for (i=1; itemCount; 1){
var item = container.addCtrl(
["item"+i] = {cls="custom";left=0;top=0;right=itemWidth;bottom=itemHeight;dl=1;dt=1;hide=1;z=1}; //默认为隐藏状态
);
container["item"+i].index = i;
container["item"+i].addCtrl(table.clone(itemCode));
//响应事件
container["item"+i].onMouseClick = function(wParam,lParam){
winform.msgbox(container["item"+i].name.text)
}
}
//自动布局
setGridLayout(container);
}
//返回容器中所有的item
function getLayoutItems(container){
var items = {};
for (name, ctrl in container.eachControl("custom","item")){
items[ctrl.index] = ctrl;
}
return items;
}
//设置布局
function setGridLayout(container/*容器控件*/){
var _, _, dpiScaleX, dpiScaleY = container.getScale(); //适配DPI
//读取布局选项
var layout = container.layout;
var margin = layout.margin * dpiScaleX;
var hgap = layout.hgap * dpiScaleX;
var vgap = layout.vgap * dpiScaleX;
var itemHeight = layout.itemHeight * dpiScaleY;
var itemWidth = layout.itemWidth * dpiScaleX;
if (layout.fillWidth) {
itemWidth = container.width - margin * 2;
}
//遍历容器中的item
var items = getLayoutItems(container);
var itemCount = #items;
//计算一行最多显示多少个item(列数)
var colNum = 1; //最少1列,横向填充模式也是1列
if (!layout.fillWidth) {
colNum = math.floor((container.width - margin*2 + hgap)/(itemWidth + hgap)) : 1;
}
//判断是否显示滚动条
var listHeight = (itemHeight + vgap) * math.ceil(itemCount / colNum) - vgap + margin * 2; //计算item列表的总高度
if (container.scrollbar) {
container.scrollbar.show(listHeight > container.height);
//当布局类型为横向填充,且出现滚动条时,缩小item宽度,避让滚动条
if (layout.fillWidth && listHeight > container.height) {
itemWidth = itemWidth - User32.GetSystemMetrics(2/*_SM_CXVSCROLL*/);
}
}
//第一列item的起始点
var marginLeft = margin;
//动态调整item尺寸和位置
var itemLeft = marginLeft;
var itemTop = margin;
var itemRight = itemLeft + itemWidth;
var itemBottom = itemTop + itemHeight;
for (i=1; itemCount; 1){
items[i].left = itemLeft;
items[i].top = itemTop;
items[i].right = itemRight;
items[i].bottom = itemBottom;
items[i].hide = false;
//计算下一个item的位置
itemLeft = itemRight + hgap;
itemRight = itemLeft + itemWidth;
if (i % colNum == 0){
itemLeft = marginLeft; //超出一行最大显示个数,left回到起始点
itemRight = itemLeft + itemWidth;
itemTop = itemBottom + vgap;
itemBottom = itemTop + itemHeight;
}
}
}
//动态控件的模板
var itemTemplate = {
icon = {cls="plus";left=0;top=0;right=120;bottom=48;align="left";color=3947580;dl=1;dt=1;iconColor=16711680;iconStyle={font=LOGFONT(h=-48;name='FontAwesome')};iconText='\uF007';paddingBottom=5;paddingLeft=3;paddingRight=3;paddingTop=5;z=2};
name = {cls="static";left=120;top=0;right=360;bottom=28;dl=1;dt=1;font=LOGFONT(h=-16);transparent=1;z=3};
status = {cls="static";left=120;top=28;right=360;bottom=48;color=8421504;font=LOGFONT(h=-11);dl=1;dt=1;transparent=1;z=4};
}
//创建第一个表格布局
var itemCount = 5; //item总数
var itemWidth, itemHeight = 360, 48; //item宽度/高度
var margin = 8; //item到容器间的距离
var hgap, vgap = 15, 10; //item之间的横间距/竖间距
createGridLayout(winform.custom, itemTemplate, itemCount, itemWidth, itemHeight, margin, hgap, vgap);
//修改每个item的内容
var layoutItems = getLayoutItems(winform.custom);
for(i=1; #layoutItems; 1){
layoutItems[i].name.text = "客户名称"+i;
layoutItems[i].status.text = ">> 这里是简介信息"+i;
}
//创建第二个表格布局,横向填充模式
//修改控件模板
var itemTemplate2 = table.clone(itemTemplate);
itemTemplate2["listview"] = {cls="listview";border=1;left=0;top=48;right=800;bottom=120;aw=1;dl=1;dt=1;fullRow=1;transparent=1;z=5};
createGridLayout(winform.custom2, itemTemplate2, 2, 800, 120, margin, hgap, vgap, true);
//修改每个item的内容
var layoutItems2 = getLayoutItems(winform.custom2);
for(i=1; #layoutItems2; 1){
layoutItems2[i].name.text = "客户名称"+i;
layoutItems2[i].status.text = ">> 这里是简介信息";
layoutItems2[i].listview.setColumns({"姓名";"性别";"年龄"})
layoutItems2[i].listview.items = {{"111";"222";"333"};{"111";"222";"333"}};
}
//窗体缩放的时,自动重新布局
winform.adjust = function( cx,cy,wParam ) {
for(name,ctrl in winform.eachControl("custom") ){
if (ctrl.layout){
setGridLayout(ctrl);
}
}
};
winform.show();
win.loopMessage();