2022年6月23日木曜日

Pywin32 データWriteの高速化

 Cell.Valueだけでしたら可能です。PythonでRangeを読んでみると2次元Tupleで返ってきました。つまり2次元配列で書いてやれば、時間のかかるCOM通信を一回で行えるのではないか?と推察しました。それに対して、Interior.Colorとかは、明示的な構造体・配列を示唆する情報が返ってきません。(print(xx)で見ました。)

なので、とりあえず、Valueは行けるのではないかと思って書いたのが次のソースです。これで、体感数十倍速にはなりました。

残念なことにこの技は、Interior.Colorには使えません。Rangeで一括は、定数では可能です。ですから初期化には使えます。例えば,次のソースです。

ws.UsedRange.Interior.ColorIndex=0 #Clear Colors

VBAでは、UnionでプログラムでRangeに追加できますが、Pythonではそうしたことが可能になる例は見つけられませんでした。やむを得ず、色付の場合、一個ずづ処理するので時間がかかりますよ。いいですか? のメッセージを出すのが精一杯ということになります。(無理やりPythonでやろうとすれば、Pythonソースをダイナミックに生成することになると思いますが..)

さて、求解すると次のところで停止します。pdb.set_trace()の次の行で停止します。

デバッグしたい開始点に、この行を設置することになります。ソースエディタで設定したブレークポイントは、set_traceで読み込まれます。また、当該エディタ上で停止しているときに設置・解除することが出来ます。実行ボタンを押すと進みます。


次の画像は、時間がかかるので、どうします?と聞いてくるスナップショットです。
このプロジェクトは、INRC2 35人4WEEKSです。

色付出力を選択した場合、90秒 


色なしを選択した場合、2-3秒


なお、プロジェクトファイル名と同名の拡張子xlsxのExcelファイルが無ければフォーマットから開始するソースです。

<不明なCOMエラーが出る場合>
ソース行で、ExcelをVisibleにしておくことは重要です。

xl.Visible = True#False makes debug harder..

FalseにするとExcelが現れません。で、プログラム開発途中でExcelがプロセスとして残っていたりすると、そのExcelに対して操作が行われます。がExcelそのものは見えないと、原因不明のCOMエラーになったりします。Excelが現れていれば、その辺は、すぐに分かります。Excelが現れて、余計なキー操作でエラーになったりすることはありますが、その事自体は気付けるので、程度が良いです。プロセスが残っているかどうかは、タスクマネージャで見ることが出来ます。起動していないのに存在する!、という場合は、死んでもらってから求解するようにしましょう。

以下、Pythonソースです。ScheduleNurse固有命令sc3...は一切使っていませんが、GUIの集合定義は参照しています。これ位の規模になるとデバッガが欲しくなった次第です。最初は、print()文の実装で済まそうと思っていたのが、やはり欲しくなって155Aから内蔵しています。


import os
import datetime
import locale
import ctypes
import win32gui
import win32com.client
import re
import sc3
import pdb

#---------------------------
xlHairline = 1
xlThin     = 2
xlThick    = 4
xlMedium   = -4138

    # ------------------------------------------------------------------
    # Excel Enum XlFileFormat
    # ------------------------------------------------------------------
xlCSV                         =  6
xlHtml                        = 44
xlWorkbookDefault             = 51
xlOpenXMLWorkbook             = 51
xlOpenXMLWorkbookMacroEnabled = 52
xlWorkbookNormal              = -4143
xlCurrentPlatformText         = -4158

    # ------------------------------------------------------------------
    # Excel Enum XlLineStyle
    # ------------------------------------------------------------------
xlContinuous    =  1
xlDashDot       =  4
xlDashDotDot    =  5
xlSlantDashDot  = 13
xlDash          = -4115
xldot           = -4118
xlDouble        = -4119
xlLineStyleNone = -4142
    # ------------------------------------------------------------------
    # Excel Enum XlOrientation
    # ------------------------------------------------------------------
xlHorizontal = -4128
xlVertical   = -4166
xlDownward   = -4170
xlUpward     = -4171
 
# ------------------------------------------------------------------
#https://docs.microsoft.com/en-us/office/vba/api/excel.xlformatconditionoperator
xlCellValue=1
xlExpression=2
xlBetween=1#	Between. Can be used only if two formulas are provided.
xlEqual=3#	Equal.
xlGreater=5#	Greater than.
xlGreaterEqual=7#	Greater than or equal to.
xlLess=6#	Less than.
xlLessEqual=8#	Less than or equal to.
xlNotBetween=2#	Not between. Can be used only if two formulas are provided.
xlNotEqual=4#	Not equal.
xlUnderlineStyleSingle           = 2 
xlCenter      = -4108

MB_OK=0x00000000#The message box contains one push button: OK. This is the default.
MB_OKCANCEL=0x00000001#The message box contains two push buttons: OK and Cancel.
MB_RETRYCANCEL=0x00000005#The message box contains two push buttons: Retry and Cancel.
MB_YESNO=0x00000004#The message box contains two push buttons: Yes and No.
MB_YESNOCANCEL=0x00000003#The message box contains three push buttons: Yes, No, and 

MB_TOPMOST=0x00040000#The message box is created with the WS_EX_TOPMOST window style.
IDABORT=3#The Abort button was selected.
IDCANCEL=2#The Cancel button was selected.
IDCONTINUE=11#The Continue button was selected.
IDIGNORE=5#The Ignore button was selected.
IDNO=7#The No button was selected.
IDOK=1#The OK button was selected.
IDRETRY=4#The Retry button was selected.
IDTRYAGAIN=10#The Try Again button was selected.
IDYES=6#The Yes button was selected.

def post_main():
    pdb.set_trace()
    
    print(locale.getlocale(locale.LC_CTYPE))
    print("Hello post main world!")
    print('\n\n*********Processing Post operation *************\n')
    phases=len(dayphase_list)
#
#Launch Excel
    try :
        xl = win32com.client.Dispatch("Excel.Application")
    except:
        print("can not invoke excel")
        exit()
    #Show working
    xl.Visible = True#False makes debug harder..
    os.chdir(project_file_path)
    file_name=project_file_name+".xlsx";
    file=os.path.join(project_file_path,file_name)
    exists=os.path.exists(file) 
    if exists:
        wb = xl.Workbooks.Open(file)
    else:
        wb=xl.Workbooks.Add()
    
    
    
    # Excelsheet object
    ws = wb.Worksheets(1)
    with_color=False
    if not exists:
        day_str=daydef[今月[0]]
        day=int(day_str[8:])#Day
        one_month_mode=False
        if day==1 and len(今月)<=31:
            one_month_mode=True
        make_initial_format_improved(ws,one_month_mode)
    
    
    sc_hwnd=get_sc3_handle()
    print("hwnd=",sc_hwnd)
 
    if "Japan" in locale.getlocale(locale.LC_CTYPE)[0]:#('Japanese_Japan', '932')('English_United States', '932')
        MessageBox = ctypes.windll.user32.MessageBoxW
        res=MessageBox(sc3_hwnd, '本当に色付き出力にしますか?色付きにするとすごく時間がかかります。', '色付き出力選択', MB_TOPMOST|MB_YESNOCANCEL)
    else:
        MessageBox = ctypes.windll.user32.MessageBoxW
        res=MessageBox(sc3_hwnd, 'Are sure you want the results with colored?\nIt takes far longer time with colored.', 'With/Without Color Selection',MB_TOPMOST|MB_YESNOCANCEL)
        
    if res==IDYES:#
        with_color=True
    elif res==IDCANCEL:#Cancel
        wb.SaveAs(f"{os.getcwd()}\\"+file_name, FileFormat = xlOpenXMLWorkbook)
        wb.Close(True)# True:Save False=Default:Not Save
        xl.Quit()
        return
    else:#No
        with_color=False
    make_data_improved(ws,phases,with_color)#Output the SC3 Data on the formatted sheet.
    if not exists:
        wb.SaveAs(f"{os.getcwd()}\\"+file_name, FileFormat = xlOpenXMLWorkbook)
    
    
    wb.Close(True)# True:Save False=Default:Not Save
    # Excel Quit
    xl.Quit()
    print('\n\n*********Processed Post Operation.*************\n')

def clear(ws):
    ws.UsedRange.ClearContents()
    ws.UsedRange.ClearFormats()
    

def set_font(ws,addr,value):
    ws.Range(addr).Value=value
    ws.Range(addr).Font.Name = "Yu Gothic UI"
    # Set Cell font size
    ws.Range(addr).Font.Size = 14
    # Set Bold
    ws.Range(addr).Font.Bold = True


def make_initial_format_improved(ws,one_month_mode=False):
    if one_month_mode==True:
        print("one_month mode formatting..")
        day_str=daydef[今月[0]]
        day=int(day_str[8:])#Day
        if day !=1 :
            print("Fatal Error. 今月 must start with 1.")
            exit()
        if len(今月)>31:
            print("Fatal Error. Excessive 今月 Length.")
            exit()
    else:
        print("nominal mode formatting..")
    今月2=list(今月)#Deep Copy
    if one_month_mode==True:
        for m in range(31)[len(今月):]:
            今月2.append(m+今月[0])

    clear(ws)
    
    set_font(ws,"D2","Work Schedule")
    set_font(ws,"AW2","")
    #ws.Range("AW2").Formula='=Year(E7)'
    ws.Range("AW2","AY2").Merge()
    ws.Range("AW2").Font.Underline = xlUnderlineStyleSingle
    ws.Range("AW1","AY1").Merge()
    set_font(ws,"AW1",'Year')
    
    #ws.Range("AZ2").Formula='=Month(E7)'
    ws.Range("AZ2").Font.Underline = xlUnderlineStyleSingle
    ws.Range("AZ2","BB2").Merge()
    set_font(ws,"AZ1",'Month')
    ws.Range("AZ2","BB2").Merge()

    #ws.Range("BC2").Formula='=Month(E7)'
    ws.Range("BC2").Font.Underline = xlUnderlineStyleSingle
    ws.Range("BC2","BD2").Merge()
    set_font(ws,"BC1",'Day')
    ws.Range("BC1","BD1").Merge()

    ws.Columns(2).EntireColumn.ColumnWidth = 20
    ws.Columns(3).EntireColumn.ColumnWidth = 10
    ws.Columns(4).EntireColumn.ColumnWidth = 5

    row_start=8
    row=row_start
    col_start=2
    col=col_start
    day_col_offset=3
    persons=len(staffdef)
    days=len(今月2)
    phases=len(dayphase_list)
    cols=phases*days
    day_processed=0
    row=row_start-2

    #Draw Top Header
    for day in 今月2:
        col=col_start+day_col_offset+day_processed
        for ph in range(phases):
            ws.Columns(col+ph).EntireColumn.ColumnWidth = 2

        if day_processed==0:
            day_str=daydef[day]
        
            #print(day_str,int(day_str[8:]))
            ws.Range("AW2").Formula='='+day_str[0:4]#Year
            ws.Range("AZ2").Formula='='+day_str[5:7]#Month
            ws.Range("BC2").Formula='='+day_str[8:]#Day
               
            
            print(get_relative_addr_str(ws,row-1,col))
            ws.Cells(row-1,col).Formula='=Date(AW2,AZ2,BC2)'#
            ws.Cells(row  ,col).Formula='=Day('+get_relative_addr_str(ws,row-1,col)+')' 
            
            day_color_format2(ws,row,col,-1)
            merge_and_align(ws,row ,col,row,col+phases-1)
            
            ws.Cells(row+1  ,col).Formula='='+get_relative_addr_str(ws,row-1,col)   
            ws.Cells(row+1,col).NumberFormatLocal='aaa'
            day_color_format2(ws,row+1,col,-2)
            merge_and_align(ws,row+1,col,row+1,col+phases-1)
            
        elif day_processed==phases:
            ws.Cells(row-1,col).Formula='='+get_relative_addr_str(ws,row-1,col-phases)+'+1'
            if one_month_mode:
                ws.Cells(row  ,col).Formula='=if($AZ$2 <> Month('+get_relative_addr_str(ws,row-1,col)+'),"",Day('+get_relative_addr_str(ws,row-1,col)+'))'
            else:
                ws.Cells(row  ,col).Formula='=Day('+get_relative_addr_str(ws,row-1,col)+')' 
            day_color_format2(ws,row,col,-1,one_month_mode)
            merge_and_align(ws,row ,col,row,col+phases-1)
            
            if one_month_mode:
                #print("")
                ws.Cells(row+1  ,col).Formula='=if($AZ$2 <> Month('+get_relative_addr_str(ws,row-1,col)+'),"",'+get_relative_addr_str(ws,row-1,col)+')'
            else:
                ws.Cells(row+1  ,col).Formula='='+get_relative_addr_str(ws,row-1,col) #'=Day('+get_relative_addr_str(ws,row-1,col)+')'   
            ws.Cells(row+1,col).NumberFormatLocal='aaa'
            day_color_format2(ws,row+1,col,-2,one_month_mode)
            merge_and_align(ws,row+1,col,row+1,col+phases-1)
            
            
        else:
            ws.Range(ws.Cells(row-1,col-phases),ws.Cells(row-1,col-1)).Copy(ws.Range(ws.Cells(row-1,col),ws.Cells(row-1,col)))
            ws.Range(ws.Cells(row,col-phases),ws.Cells(row+1,col-1)).Copy(ws.Range(ws.Cells(row,col),ws.Cells(row,col)))
        day_processed +=phases

    #Draw Person Property and Data Area
    row=row_start
    for person in All_Staff:
        day_processed=0
        row =row_start+person*4
        if person==All_Staff[0]:
            #name=staffdef[person]
            #ws.Cells(row,col_start).Value=name   
            col=col_start
            merge_and_align(ws,row,col,row+3,col)
            ws.Cells(row,col+1).Value='Preferred'
            merge_and_align(ws,row,col+1,row+1,col+1)

            ws.Cells(row+2,col+1).Value='Sc3 Solution'
            merge_and_align(ws,row+2,col+1,row+3,col+1)

            ws.Cells(row,col+2).Value='Shift'
            merge_and_align(ws,row,col+2,row,col+2)

            ws.Cells(row+2,col+2).Value='Shift'
            merge_and_align(ws,row+2,col+2,row+2,col+2)
        
            ws.Cells(row+1,col+2).Value='Task'
            merge_and_align(ws,row+1,col+2,row+1,col+2)
        
            ws.Cells(row+3,col+2).Value='Task'
            merge_and_align(ws,row+3,col+2,row+3,col+2)
            
            for day in 今月2:
                #print("row=",row,"row_start=",row_start)
                col=col_start+day_col_offset+day_processed
                merge_and_align(ws,row,col,row,col+phases-1)
                merge_and_align(ws,row+2,col,row+2,col+phases-1)
                ws.Range(ws.Cells(row,col),ws.Cells(row+3,col+phases-1)).Borders.LineStyle = xlContinuous
                ws.Range(ws.Cells(row,col),ws.Cells(row+3,col+phases-1)).Borders.weight=xlThin
                day_processed +=phases
        else:
            data_start_col=col_start
            data_end_col=data_start_col+day_col_offset+phases*len(今月2)-1
            ws.Range(ws.Cells(row-4,data_start_col),ws.Cells(row-1,data_end_col)).Copy(ws.Range(ws.Cells(row,data_start_col),ws.Cells(row,data_start_col)))

    #Fill in Staff names
    list2 = [['' for i in range(1)] for j in range(len(All_Staff)*4)]#Constructor
    #wk=ws.Range(ws.Cells(row_start,col_start),ws.Cells(row_start+4*len(All_Staff)-1,col_start)).Value#Values ->2 dim array
    print("list2=",len(list2))
    #[[],[],[]...
    for person in All_Staff:
        list2[person*4][0]=staffdef[person]
    ws.Range(ws.Cells(row_start,col_start),ws.Cells(row_start+4*len(All_Staff)-1,col_start)).Value=list2#Restore it    
    ws.Rows(5).EntireRow.Hidden = True#Hide intemidiate Results

def get_relative_addr_str(ws,row,col):
    str=ws.Cells(row,col).address
    str=str.replace('$','')
    return str
def day_color_format2(ws,row,col,row_offset,one_month_mode=False):
    ws.Cells(row,col).FormatConditions.Delete()#Add(xlCellValue, xlGreaterEqual, '=85')

    if one_month_mode:
        ws.Cells(row,col).FormatConditions.Add(xlExpression, xlGreater,'=Month('+get_relative_addr_str(ws,row+row_offset,col)+')>$AZ$2')
        ws.Cells(row,col).FormatConditions.Add(xlExpression, xlEqual, '=Weekday('+get_relative_addr_str(ws,row+row_offset,col)+')=7') #SAT:7 Sun:1
        ws.Cells(row,col).FormatConditions.Add(xlExpression, xlEqual, '=Weekday('+get_relative_addr_str(ws,row+row_offset,col)+')=1') #SAT:7 Sun:1
        
        ws.Cells(row,col).FormatConditions(1).Interior.ColorIndex=2 #White
        ws.Cells(row,col).FormatConditions(2).Interior.ColorIndex=20 #LightBlue
        ws.Cells(row,col).FormatConditions(3).Interior.ColorIndex=22 #
    else:
        ws.Cells(row,col).FormatConditions.Add(xlExpression, xlEqual, '=Weekday('+get_relative_addr_str(ws,row+row_offset,col)+')=7') #SAT:7 Sun:1
        ws.Cells(row,col).FormatConditions.Add(xlExpression, xlEqual, '=Weekday('+get_relative_addr_str(ws,row+row_offset,col)+')=1') #SAT:7 Sun:1
        
        ws.Cells(row,col).FormatConditions(1).Interior.ColorIndex=20 #LightBlue
        ws.Cells(row,col).FormatConditions(2).Interior.ColorIndex=22 #
def merge_and_align(ws,row_start1,col_start1,row_end1,col_end1,weight=xlThin):
        

        print(row_start1,col_start1,row_end1,col_end1)

        ws.Range(ws.Cells(row_start1,col_start1), ws.Cells(row_end1,col_end1)).Merge()
        ws.Range(ws.Cells(row_start1,col_start1), ws.Cells(row_end1,col_end1)).VerticalAlignment = xlCenter
        ws.Range(ws.Cells(row_start1,col_start1), ws.Cells(row_end1,col_end1)).HorizontalAlignment = xlCenter
        ws.Range(ws.Cells(row_start1,col_start1), ws.Cells(row_end1,col_end1)).Borders.LineStyle = xlContinuous
        ws.Range(ws.Cells(row_start1,col_start1), ws.Cells(row_end1,col_end1)).Borders.Weight = weight

#Sub rountines



def get_shift_label(shift,scheduled_shift_label):
    for key in shift_label_color_map.keys():
        if key ==shift:
            item_array=shift_label_color_map[key]
            i=0
            for item in item_array:
                if i==0:
                    solution_shift_label=item[0]
                    solution_label_color=item[1]
                else:
                    if len(scheduled_shift_label)>=1 and item[0]==scheduled_shift_label:
                        return item[0],item[1]
                i+=1
            return solution_shift_label,solution_label_color
    print("Fatal Error",shift,scheduled_shift_label)
    exit()

def get_task_label(task):
    
    if task in  task_label_color_map:
        return task_label_color_map[task][0][0]
    else:
        print("Invalid Task", task)
        exit()
def rgb_to_hex(rgb):
    '''
    ws.Cells(1, i).Interior.color uses bgr in hex

    '''
    bgr = (int(rgb[2]),int(rgb[1]),int(rgb[0]))
    strValue = '%02x%02x%02x' % bgr
    # print(strValue)
    iValue = int(strValue, 16)
    return iValue

def get_task_label_color(task_label):
    if len(task_label)==0 or task_label=='.':
        return 0xffffff #空白,Dummy DummyDay
    for item_array in task_label_color_map.values():#task集合から探して
        for item in item_array:#taskは複数のラベルを持つ
            task_label_candidate=item[0]
            if task_label==task_label_candidate:#ラベル名が一致したなら
                color_str=item[1]
                rgb = re.findall(r"\d+",color_str)
                if len(rgb)==3:
                    return rgb_to_hex(rgb)
                else:
                    return 0xffffff #rgb形式でなければWhiteを返す
    for item in task_collections_def.values():#無かったらtask aggregatesから探す
        task_label_candidate=item[0]
        #if len(task_label)>=1:
        #    print("list",task_label,task_label_candidate)
        if task_label==task_label_candidate:
            #print("matched",task_label_candidate)
            color_str=item[1]
            rgb = re.findall(r"\d+",color_str)
            if len(rgb)==3:
                return rgb_to_hex(rgb)
            else:
                return 0xffffff #rgb形式でなければWhiteを返す
    #print("unmatched",task_label)
    return 0xffffff #なければWhiteを返す

def get_shift_label_color(shift_label):
    if len(shift_label)==0 or shift_label=='・':
        return 0xffffff #空白ならWhiteを返す
    for item_array in shift_label_color_map.values():#task集合から探して
        for item in item_array:#taskは複数のラベルを持つ
            shift_label_candidate=item[0]
            #print("label ",shift_label,shift_label_candidate)
            if shift_label==shift_label_candidate:#ラベル名が一致したなら
                color_str=item[1]
                rgb = re.findall(r"\d+",color_str)
                if len(rgb)==3:
                    return rgb_to_hex(rgb)
                else:
                    return 0xffffff #rgb形式でなければWhiteを返す
    #print(shift_label," line511")
    for item in shift_collections_def.values():#無かったらtask aggregatesから探す
        shift_label_candidate=item[0]
        #if len(task_label)>=1:
        #    print("list",task_label,task_label_candidate)
        if shift_label==shift_label_candidate:
            #print("matched",task_label_candidate)
            color_str=item[1]
            rgb = re.findall(r"\d+",color_str)
            if len(rgb)==3:
                return rgb_to_hex(rgb)
            else:
                return 0xffffff #rgb形式でなければWhiteを返す
    for item in phase_objects_def.values():
        shift_label_candidate=item[0]
        if shift_label==shift_label_candidate:
            color_str=item[1]
            rgb = re.findall(r"\d+",color_str)
            if len(rgb)==3:
                return rgb_to_hex(rgb)
            else:
                return 0xffffff #rgb形式でなければWhiteを返す
    for item in phase_aggregate_object_def.values():
        shift_label_candidate=item[0]
        if shift_label==shift_label_candidate:
            color_str=item[1]
            rgb = re.findall(r"\d+",color_str)
            if len(rgb)==3:
                return rgb_to_hex(rgb)
            else:
                return 0xffffff 
    #print("unmatched",task_label)
    return 0xffffff #なければWhiteを返す  
def get_task_color(task):
    if len(task)==0 or task=='Dummy' or task=='DummyDay':
        return 0xffffff
    if task in  task_label_color_map:
        color_str=task_label_color_map[task][0][1]
        rgb = re.findall(r"\d+",color_str)
        if len(rgb)==3:
            return rgb_to_hex(rgb)
        else:
            return 255 + 255*256 + 255*256*256
    else:
        return 255 + 255*256 + 255*256*256


def rgb_str_to_hex(color_str):
    rgb = re.findall(r"\d+",color_str)
    if len(rgb)==3:
        return rgb_to_hex(rgb)
    else:
        return 0xffffff
def make_data_improved(ws,phases,color_enabled=False):
    ws.UsedRange.Interior.ColorIndex=0 #Clear Colors
    day_cols=phases*len(今月)
    person_rows=4*len(All_Staff)
    list2_val = [['' for i in range(day_cols)] for j in range(person_rows)]#2 Dim Array Constructor for shift/task
    list2_color = [[0xfffffff for i in range(day_cols)] for j in range(person_rows)]#2 Dim Array Constructor for label color Default White(0xffffff)

    for person in All_Staff:
        staff_name=staffdef[person]
        c=ws.Range("B1:B151").Find(staff_name)
        print('Excel Processing Data ',staff_name,c.Row,c.Column)
        col_offset=3
        if person==0:
            row_start=c.Row
            col_start=c.Column+col_offset
        for day in 今月:
            D=day-制約開始日
            #print(day)
            tph=D*phases
            #print("day",day)
            shift_label=shift_schedules[person][day][2]
            #ws.Cells(c.Row,c.Column+3+col*phases).Value=shift_label#Scheduled Shift
            list2_val[person*4][tph]=shift_label
            shift=shift_schedules[person][day][0]
            shift_color=get_shift_label_color(shift_label)    
            #ws.Cells(c.Row,c.Column+3+col*phases).Interior.Color=shift_color#Scheduled Shift Color
            list2_color[person*4][tph]=shift_color
            for m in range(phases):
                tl=task_schedules[person][day*phases+m][2]#label
                tl_color=get_task_label_color(tl)
                #ws.Cells(c.Row+1,c.Column+3+tph+m).Value=tl#task schedule
                #ws.Cells(c.Row+1,c.Column+3+tph+m).Interior.Color=tl_color
                list2_val  [person*4+1][tph+m]  =tl
                list2_color[person*4+1][tph+m]  =tl_color
  
            shift=shift_solution[person][day]
 
            label_color=get_shift_label(shift,shift_label)#return (label,color_str)
            #ws.Cells(c.Row+2,c.Column+3+col*phases).Value=label_color[0]
            #ws.Cells(c.Row+2,c.Column+3+col*phases).Interior.Color=rgb_str_to_hex(label_color[1])
            list2_val[person*4+2][tph]  =label_color[0]
            list2_color[person*4+2][tph]=rgb_str_to_hex(label_color[1])
  
            for m in range(phases):
                task0=task_solution[person][day*phases+m]
                if len(task0)>=1:
                    t0_color=get_task_color(task0)
                    #ws.Cells(c.Row+3,c.Column+3+tph+m).Interior.Color=t0_color
                    list2_color[person*4+3][tph+m]=t0_color
                    task_label=get_task_label(task0)
                    #ws.Cells(c.Row+3,c.Column+3+tph+m).Value=task_label
                    list2_val[person*4+3][tph+m]=task_label
                #else:
                    #ws.Cells(c.Row+3,c.Column+3+tph+m).Interior.Color=0xffffff
                    #ws.Cells(c.Row+3,c.Column+3+tph+m).Value=""
    col_end=col_start+len(今月)*phases-1
    ws.Range(ws.Cells(row_start,col_start),ws.Cells(row_start+4*len(All_Staff)-1,col_end)).Value=list2_val
    #wk=ws.Range(ws.Cells(row_start,col_start),ws.Cells(row_start+4*len(All_Staff)-1,col_end)).Interior.Color#=list2_color
    #print(len(wk))
    if color_enabled:
        print("Please be patient for 2 min.")
        for row_person in range(len(list2_color)):
            for day_col in range(len(list2_color[row_person])):
                if list2_color[row_person][day_col] !=0xffffff:
                    row=row_start+row_person
                    col=col_start+day_col
                    ws.Cells(row,col).Interior.Color=list2_color[row_person][day_col]
def get_sc3_handle():
    global sc3_hwnd
    win32gui.EnumWindows( winEnumHandler, None )
    sc3_hwnd=int(int(sc3_hwnd,0))
    return sc3_hwnd
def winEnumHandler( hwnd, ctx ):
    if win32gui.IsWindowVisible( hwnd ):
        text=win32gui.GetWindowText( hwnd )
        print (hex(hwnd),text )
        if ('スケジュールナース' in text or "Schedule Nurse" in text) and project_file_name in text:
            global sc3_hwnd
            sc3_hwnd=hex(hwnd)
            print("Detected",sc3_hwnd)
   


0 件のコメント:

コメントを投稿