gdip 绘制主从关系节点图

mndsoft 2月前 358

最近在研究使用  aardio如何实现一个以前用VB做的节点从属关系的图,实现如下图功能。

gdi GDI绘图库需要慢慢研究,弄了简单示例,还不支持拖动,信息提示。而且还闪烁,让AI也没有解决,看来绘图有点难度哈。希望高手建言,学习。

也在研究 光庆大师的 画板 paint库,这个感觉比较全面,实现这个功能应该没问题,慢慢研究学习。

还有目前还不熟悉 aardio 使用 ActiveX 这些ocx库,接下来也研究下,如果可以,其实使用这个 Xtreme SuitePro ActiveX  的界面库中的 FlowGraph 组件也不错。下面这个图就是这个OCX的示例,这个组件的官网地址:https://codejock.com/products/suitepro/?2yn6s14z=p1z ,感兴趣的可以看看。

这个是Xtreme SuitePro ActiveX  的界面库中的 FlowGraph 组件的示例:


这个是 aardio弄得简单节点图:

import win.ui;
import gdip;

/*DSG{{*/
var winform = win.form(text="节点关系图";right=759;bottom=469)
winform.add(
btnAddMain={cls="button";text="添加主节点";left=588;top=16;right=716;bottom=55;z=1};
btnAddSub={cls="button";text="添加从属节点";left=588;top=88;right=716;bottom=127;z=2}
)
/*}}*/

var nodes = {};
var mainNode = null;
var draggingNode = null;

class Node {
    ctor(x, y, text, isMain = false) {
        this.x = x;
        this.y = y;
        this.text = text;
        this.children = {};
        this.isMain = isMain;
    }
}

function drawNodes(graphics) {
    var backgroundBrush = gdip.solidBrush(0xFFFFFFFF);
    graphics.fillRectangle(backgroundBrush, 0, 0, winform.width, winform.height);
    
    for(i=1; #nodes) {
        var node = nodes[i];
        var brush = node.isMain ? gdip.solidBrush(0xFFFF0000) : gdip.solidBrush(0xFF0000FF);
        graphics.fillEllipse(brush, node.x-25, node.y-25, 50, 50);
        
        var family = gdip.family("宋体");
        var font = family.createFont(15, 0/*_GdipFontStyleRegular*/, 2/*_GdipUnitPixel*/);
        var format = gdip.stringformat();
        format.align = 1;
        format.lineAlign = 1;
        graphics.drawString(node.text, font, gdip.RECTF(node.x-25, node.y-25, 50, 50), format, gdip.solidBrush(0xFFFFFFFF));
        
        if(node.isMain) {
            for(j=1; #node.children) {
                var child = node.children[j];
                var pen = gdip.pen(0xFF000000, 2);
                graphics.drawCurve(pen,
                    node.x, node.y,
                    (node.x + child.x)/2, node.y,
                    (node.x + child.x)/2, child.y,
                    child.x, child.y
                );
            }
        }
    }
}

winform.btnAddMain.oncommand = function(id,event){
    if(mainNode === null) {
        mainNode = Node(300, 200, "主节点", true);
        table.push(nodes, mainNode);
        
        var graphics = gdip.graphics(winform);
        graphics.smoothingMode = 4/*_GdipSmoothingModeAntiAlias*/;
        drawNodes(graphics);
        
       // win.msgbox("已添加主节点,节点总数:" ++ tostring(#nodes));
    } else {
        win.msgbox("已存在主节点!");
    }
}

winform.btnAddSub.oncommand = function(id,event){
    if(mainNode === null) {
        win.msgbox("请先添加主节点!");
        return;
    }
    var x = math.random(100, 500);
    var y = math.random(100, 300);
    var newNode = Node(x, y, "节点" ++ tostring(#nodes + 1));
    table.push(nodes, newNode);
    table.push(mainNode.children, newNode);

    var graphics = gdip.graphics(winform);
    graphics.smoothingMode = 4/*_GdipSmoothingModeAntiAlias*/;
    drawNodes(graphics);
    
   // win.msgbox("已添加从属节点,节点总数:" ++ tostring(#nodes));
}

winform.wndproc = function(hwnd,message,wParam,lParam){
    select(message) {
        case 0x201/*_WM_LBUTTONDOWN*/ {
            var x, y = win.getMessagePos(lParam);
            for(i=1; #nodes) {
                if((x-nodes[i].x)^2 + (y-nodes[i].y)^2 <= 25^2) {
                    draggingNode = nodes[i];
                    break;
                }
            }
        }
        case 0x202/*_WM_LBUTTONUP*/ {
            draggingNode = null;
        }
        case 0x200/*_WM_MOUSEMOVE*/ {
            if(draggingNode) {
                var x, y = win.getMessagePos(lParam);
                draggingNode.x = x;
                draggingNode.y = y;
                var graphics = gdip.graphics(winform);
                graphics.smoothingMode = 4/*_GdipSmoothingModeAntiAlias*/;
                drawNodes(graphics);
            }
        }
    }
}

winform.onPaint = function(hdc) {
    var graphics = gdip.graphics(winform);
    graphics.smoothingMode = 4/*_GdipSmoothingModeAntiAlias*/;
    drawNodes(graphics);
}

winform.show();
win.loopMessage();


最新回复 (5)
  • 光庆 2月前
    0 2

    画曲线的函数使用不对,所以画出来的线不美观。

    这样改一下试试:

                    graphics.drawBezier(pen,
                        node.x, node.y, 
                        (child.x+node.x)/2, node.y,
                        (child.x+node.x)/2,child.y,
                        child.x, child.y
                    );

  • 光庆 2月前
    0 3

    稍微改了下代码,优化了一下拖动效果:

    import win.ui;
    import gdip;
    /*DSG{{*/
    var winform = win.form(text="节点关系图";right=759;bottom=469)
    winform.add(
    btnAddMain={cls="button";text="添加主节点";left=588;top=16;right=716;bottom=55;z=1};
    btnAddSub={cls="button";text="添加从属节点";left=588;top=88;right=716;bottom=127;z=2}
    )
    /*}}*/
    
    var nodes = {};
    var mainNode = null;
    var draggingNode = null;
    var graphics = gdip.graphics(winform);
    graphics.smoothingMode = 4/*_GdipSmoothingModeAntiAlias*/;
    
    class Node {
        ctor(x, y, text, isMain = false) {
            this.x = x;
            this.y = y;
            this.text = text;
            this.children = {};
            this.isMain = isMain;
            this.rect = ::RECT(x-25,y-25,x+25,y+25);
            this.rectf = ::RECTF(x-25,y-25,50,50);
        }
    }
    
    function drawNodes() {
        var backgroundBrush = gdip.solidBrush(0xFFFFFFFF);
        graphics.fillRectangle(backgroundBrush, 0, 0, winform.width, winform.height);
        
        for(i=1; #nodes) {
            var node = nodes[i];
            var brush = node.isMain ? gdip.solidBrush(0xFFFF0000) : gdip.solidBrush(0xFF0000FF);
            graphics.fillEllipse(brush, node.rect.xywh());
            var family = gdip.family("宋体");
            var font = family.createFont(15, 0/*_GdipFontStyleRegular*/, 2/*_GdipUnitPixel*/);
            var format = gdip.stringformat();
            format.align = 1;
            format.lineAlign = 1;
            graphics.drawString(node.text, font, node.rectf, format, gdip.solidBrush(0xFFFFFFFF));
            if(node.isMain) {
                for(j=1; #node.children) {
                    var child = node.children[j];
                    var pen = gdip.pen(0xFF000000, 2);
                    graphics.drawBezier(pen,
                        node.x+25, node.y, 
                        (child.x+node.x)/2, node.y,
                        (child.x+node.x)/2,child.y,
                        child.x-25, child.y
                    );
                }
            }
        }
    }
    
    winform.btnAddMain.oncommand = function(id,event){
        if(mainNode === null) {
            mainNode = Node(300, 200, "主节点", true);
            table.push(nodes, mainNode);
            drawNodes();
           // win.msgbox("已添加主节点,节点总数:" ++ tostring(#nodes));
        } else {
            win.msgbox("已存在主节点!");
        }
    }
    
    winform.btnAddSub.oncommand = function(id,event){
        if(mainNode === null) {
            win.msgbox("请先添加主节点!");
            return;
        }
        var x = math.random(100, 500);
        var y = math.random(100, 300);
        var newNode = Node(x, y, "节点" ++ tostring(#nodes + 1));
        table.push(nodes, newNode);
        table.push(mainNode.children, newNode);
        drawNodes(graphics);
       // win.msgbox("已添加从属节点,节点总数:" ++ tostring(#nodes));
    }
    
    winform.wndproc = function(hwnd,message,wParam,lParam){
        select(message) {
            case 0x201/*_WM_LBUTTONDOWN*/ {
                draggingNode = null;
                offsetx,offsety=0,0;
                var x, y = win.getMessagePos(lParam);
                for(i=1; #nodes) {
                    if ::PtInRect(nodes[i].rect,x,y){
                        draggingNode = nodes[i];
    		            offsetx,offsety=draggingNode.x-x,draggingNode.y-y;
                        break;
                    }
                }
            }
            case 0x202/*_WM_LBUTTONUP*/ {
                draggingNode = null;
            }
            case 0x200/*_WM_MOUSEMOVE*/ {
                if(draggingNode) {
                    var x, y = win.getMessagePos(lParam);
                    x+=offsetx;
                    y+=offsety;
                    draggingNode.x = x;
                    draggingNode.y = y;
             		draggingNode.rect = ::RECT(x-25,y-25,x+25,y+25);
            		draggingNode.rectf = ::RECTF(x-25,y-25,50,50);
                    drawNodes();
                }
            }
        }
    }
    
    winform.onPaint = function(hdc) {
        drawNodes();
    }
    
    winform.show();
    win.loopMessage();


  • 光庆 2月前
    0 4

  • mndsoft 2月前
    0 5
    帅! 学习! 大师太牛了,正在研究大师的那个 画板库,大师对绘图也有很深的造诣!
  • mndsoft 2月前
    0 6

    大师,我想弄个鼠标悬停到节点是出现 信息提示,但是坐标不知道如何获取,信息显示到窗体外面了,请帮忙看看哈

    import win.ui;
    import gdip;
    import win.ui.tooltip;
    import console
    /*DSG{{*/
    var winform = win.form(text="节点关系图";right=759;bottom=469)
    winform.add(
    btnAddMain={cls="button";text="添加主节点";left=588;top=16;right=716;bottom=55;z=1};
    btnAddSub={cls="button";text="添加从属节点";left=588;top=88;right=716;bottom=127;z=2}
    )
    /*}}*/
    // 创建 tooltip 控件
    var tooltip = win.ui.tooltip(winform);
    
    // 创建跟踪型气泡提示控件
    var balloonTipCtrl = win.ui.tooltip.tracking(winform,false);
    
    var nodes = {};
    var mainNode = null;
    var draggingNode = null;
    var graphics = gdip.graphics(winform);
    graphics.smoothingMode = 4/*_GdipSmoothingModeAntiAlias*/;
    
    class Node {
        ctor(x, y, text, isMain = false) {
            this.x = x;
            this.y = y;
            this.text = text;
            this.children = {};
            this.isMain = isMain;
            this.rect = ::RECT(x-25,y-25,x+25,y+25);
            this.rectf = ::RECTF(x-25,y-25,50,50);
        }
    }
    
    function drawNodes() {
        var backgroundBrush = gdip.solidBrush(0xFFFFFFFF);
        graphics.fillRectangle(backgroundBrush, 0, 0, winform.width, winform.height);
        
        for(i=1; #nodes) {
            var node = nodes[i];
            var brush = node.isMain ? gdip.solidBrush(0xFFFF0000) : gdip.solidBrush(0xFF0000FF);
            graphics.fillEllipse(brush, node.rect.xywh());
            var family = gdip.family("宋体");
            var font = family.createFont(15, 0/*_GdipFontStyleRegular*/, 2/*_GdipUnitPixel*/);
            var format = gdip.stringformat();
            format.align = 1;
            format.lineAlign = 1;
            graphics.drawString(node.text, font, node.rectf, format, gdip.solidBrush(0xFFFFFFFF));
            if(node.isMain) {
                for(j=1; #node.children) {
                    var child = node.children[j];
                    var pen = gdip.pen(0xFF000000, 2);
                    graphics.drawBezier(pen,
                        node.x+25, node.y, 
                        (child.x+node.x)/2, node.y,
                        (child.x+node.x)/2,child.y,
                        child.x-25, child.y
                    );
                }
            }
        }
    }
    
    winform.btnAddMain.oncommand = function(id,event){
        if(mainNode === null) {
            mainNode = Node(300, 200, "主节点", true);
            table.push(nodes, mainNode);
            drawNodes();
           // win.msgbox("已添加主节点,节点总数:" ++ tostring(#nodes));
        } else {
            win.msgbox("已存在主节点!");
        }
    }
    
    winform.btnAddSub.oncommand = function(id,event){
        if(mainNode === null) {
            win.msgbox("请先添加主节点!");
            return;
        }
        var x = math.random(100, 500);
        var y = math.random(100, 300);
        var newNode = Node(x, y, "节点" ++ tostring(#nodes + 1));
        table.push(nodes, newNode);
        table.push(mainNode.children, newNode);
        drawNodes(graphics);
       // win.msgbox("已添加从属节点,节点总数:" ++ tostring(#nodes));
    }
    
    winform.wndproc = function(hwnd,message,wParam,lParam){
        select(message) {
            case 0x201/*_WM_LBUTTONDOWN*/ {
                draggingNode = null;
                offsetx,offsety=0,0;
                var x, y = win.getMessagePos(lParam);
                for(i=1; #nodes) {
                    if ::PtInRect(nodes[i].rect,x,y){
                        draggingNode = nodes[i];
                        offsetx,offsety=draggingNode.x-x,draggingNode.y-y;
                        break;
                    }
                }
            }
            case 0x202/*_WM_LBUTTONUP*/ {
                draggingNode = null;
            }
            case 0x200/*_WM_MOUSEMOVE*/ {   //鼠标悬停信息显示 
                if(draggingNode) {
                    var x, y = win.getMessagePos(lParam);
                    x+=offsetx;
                    y+=offsety;
                    draggingNode.x = x;
                    draggingNode.y = y;
                     draggingNode.rect = ::RECT(x-25,y-25,x+25,y+25);
                    draggingNode.rectf = ::RECTF(x-25,y-25,50,50);
                    drawNodes();
                } else {
                
                    var x, y = win.getMessagePos(lParam);
                    var hoveredNode = null;
                    for(i=1; #nodes) {
                        if ::PtInRect(nodes[i].rect,x,y){
                            hoveredNode = nodes[i];
                            break;
                        }
                    }
                    
                    if(hoveredNode) {
                        var info = hoveredNode.isMain ? "主节点" : "从属节点";
                        tooltip.setText(hoveredNode.text + "\n类型: " + info);
                        
                        // 使用节点矩形的右下角作为 tooltip 的位置
                        var screenX, screenY = win.toScreen(winform.hwnd, hoveredNode.rect.right, hoveredNode.rect.bottom);
                        
                        // 显示 tooltip,稍微偏移一点以避免遮挡节点
                        tooltip.trackPopup(screenX + 5, screenY + 5);
                    }
                    else {
                        tooltip.trackPopup(); // 隐藏 tooltip
                    }
                }
            }
        }
    }
    
    
    winform.onPaint = function(hdc) {
        drawNodes();
    }
    
    winform.show();
    win.loopMessage();


返回