zoukankan      html  css  js  c++  java
  • AutoHotkey监控Excel事件应用(1)---根据当前列的值高亮行

    实现的效果见视频。

    使用方法:

    1. 以下代码保存为 ahk 文件,并运行。
    2. 鼠标停留到Excel的关键列任意单元格,按F9即可。

    说明:

    1. Excel表数据要带标题行
    2. 不要在关键列左侧增加列
    3. 相同的值要连续才会是同颜色
    4. 颜色是根据下表 Excel 自带 ColorIndex 的33-41 颜色循环使用,可自行在代码里修改

    #SingleInstance Force
    F12::ExitApp
    
    F9::
    event_highlightRowByColumnValue()
    return
    
    ;根据当前列的值高亮表内【行】
    ;要求有标题行
    event_highlightRowByColumnValue()
    {
        idName := A_ThisFunc
        xl := ox()
        ac := xl.ActiveCell
        ;NOTE 记录关键列号,因为 target 不可靠
        cKey := ac.column
        ;定义颜色顺序 ColorIndex
        arrColor := [33,34,35,36,37,38,39,40,41]
        ;开启/关闭事件
        if !Events_Workbook.objEvent.haskey(idName)
        {
            highlightRowByColumn(ac) ;开启事件前直接运行一次
            new Events_Workbook(xl.ActiveWorkbook, idName, "Change", func("highlightRowByColumn")).start() ;用内部函数也没问题
        }
        else if (Events_Workbook.objEvent[idName].wb.name = xl.ActiveWorkbook.name) ;当前工作表 = 事件监控工作表
            Events_Workbook.objEvent[idName].stop() ;实例没保存到变量,用此方法引用
        highlightRowByColumn(target:="")
        {
            ;获取数据区域(不含标题行)
            try
                rngData := target.ListObject.DataBodyRange
            catch
            {
                rngCR := target.CurrentRegion
                rngData := rngCR.offset(1).resize(rngCR.rows.count-1)
            }
            ;关键列区域
            rngKeyCol := rngData.columns(cKey-rngData.column+1)
            ;判断修改值的单元格是否在 rngKeyCol 内
            if !isobject(xl.intersect(target, rngKeyCol))
                return
            else if (target.columns.count > 1) ;多列
                target := xl.intersect(target, rngKeyCol)
            ;单个单元格且为空值,则不处理
            if (target.cells.count == 1 & !strlen(target.value))
                return
            xl.ScreenUpdating := false
            arrV := rngKeyCol.value ;获取当前列的值
            idx := 1 ;颜色序号
            cnt := 1 ;同值行数
            _v := arrV[1,1] ;用来判断是否同个值
            rngRowStart := rngData.rows(1) ;当前高亮的第1行
            loop(arrV.MaxIndex(1)-1) ;从第2行开始循环
            {
                if (arrV[A_Index+1,1] != _v)
                {
                    rngRowStart.resize(cnt).interior.ColorIndex := arrColor[idx]
                    ;初始化
                    rngRowStart := rngData.rows(A_Index+1)
                    _v := arrV[A_Index+1,1]
                    cnt := 1
                    ;记录下一颜色序号
                    idx++
                    if (idx > arrColor.length())
                        idx := 1
                }
                else
                    cnt++
            }
            ;NOTE 执行最后一类数据的高亮
            rngRowStart.resize(cnt).interior.ColorIndex := arrColor[idx]
            xl.ScreenUpdating := true
        }
    }
    
    ; https://autohotkey.com/board/topic/69847-com-events-using-ByRef-parms/?p=442260
    class Events_Workbook
    {
        static objEvent := {} ;保存事件的所有信息供外部使用,以传入的 event 为key
    
        ;NOTE wb为事件的载体,其他工作簿单独事件逻辑
        ;用 idName 区别各功能
        ;同事件可满足多个需求
        __new(wb, idName, event, funcObj:="", data:="")
        {
            this.tipsLevel := 19
            this.idName := idName
            this.event := event ;监控的事件名称,多事件可用数组
            this.wb := wb ;实例要用,用 objEvent 提取太麻烦
            this.funcObj := funcObj ;TODO 是否要区分不同事件
            this.data := data ;其他传入的值
        }
    
        ;所有事件+方法都会运行 
        ;evtThis为 Sheet+事件名,args[1]=target
        __call(evtThis, args*)
        {
            ;tooltip(evtThis)
            if (evtThis = this.event || substr(evtThis,6) = this.event) ;筛选事件名称(从第6个字符开始提取是为了删除 Sheet 前缀)
                this.funcObj.call(args*)
            ;else if isobject(this.event) ;暂时没用
            ;{
                ;for _, evt in this.event
                ;{
                    ;if (evtThis = evt || substr(evtThis,6) = evt) ;筛选事件
                    ;{
                        ;this.funcObj.call(args*)
                        ;return
                    ;}
                ;}
            ;}
        }
    
        ;TODO 监控工作表和工作簿,分别怎么实现
        start()
        {
            Events_Workbook.objEvent[this.idName] := this ;NOTE 保存实例,外部获取信息和 stop 用,这样外面不需要保存实例变量
            ComObjConnect(this.wb, this)
            this.tipsShow("start")
        }
        stop()
        {
            ComObjConnect(this.wb)
            Events_Workbook.objEvent.delete(this.idName)
            this.tipsShow("stop")
            this := "" ;ObjRelease 会出错
        }
    
        list()
        {
            return Events_Workbook.objEvent
        }
    
        ;事件结束会关闭显示
        tipsShow(str)
        {
            if !isobject(this.data)
            {
                tooltip(str,,, this.tipsLevel)
                SetTimer(func("tooltip").bind(,,, this.tipsLevel), -1000)
            }
            else
            {
                tooltip(this.data.tipStr,,, this.tipsLevel)
                if this.data.haskey("tipTime")
                {
                    if this.data.tipTime
                        SetTimer(func("tooltip").bind(,,, this.tipsLevel), -this.data.tipTime)
                }
                else
                    SetTimer(func("tooltip").bind(,,, this.tipsLevel), -1000)
            }
        }
    
    }
    
    ox(winTitle:="ahk_class XLMAIN")
    {
        ctlID := ControlGetHwnd("EXCEL71", winTitle)
        if !ctlID
            ExitApp
        if dllcall("oleaccAccessibleObjectFromWindow", "ptr",ctlID, "uint",4294967280, "ptr",-VarSetCapacity(IID,16)+NumPut(0x46000000000000C0,NumPut(0x0000000000020400,IID,"int64"),"int64"), "ptr*",pacc) = 0
            win := ComObject(9, pacc, 1)
        loop
        {
            try
                xl := win.application
            catch
                ControlSend("{escape}", "EXCEL71", winTitle)
        }
        until !!xl
        return xl
    }
  • 相关阅读:
    [HNOI2006] 公路修建问题
    [8.16模拟赛] 玩具 (dp/字符串)
    [NOI2014] 动物园
    [CF816E] Karen and Supermarket1 [树形dp]
    [POI2006] OKR-period of words
    [BZOJ4260] Codechef REBXOR
    [POJ3630] Phone List
    正确答案 [Hash/枚举]
    The xor-longest Path [Trie]
    [NOI1999] 生日蛋糕
  • 原文地址:https://www.cnblogs.com/hyaray/p/13171936.html
Copyright © 2011-2022 走看看