窗口靠边吸附的效果dock

zhhyit 2月前 688

搬运与大家分享

使用方法:复制后保存成dock库文件,放lib里,调用使用 import dock;

Code AardioLine:181复制
  • 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.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
    • class dock{
    • ctor(winform, acts=10/*每过程动作次数*/, isTop=false/*置顶*/, isDock=true/*吸附*/, margin=false/*留边*/){
    • assert(winform[["hwnd"]], "参数@1必须是窗体对象");
    • acts = ..math.abs(tonumber(acts) : 1);
    • //this = win.form(); this.messageOnly();
    • this = winform;
    • this.site, this.msIn = "", 0;
    • var scrw, scrh = win.getScreen();
    • var wndGdi, alSign = _wndGdi();
    • var wndAlpha = function(v = false, w, h){
    • alSign = !!v;
    • if(!alSign){
    • this.transparent(false);
    • //this.hide = 1; this.hide = 0;
    • //this.redraw();
    • _redrawWindow(this.hwnd, , , 0x400/*_RDW_FRAME*/ | 0x1/*_RDW_INVALIDATE*/ | 0x4/*_RDW_ERASE*/)
    • return;
    • }
    • this.transparent(true);
    • var col = margin ? 0xaad2d2d2 : 0x01d2d2d2//0xaad2d2d2 : 0x01d2d2d2
    • wndGdi(this.hwnd, w, h, function(mdc, w, h){
    • var gph = gdip.graphics(mdc)
    • var gBru = gdip.solidBrush(col)
    • gph.fillRectangle(gBru, 0, 0, w, h)
    • gBru.delete()
    • gph.delete()
    • gdi.updateLayeredWindow(this.hwnd, mdc, ::SIZE(w, h), gdi.blendFunction(255/*透明度*/))
    • })
    • }
    • var ap = {}; //aTimer动作定时器运行时参数
    • var aTimer = win.timer(, 10);
    • aTimer.onTimer = function(hwnd,msg,id,tick){
    • var c = true;
    • if(ap[["site"]] == "top"){
    • ap.y += ap.v;
    • c = ap.msIn ? !(ap.y<0) : !(ap.y>4-ap.h);
    • if(c) ap.y = !ap.msIn ? 4-ap.h : 0;
    • }
    • elseif(ap[["site"]] == "left"){
    • ap.x += ap.v;
    • c = ap.msIn ? !(ap.x<0) : !(ap.x>4-ap.w);
    • if(c) ap.x = !ap.msIn ? 4-ap.w : 0;
    • }
    • elseif(ap[["site"]] == "right"){
    • ap.x -= ap.v;
    • c = ap.msIn ? !(ap.x>scrw-ap.w) : !(ap.x<scrw-4);
    • if(c) ap.x = ap.msIn ? scrw-ap.w : scrw-4;
    • }
    • this.setPos(ap.x, ap.y);
    • if(c){
    • if(#ap[["site"]] && !ap.msIn){
    • wndAlpha(1, ap.w, ap.h);
    • if(!isTop) win.setTopmost(this.hwnd);
    • }
    • elseif(!isTop) win.setTopmost(this.hwnd, false);
    • owner.disable();
    • }
    • elseif(alSign) wndAlpha(, ap.w, ap.h);
    • }
    • var msPos = ::POINT();
    • var mTimer = win.timer(, 10);
    • mTimer.onTimer = function(hwnd,msg,id,tick){
    • var x, y, w, h = this.getPos();
    • if(w >= scrw) return;
    • //**判断窗口停靠位置
    • var site = ""
    • if(x <= 0) site = "left";
    • elseif(x+w >= scrw) site = "right";
    • elseif(y <= 0) site = "top";
    • if(this.site != site){
    • this.site = site
    • ::PostMessage(this.hwnd, 0x503, 0, 0)
    • }
    • //**/
    • //**检测鼠标进出窗口 左键状态 判断是否动作
    • _getMsPos(msPos)
    • var msIn = _msIn(msPos.x, msPos.y) ? 1 : 0
    • var v = _getAsyncKeyState(1)
    • if(this.msIn != msIn){
    • this.msIn = msIn
    • ::PostMessage(this.hwnd, 0x5A3, 0, 0)
    • }
    • elseif(!v) return;
    • if(!#site || v) return;
    • //**/
    • //**执行动作
    • v = (site == "top") ? ..math.ceil(h/acts) : ..math.ceil(w/acts);
    • v = msIn ? v : -v;
    • ap.site,ap.msIn,ap.x,ap.y,ap.w,ap.h,ap.v = site,msIn,x,y,w,h,v;
    • aTimer.enable();
    • //**/
    • }
    • this.wndMargin = function(v = false){
    • margin = !!v
    • }
    • //**窗口呼出
    • this.wndDisplay = function(){
    • var x, y, w, h = owner.getPos();
    • if(x<0) x = 0
    • elseif(x+w>scrw) x = scrw-w
    • if(y<0) y = 0
    • elseif(y+h>scrh) y = scrh-h
    • owner.setPos(x, y)
    • owner.transparent(false)
    • }
    • this.wndDisplay()
    • //**/
    • //**窗口置顶 避免与aTimer里的win.setTopmost冲突
    • this.wndTopmost = function(v){
    • isTop = !!v
    • win.setTopmost(owner.hwnd, isTop)
    • return isTop;
    • }
    • this.wndTopmost(isTop)
    • //**/
    • //**窗口吸附
    • this.wndDock = function(v = true){
    • isDock = !!v
    • if(isDock) mTimer.enable();
    • else { mTimer.disable(); owner.wndDisplay() }
    • return isDock;
    • }
    • this.wndDock(isDock)
    • //**/
    • this.wndproc = {
    • [0x7E/*_WM_DISPLAYCHANGE 屏幕分辨率改变*/] = function(hwnd,message,wParam,lParam){
    • scrw, scrh = win.getScreen();
    • owner.wndDisplay()
    • }
    • }
    • ::PostMessage(this.hwnd, 0x5A3, 0, 0);
    • };
    • }
    • namespace dock{
    • import win.timer;
    • import gdip.graphics;
    • import gdip.solidBrush;
    • import gdi;
    • _getMsPos = ::User32.GetCursorPos;
    • _redrawWindow = ::User32.RedrawWindow;
    • _fromPoint = ::User32.WindowFromPoint;
    • _getAsyncKeyState = ::User32.GetAsyncKeyState;
    • _getWindowThreadProcessId = ::User32.GetWindowThreadProcessId;
    • _msIn = function(x, y){
    • var hwnd = _fromPoint(x, y);
    • return _getWindowThreadProcessId(hwnd, 0) == ..thread.getId();
    • }
    • _wndGdi = function(){
    • var hdc, mdc, hbmp;
    • var create = function(hwnd, w, h){
    • hdc = ::GetWindowDC(hwnd);
    • mdc = ::CreateCompatibleDC();
    • hbmp = ::CreateCompatibleBitmap(hdc, w, h);
    • ::SelectObject(mdc, hbmp);
    • }
    • var delete = function(hwnd){
    • ::ReleaseDC(hwnd, hdc);
    • ::DeleteDC(mdc);
    • ::DeleteObject(hbmp);
    • }
    • return function(hwnd, w, h, draw, ...){
    • create(hwnd, w, h);
    • if(type(draw) == "function") draw(mdc, w, h, ...);
    • delete(hwnd);
    • }
    • }
    • }

    已知问题(希望光大能帮助优化下):

    1、窗体贴边影藏之后,无法通过点击状态栏程序图标激活,必须鼠标放到贴边位置,有时候找不到,需要鼠标围着桌面贴边找一圈;

    2、贴边程序不稳定,有时候锁屏之后,再打开电脑,发现程序界面变得透明,甚至到找不到了,完全透明了;

    纯属搬运,非原创

    上传的附件:
    最新回复 (5)
    • zhhyit 2月前
      0 2

      补充一下简单的用法,供大家参考学习

      Code AardioLine:11复制
    • 1.
    • 2.
    • 3.
    • 4.
    • 5.
    • 6.
    • 7.
    • 8.
    • 9.
    • 10.
    • 11.
      • import win.ui;
      • import dock;
      • /*DSG{{*/
      • var winform = win.form(text="窗体靠边吸附";right=275;bottom=291)
      • winform.add()
      • /*}}*/
      • var dockManager = dock(winform, 10/*每过程动作次数*/, true/*置顶*/, true/*吸附*/, true/*留边*/);
      • winform.show();
      • win.loopMessage();


    • 光庆 2月前
      0 3

    • zhhyit 21天前
      0 4
      Code AardioLine:2复制
    • 1.
    • 2.
      • 修复一个BUG 2025-03-25
      • // 获取所有显示器的信息(针对双显示器),修复多显示器的贴边的时候闪屏的BUG

      使用方法:复制后保存成dock库文件,放lib里,调用使用 import dock;

      Code AardioLine:224复制
    • 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.
    • 89.
    • 90.
    • 91.
    • 92.
    • 93.
    • 94.
    • 95.
    • 96.
    • 97.
    • 98.
    • 99.
    • 100.
    • 101.
    • 102.
    • 103.
    • 104.
    • 105.
    • 106.
    • 107.
    • 108.
    • 109.
    • 110.
    • 111.
    • 112.
    • 113.
    • 114.
    • 115.
    • 116.
    • 117.
    • 118.
    • 119.
    • 120.
    • 121.
    • 122.
    • 123.
    • 124.
    • 125.
    • 126.
    • 127.
    • 128.
    • 129.
    • 130.
    • 131.
    • 132.
    • 133.
    • 134.
    • 135.
    • 136.
    • 137.
    • 138.
    • 139.
    • 140.
    • 141.
    • 142.
    • 143.
    • 144.
    • 145.
    • 146.
    • 147.
    • 148.
    • 149.
    • 150.
    • 151.
    • 152.
    • 153.
    • 154.
    • 155.
    • 156.
    • 157.
    • 158.
    • 159.
    • 160.
    • 161.
    • 162.
    • 163.
    • 164.
    • 165.
    • 166.
    • 167.
    • 168.
    • 169.
    • 170.
    • 171.
    • 172.
    • 173.
    • 174.
    • 175.
    • 176.
    • 177.
    • 178.
    • 179.
    • 180.
    • 181.
    • 182.
    • 183.
    • 184.
    • 185.
    • 186.
    • 187.
    • 188.
    • 189.
    • 190.
    • 191.
    • 192.
    • 193.
    • 194.
    • 195.
    • 196.
    • 197.
    • 198.
    • 199.
    • 200.
    • 201.
    • 202.
    • 203.
    • 204.
    • 205.
    • 206.
    • 207.
    • 208.
    • 209.
    • 210.
    • 211.
    • 212.
    • 213.
    • 214.
    • 215.
    • 216.
    • 217.
    • 218.
    • 219.
    • 220.
    • 221.
    • 222.
    • 223.
    • 224.
      • class dock{
      • ctor(winform, acts=10/*每过程动作次数*/, isTop=false/*置顶*/, isDock=true/*吸附*/, margin=false/*留边*/){
      • assert(winform[["hwnd"]], "参数@1必须是窗体对象");
      • acts = ..math.abs(tonumber(acts) : 1);
      • //this = win.form(); this.messageOnly();
      • this = winform;
      • this.site, this.msIn = "", 0;
      • // 获取所有显示器的信息(针对双显示器),修复多显示器的BUG
      • var monitors = {};
      • for hMonitor, monitorInfo in sys.monitor.eachInfo() {
      • ..table.push(monitors,monitorInfo);
      • //var width =monitorInfo.rcMonitor.right-monitorInfo.rcMonitor.left;
      • //var height =monitorInfo.rcMonitor.bottom-monitorInfo.rcMonitor.top;
      • }
      • var scrw, scrh = win.getScreen();//定义显示器分辨率的局部变量
      • // 判断排列方式
      • if (#monitors > 1) {
      • var monitor1 = monitors[1];
      • var monitor2 = monitors[2];
      • // 判断水平排列
      • if (monitor1.rcMonitor.right == monitor2.rcMonitor.left or monitor1.rcMonitor.left == monitor2.rcMonitor.right) {
      • //console.log("显示器是水平排列");
      • var width = ..math.abs(monitor2.rcMonitor.right-monitor1.rcMonitor.left);
      • var height = ..math.abs(monitor1.rcMonitor.bottom-monitor2.rcMonitor.top);
      • scrw, scrh = width,height
      • //console.log(width, height)
      • }
      • // 判断垂直排列
      • elseif (monitor1.rcMonitor.bottom == monitor2.rcMonitor.top or monitor1.rcMonitor.top == monitor2.rcMonitor.bottom) {
      • //console.log("显示器是垂直排列");
      • var width = ..math.abs(monitor2.rcMonitor.right-monitor1.rcMonitor.left);
      • var height = ..math.abs(monitor1.rcMonitor.bottom-monitor2.rcMonitor.top);
      • scrw, scrh = width,height
      • //console.log(width, height)
      • }
      • // 其他排列方式
      • else {
      • //console.log("显示器是其他排列方式");
      • scrw, scrh = win.getScreen();
      • }
      • } else {
      • //console.log("只有一个显示器");
      • scrw, scrh = win.getScreen();
      • }
      • //var scrw, scrh = win.getScreen();
      • var wndGdi, alSign = _wndGdi();
      • var wndAlpha = function(v = false, w, h){
      • alSign = !!v;
      • if(!alSign){
      • this.transparent(false);
      • //this.hide = 1; this.hide = 0;
      • //this.redraw();
      • _redrawWindow(this.hwnd, , , 0x400/*_RDW_FRAME*/ | 0x1/*_RDW_INVALIDATE*/ | 0x4/*_RDW_ERASE*/)
      • return;
      • }
      • this.transparent(true);
      • var col = margin ? 0xaad2d2d2 : 0x01d2d2d2//0xaad2d2d2 : 0x01d2d2d2
      • wndGdi(this.hwnd, w, h, function(mdc, w, h){
      • var gph = gdip.graphics(mdc)
      • var gBru = gdip.solidBrush(col)
      • gph.fillRectangle(gBru, 0, 0, w, h)
      • gBru.delete()
      • gph.delete()
      • gdi.updateLayeredWindow(this.hwnd, mdc, ::SIZE(w, h), gdi.blendFunction(255/*透明度*/))
      • })
      • }
      • var ap = {}; //aTimer动作定时器运行时参数
      • var aTimer = win.timer(, 10);
      • aTimer.onTimer = function(hwnd,msg,id,tick){
      • var c = true;
      • if(ap[["site"]] == "top"){
      • ap.y += ap.v;
      • c = ap.msIn ? !(ap.y<0) : !(ap.y>4-ap.h);
      • if(c) ap.y = !ap.msIn ? 4-ap.h : 0;
      • }
      • elseif(ap[["site"]] == "left"){
      • ap.x += ap.v;
      • c = ap.msIn ? !(ap.x<0) : !(ap.x>4-ap.w);
      • if(c) ap.x = !ap.msIn ? 4-ap.w : 0;
      • }
      • elseif(ap[["site"]] == "right"){
      • ap.x -= ap.v;
      • c = ap.msIn ? !(ap.x>scrw-ap.w) : !(ap.x<scrw-4);
      • if(c) ap.x = ap.msIn ? scrw-ap.w : scrw-4;
      • }
      • this.setPos(ap.x, ap.y);
      • if(c){
      • if(#ap[["site"]] && !ap.msIn){
      • wndAlpha(1, ap.w, ap.h);
      • if(!isTop) win.setTopmost(this.hwnd);
      • }
      • elseif(!isTop) win.setTopmost(this.hwnd, false);
      • owner.disable();
      • }
      • elseif(alSign) wndAlpha(, ap.w, ap.h);
      • }
      • var msPos = ::POINT();
      • var mTimer = win.timer(, 10);
      • mTimer.onTimer = function(hwnd,msg,id,tick){
      • var x, y, w, h = this.getPos();
      • if(w >= scrw) return;
      • //**判断窗口停靠位置
      • var site = ""
      • if(x <= 0) site = "left";
      • elseif(x+w >= scrw) site = "right";
      • elseif(y <= 0) site = "top";
      • if(this.site != site){
      • this.site = site
      • ::PostMessage(this.hwnd, 0x503, 0, 0)
      • }
      • //**/
      • //**检测鼠标进出窗口 左键状态 判断是否动作
      • _getMsPos(msPos)
      • var msIn = _msIn(msPos.x, msPos.y) ? 1 : 0
      • var v = _getAsyncKeyState(1)
      • if(this.msIn != msIn){
      • this.msIn = msIn
      • ::PostMessage(this.hwnd, 0x5A3, 0, 0)
      • }
      • elseif(!v) return;
      • if(!#site || v) return;
      • //**/
      • //**执行动作
      • v = (site == "top") ? ..math.ceil(h/acts) : ..math.ceil(w/acts);
      • v = msIn ? v : -v;
      • ap.site,ap.msIn,ap.x,ap.y,ap.w,ap.h,ap.v = site,msIn,x,y,w,h,v;
      • aTimer.enable();
      • //**/
      • }
      • this.wndMargin = function(v = false){
      • margin = !!v
      • }
      • //**窗口呼出
      • this.wndDisplay = function(){
      • var x, y, w, h = owner.getPos();
      • if(x<0) x = 0
      • elseif(x+w>scrw) x = scrw-w
      • if(y<0) y = 0
      • elseif(y+h>scrh) y = scrh-h
      • owner.setPos(x, y)
      • owner.transparent(false)
      • }
      • this.wndDisplay()
      • //**/
      • //**窗口置顶 避免与aTimer里的win.setTopmost冲突
      • this.wndTopmost = function(v){
      • isTop = !!v
      • win.setTopmost(owner.hwnd, isTop)
      • return isTop;
      • }
      • this.wndTopmost(isTop)
      • //**/
      • //**窗口吸附
      • this.wndDock = function(v = true){
      • isDock = !!v
      • if(isDock) mTimer.enable();
      • else { mTimer.disable(); owner.wndDisplay() }
      • return isDock;
      • }
      • this.wndDock(isDock)
      • //**/
      • this.wndproc = {
      • [0x7E/*_WM_DISPLAYCHANGE 屏幕分辨率改变*/] = function(hwnd,message,wParam,lParam){
      • scrw, scrh = win.getScreen();
      • owner.wndDisplay()
      • }
      • }
      • ::PostMessage(this.hwnd, 0x5A3, 0, 0);
      • };
      • }
      • namespace dock{
      • import win.timer;
      • import gdip.graphics;
      • import gdip.solidBrush;
      • import gdi;
      • import sys.monitor;
      • import console;
      • _getMsPos = ::User32.GetCursorPos;
      • _redrawWindow = ::User32.RedrawWindow;
      • _fromPoint = ::User32.WindowFromPoint;
      • _getAsyncKeyState = ::User32.GetAsyncKeyState;
      • _getWindowThreadProcessId = ::User32.GetWindowThreadProcessId;
      • _msIn = function(x, y){
      • var hwnd = _fromPoint(x, y);
      • return _getWindowThreadProcessId(hwnd, 0) == ..thread.getId();
      • }
      • _wndGdi = function(){
      • var hdc, mdc, hbmp;
      • var create = function(hwnd, w, h){
      • hdc = ::GetWindowDC(hwnd);
      • mdc = ::CreateCompatibleDC();
      • hbmp = ::CreateCompatibleBitmap(hdc, w, h);
      • ::SelectObject(mdc, hbmp);
      • }
      • var delete = function(hwnd){
      • ::ReleaseDC(hwnd, hdc);
      • ::DeleteDC(mdc);
      • ::DeleteObject(hbmp);
      • }
      • return function(hwnd, w, h, draw, ...){
      • create(hwnd, w, h);
      • if(type(draw) == "function") draw(mdc, w, h, ...);
      • delete(hwnd);
      • }
      • }
      • }


      已知的问题(能力有限,仍未能优化):

      1、窗体贴边影藏之后,无法通过点击状态栏程序图标激活,必须鼠标放到贴边位置,有时候找不到,需要鼠标围着桌面贴边找一圈;

      2、窗体不能最小化,最小化后无法还原;

      3、父子窗体中,子窗体鼠标滑过会触发主窗体的DOCK贴边显示;

      上传的附件:
    • freejzh 17天前
      0 5
      我试了一下,确实牛皮
    • shzhbook 16天前
      0 6
      效果不错,不过提到的已知问题的确存在,希望坛里面的大佬能和楼主一起完善修复此库。
    返回