안녕하세요?
회사원코딩의 마티니입니다.
요즘 이 블로그에다 파이썬-한/글 자동화에 사용하는 메서드를 하나씩 적어보고 있습니다.
예전 포스팅에서도 말씀드렸지만, 저도 새로운 자동화 스크립트를 짤 때는
매번 API문서나 스크립트매크로를 참고합니다. 이게 잘 외워지지는 않더라고요.
2020/07/28 - [아래아한글자동화(기타+)] - [파이썬-아래아한글] 제가 아래아한글 작업을 자동화하는 요령은..
API 문서 안에 대부분의 답이 있다고 생각하는데, 가끔 이런 경우가 있기도 합니다. 예를 들면 아래 메서드,
가끔 현재 커서가 위치한 셀의 위치정보를 얻어오고 싶을 때가 있죠.
표를 좀 더 섬세하게 변경하는 경우라든지, 매크로로 복잡한 표를 만드는데 사용할 수도 있고요.
다행히 HwpCtrl API.hwp 98페이지에 GetTableCellAddr 메서드가 설명되어 있고, 딱 제가 원하는 기능입니다.
근데 이게 실행되지 않아요... 한/글 내부에서 스크립트매크로로 실행할 땐 되는 것 같은데,
COM 오브젝트를 생성하면, 소스를 아무리 뒤져봐도 GetTableCellAddr이라는 메서드가 안 보입니다.
그런 맥락에서 이번 포스팅에서는 일종의 꼼수(?)를 이용해서 현재 셀의 주소를 얻어오는 함수를 직접 만들어봅시다.
참고로 파이썬에서 함수를 만드는 기본적인 문법은 아래와 같이 아주 간단하죠.
def hello(name="Martinii"):
return f"Hello {name}!"
print(hello())
# "Hello Martinii!" 를 리턴
print(hello("World"))
# "Hello World!" 를 리턴
그리고 GetTableCellAddr 대신 엑셀형식의 셀주소 문자열을 받아올 수 있는 메서드가 하나 숨어 있는데
그게 바로 지난 포스팅에 언급했던 hwp.KeyIndicator() 입니다.
2020/07/30 - [아래아한글자동화(기타+)] - [파이썬-한/글] 현재 커서의 페이지를 알고 싶다?
KeyIndicator 메서드를 HwpCtrl API.hwp에서 찾으면 다음과 같은 설명이 있습니다. "상태 바의 정보를 얻어온다"
커서를 표 안에 두고 파라미터 없이 hwp.KeyIndicator()를 실행하면, 튜플을 반환하는데, 그 값이 이렇게 생겼습니다.
눈치채셨나요? hwp.KeyIndicator()[-1] 안에 현재 셀의 주소가 괄호 안에 들어 있어요.
이걸 이용해서 현재 캐럿의 셀 주소를 알아낼 수 있습니다. 저는 이렇게 문자열메서드로 추출합니다.
파이썬 문자열 다루는 문법이 익숙하지 않은 분들을 위해서 간단히 설명드리면,
코 드 | 설 명 | 실행결과 |
hwp.KeyIndicator() | 상태표시줄 관련 튜플 리턴 | (True,1,1,1,1,1,1,0, "(A1): 문자 입력") |
[-1] | 그 튜플에서 가장 마지막 원소만 꺼내서 | "(A1): 문단 나눔" |
[1:] | 첫 번째 글자인 "("는 빼고 그 뒤의 문자열을 가져다가 |
"A1): 문단 나눔" |
.split(")") | ")"를 기준으로 분리해서(split) 리스트를 만들고 |
["A1", ": 문단 나눔"] |
[0] | 그 중 첫 번째 원소만 선택 | "A1" |
정도가 되겠습니다.
아주 간단히 함수로 만들어보면 아래처럼 만들 수 있겠습니다.
def GetTableCellAddr():
return hwp.KeyIndicator()[-1][1:].split(")")[0]
현재 커서가 셀 안에 있지 않은 경우도 있으니까, 해당 예외처리를 더해주면
def GetTableCellAddr():
state = hwp.KeyIndicator()[-1]
if not state.startswith("("): # 표 안에 있을 때만 "(C4)" 형태로 괄호가 들어가니까
raise AttributeError("현재 캐럿이 표 안에 있지 않습니다.")
return state[1:].split(")")[0]
조금만 더 욕심을 부려보면 이렇게.
def GetTableCellAddr():
if not hwp.CellShape: # 표 안에 있을 때만 CellShape 오브젝트를 리턴하니까
raise AttributeError("현재 캐럿이 표 안에 있지 않습니다.")
return hwp.KeyIndicator()[-1][1:].split(")")[0]
이 정도로 만들어볼 수 있을 것 같아요.
한 가지만 더 해볼까요? 커서가 표 안에 있을 때 해당 셀주소로 찾아가는 함수는 어떻게 구현할 수 있을까요?
이건 A1 셀에 커서를 두고 while문으로 한 칸씩 우측으로 이동하다가,
목표하는 셀 주소와 같을 때 while문을 종료하면 되겠죠? 코드로 구현해보면,
def SetTableCellAddr(target_addr):
while True:
current_addr = hwp.KeyIndicator()[-1][1:].split(")")[0]
hwp.Run("TableRightCell")
if target_addr == hwp.KeyIndicator()[-1][1:].split(")")[0]:
return
이렇게 작성해도 굴러가기는 하겠지만 막상 테스트해보면 몇 가지 예외들이 있죠. 크게 두 가지는,
1. 현재 셀이 A1이 아니라 끝에 있다면?
2. target_addr이 표의 범위를 넘은 값이라면?
둘 다 while문에 걸려서 다운이 되어버리겠죠.
그런 문제들 몇 가지를 보완한 코드는 약간 길어지는데,
def SetTableCellAddr(addr):
init_addr = hwp.KeyIndicator()[-1][1:].split(")")[0] # 함수를 실행할 때의 주소를 기억.
if not hwp.CellShape: # 표 안에 있을 때만 CellShape 오브젝트를 리턴함
raise AttributeError("현재 캐럿이 표 안에 있지 않습니다.")
if addr == hwp.KeyIndicator()[-1][1:].split(")")[0]: # 시작하자 마자 해당 주소라면
return # 바로 종료
hwp.Run("CloseEx") # 그렇지 않다면 표 밖으로 나가서
hwp.FindCtrl() # 표를 선택한 후
hwp.Run("ShapeObjTableSelCell") # 표의 첫 번째 셀로 이동함(A1으로 이동하는 확실한 방법 & 셀선택모드)
while True:
current_addr = hwp.KeyIndicator()[-1][1:].split(")")[0] # 현재 주소를 기억해둠
hwp.Run("TableRightCell") # 우측으로 한 칸 이동(우측끝일 때는 아래 행 첫 번째 열로)
if current_addr == hwp.KeyIndicator()[-1][1:].split(")")[0]: # 이동했는데 주소가 바뀌지 않으면?(표 끝 도착)
# == 한 바퀴 돌았는데도 목표 셀주소가 안 나타났다면?(== addr이 표 범위를 벗어난 경우일 것)
SetTableCellAddr(init_addr) # 최초에 저장해둔 init_addr로 돌려놓고
hwp.Run("Cancel") # 선택모드 해제
raise AttributeError("입력한 셀주소가 현재 표의 범위를 벗어납니다.")
if addr == hwp.KeyIndicator()[-1][1:].split(")")[0]: # 목표 셀주소에 도착했다면?
return # 함수 종료
if문도 많고 예외처리도 한 개 더 늘어나서 복잡해 보이지만
한/글을 어느 정도 다루시는 분이라면 주석만 읽어봐도 간단히 절차를 이해하실 거예요.
그리고 위 코드에 나온, 간단한 명령어 hwp.Run(명령어) 에 대해서는 다음 기회에 꼭 한 번 다루겠습니다.
우선 위 코드를 테스트해보면,
결과는,
잘 작동하네요.
그럼 오늘 포스팅은 여기서 마치겠습니다.
긴 글 읽어주셔서 감사합니다.
행복한 하루 되세요!!!
국내 유일의 파이썬+한컴오피스 업무자동화 입문강의
'아래아한글 자동화 > python+hwp 중급' 카테고리의 다른 글
한/글 파일로 사내 설문조사를 만들어 취합해보자.[1/2] (0) | 2020.08.04 |
---|---|
[파이썬-한/글] 보안모듈 설치방법(귀찮은 보안팝업 제거) (19) | 2020.07.31 |
[파이썬-한/글] 현재 커서의 페이지를 알고 싶다? (0) | 2020.07.30 |
댓글