해결된 질문
작성
·
139
1
hwpctrl과 action table은 어떻게 사용할지 알겠는데,
pyhwpx 내부의
self.hwp.HAction.Run("CopyPage")
self.hwp.HAction.Run("PastePage")
self.hwp.HAction.Run("DeletePage")
등등은 작동원리가 어떻게 되는지 궁금합니다.
HAction에 대해 이해가 없어서 알려주시면 감사하겠습니다 :)
====================================
답변 2
1
레몬민트님 안녕하세요?
self.hwp.HAction.Run(액션아이디)
에 대해 설명드리기 전에
먼저 한/글 오토메이션 API에 대한 원론적인;;; 설명을 간략히 드리겠습니다.
(설명이 다소 장황할 수 있다는 점, 양해 부탁드립니다.)
한/글 오토메이션 API도
일반 API들과 마찬가지로 메서드와 프로퍼티를 제공합니다.
예를 들면 hwp.Open()
이나 hwp.Save()
, hwp.GetPos()
라든지, hwp.HeadCtrl
같은 것들요.
그런데 아래아한글은 그 외에도 어마어마하게 기능이 많기 때문에
모든 아래아한글 기능을 메서드로 만드는 대신
(기능들의 원래 시그니쳐나 핸들은 비공개로 두고)
각 기능을 특정 문자열과 매핑하여,
"액션"이라는 이름의 인터페이스로 제공하고 있습니다.
(공식문서에는 이를 "Object Oriented" 가 아닌, "Action Oriented" 라고 부르더라고요.)
예를 들어,
"문자열삽입"라는 액션은 "InsertText"
문자열과 매핑되어 있습니다.
그런데 액션이 실행되는 방식들이 다양하기 때문에 파라미터가 필요합니다.
일반적인 함수에도 파라미터 입력에 따라 동작이 달라지는 것처럼
아래아한글의 액션들 중 대부분도 다양한 파라미터를 받습니다.
근데 이게, 파라미터 수가 여간 만만치 않습니다.
극단적인 예로, 컨트롤의 모양을 결정하는
HShapeObject
라는 파라미터셋은
파라미터 아이템이 60개 정도 됩니다. 함수 방식이었다면 스택프레임 메모리 소모도 상당하겠지요.
그래서 아래아한글 개발진은 신박한 인터페이스를 개발해냅니다.
전통적인 함수(파라미터1=a, 파라미터2=b, ...)
방식의 인터페이스가 아니라
act = hwp.CreateAction("InsertText") # 액션개체 생성
pset = hwp.CreateSet(act) # 파라미터셋 개체 생성(== pset = act.CreateSet())
act.GetDefault(pset) # 파라미터셋 초기화(현재 문서값 대입)
pset.SetItem("Text", "Hello world!") # 파라미터셋 아이템 설정
act.Execute(pset) # 파라미터셋 적용
이런 일련의 시퀀스 방식을 고안해냅니다.
API를 사용하는 개발자 입장에서는 굉장히 까다로운 인터페이스지만,
속도나 메모리 측면에서 우위가 있어 이렇게 설계한 게 아닐까 추측만 해봅니다.
그리고, 무슨 연유인지는 정확히 모르겠지만
(위와 완전히 동일한 동작을 하는) 비슷한 인터페이스를 하나 더 개발합니다.
비교적 "새로운" 방식일 뿐, 20여년 가까이 되었습니다.
기존의 문법도 그대로 남겨두고요.
아래 코드는 완전히 동일한 동작을 합니다.
pset = hwp.HParameterSet.HInsertText
hwp.HAction.GetDefault("InsertText", pset.HSet)
pset.Text = "Hello world!"
hwp.HAction.Execute("InsertText", pset.HSet)
이는 스크립트매크로를 통해 공개되는 API로,
기존의 CreateAction
이나 CreateSet
명령어를 쓰지 않는 대신
예전에는 사용하지 않던 HAction
과 HParameterSet
이라는 멤버를 사용하는데요.
각 오브젝트명 앞에 붙은
H
는 Hangul의 H가 아니라, Handle을 뜻하는 H입니다.
H나 I, X 같은 접두사는 윈도우API 코딩 컨벤션 같은 겁니다.
핸들은 일종의 "포인터"같은 개념인데, 실제 메모리주소를 가리키는 건 아니지만
내부적인 자원의 참조를 해줍니다.
사실 HAction 오브젝트에는 새로운 기능이 없습니다. 그 대신,
기존의 act.GetDefault
, act.PopupDialog
, act.Execute
및 hwp.Run
등의 액션메서드를
hwp.HAction
이 중복으로 가지고 있는 형태입니다.
① 기존에는 hwp.CreateAction
메서드와 액션아이디를 통해
액션오브젝트인 act
를 먼저 생성한 후에,
act.GetDefault
, act.PopupDialog
, act.Execute
명령어로 액션을 실행했는데
새로운 방식은, hwp.HAction
하나가 모두 담당하기 때문에
굳이 act
객체를 생성할 필요가 없다는 점, 그리고
② 기존에는 파라미터셋(pset
)이 act
에 종속되어 생성되는 방식인 반면,
새 인터페이스에서는 act
와 완전히 독립된 HParameterSet
이라는 오브젝트를 통해
아이템을 조회하고 설정할 수 있게 되었습니다.
③ 사용자 입장에서 새 인터페이스(HAction
과 HParameterSet
를 사용하는 방식)의 가장 큰 장점은
파라미터셋의 아이템 목록이 문자열이 아닌 프로퍼티 형태로 매핑되어 있기 때문에
에디터를 통해 직접 조회할 수 있게 되었다는 점인데요. (이 부분 때문에 저도 새 방식을 선호하고요.)
④ 질문의 제목에도 언급하신 pset.HSet
은
기존 인터페이스에서 pset = hwp.CreateSet(act)
를 통해 만들어지는 pset
객체와
동일한 기능을 한다고 보시면 됩니다. (완전히 동일한 인스턴스는 아니지만요.)
극단적인 예로, 기존 인터페이스와 신규 인터페이스를 아래처럼 마구 섞어도 잘 작동합니다.
act = hwp.CreateAction("InsertText") # old
pset = hwp.HParameterSet.HInsertText # new
pset.HSet.SetItem("Text", "Hello world!") # ???
act.Execute(pset.HSet) # ???
간혹 어떤 액션들은 파라미터셋이 전혀 필요없거나, 기본값으로 충분한 것들이 있습니다.
예를 들어 Copy
나 Paste
같은 단순한 액션들요.
이런 것들을 위해서까지
act = hwp.CreateAction("Copy")
pset = act.CreateSet()
act.GetDefault(pset)
act.Execute(pset)
이렇게 긴 코드를 실행하는 건 비효율적이니까
아래아한글 개발진은 위의 시퀀스를 단축한
hwp.Run("Copy")
라는 명령을 제공합니다.
신규 인터페이스인 HAction에도, Run 메서드가 같이 제공되므로
hwp.HAction.Run("Copy")
라고 실행할 수도 있습니다.
결과는 동일하지만,
hwp.Run
메서드는 항상 None을 리턴하는 반면
hwp.HAction.Run
메서드는 성공시 True, 실패시 False를 리턴해준다는 차이가 있습니다.
그럼 이제 마지막으로,
pyhwpx.Hwp
클래스의 대부분의 메서드는
HAction
을 통해 작동하는 액션들을 메서드로 매핑한 것에 지나지 않습니다.
Hwp클래스의 내부적인 구조를 간략히 설명드리겠습니다.
Hwp 클래스 안에 hwp라는 멤버변수(self.hwp)는 win32com으로 생성한 hwp오브젝트입니다.
그래서 아래 세 가지 코드는 모두 동일한 동작을 합니다.
# 저수준 코드
import win32com.client as win32
hwp = win32.gencache.EnsureDispatch("HWPFrame.HwpObject")
hwp.XHwpWindows.Item(0).Visible = True
pset = hwp.HParameterSet.HInsertText
pset.Text = "Hello world!"
hwp.HAction.Execute("InsertText", pset.HSet)
# 위와 동일해 보이지만, 한 단계 매핑이 끼어있음
from pyhwpx import Hwp
hwp = Hwp()
pset = hwp.HParameterSet.HInsertText
pset.Text = "Hello world!"
hwp.HAction.Execute("InsertText", pset.HSet)
# 저수준의 hwp객체를 꺼내서 직접 사용함
from pyhwpx import Hwp
hwp = Hwp()
pset = hwp.hwp.HParameterSet.HInsertText
pset.Text = "Hello world!"
hwp.hwp.HAction.Execute("InsertText", pset.HSet)
1~2밀리초 정도로 속도차이가 아주 미미하기는 하지만,
한 단계라도 매핑을 줄여서 성능을 끌어올리기 위해
pyhwpx.Hwp 클래스의 대부분의 메서드는
저수준의 hwp 객체를 직접 사용하는 방식으로 코딩을 해놓은 상태입니다.
예를 들어 pyhwpx의 hwp.insert_text 메서드의 코드는 아래와 같습니다.
def insert_text(self, text):
"""
한/글 문서 내 캐럿 위치에 문자열을 삽입하는 메서드.
:return:
삽입 성공시 True, 실패시 False를 리턴함.
:example:
>>> from pyhwpx import Hwp
>>> hwp = Hwp()
>>> hwp.insert_text('Hello world!')
>>> hwp.BreakPara()
"""
param = self.hwp.HParameterSet.HInsertText
self.hwp.HAction.GetDefault("InsertText", param.HSet)
param.Text = text
return self.hwp.HAction.Execute("InsertText", param.HSet)
(노가다 작업을 통해 미리 모든 기본속성이나 메서드를 Hwp클래스에 매핑해 두었기 때문에)
위 코드에서 self.hwp
를 단순히 self
로 교체해도 코드는 정상적으로 실행됩니다.
1ms라도 실행시간을 줄여보려는 의도로
내부에서 일일이 self.hwp
를 사용하는 것입니다.
이것으로
HAction과 pset, HSet, self.hwp.HAction 등에 대한 설명을 마칩니다.
제가 과도하게 헛다리를 짚고 뜬구름 잡는 설명을 했을 확률이 높아 보입니다ㅜ
추가로 궁금한 부분은 댓글로 남겨주세요.
행복한 하루 되세요^^
방금 API 문서를 보면서 생각한건데,
그럼 이걸 사용하는건
hwp.HAction.run('Action Table')
hwp.HParameterSet.ItemName.내부함수
이렇게 사용하는게 맞을까요?
제가 설명이 너무 장황했는데,
한/글 오토메이션 API의 액션 실행방식은 원래 두 가지,
일반적인 hwp.HAction.Execute
방식과
단축방식인 hwp.HAction.Run
방식 뿐입니다.
(pyhwpx에서는 액션아이디를 간편하게 쓰려고 함수를 짜 두었고요.)
hwp.Run(액션아이디)
방식은 다른 코드 없이 한 줄만 실행하시면 됩니다.
공식문서 중 actionobject.pdf
나 Action Table.hwp
를 보시면
파라미터셋이 "없음"으로 표시돼 있는 액션아이디가 많이 보입니다.
그런 액션은 모~두 예외없이 Run으로 실행 가능합니다.
예를 들어 "쪽번호 매기기"로 공식문서 중 액션테이블을 검색해보면
"PageNumPos"라는 액션아이디가 나옵니다.
이건 파라미터셋아이디 이름도 (특이하게) 액션과 동일한 "PageNumPos"네요.
이 문자열을 가지고 파라미터셋 문서에서 검색해보시면
아래와 같이 나옵니다. (H가 붙어있지만 같은 객체입니다. H는 핸들을 의미합니다.)
이를 참고해서 하단 중앙에 쪽번호를 넣는 코드를 짜면 아래와 같습니다.
pset = hwp.HParameterSet.HPageNumPos
hwp.HAction.GetDefault("PageNumPos", pset.HSet)
pset.DrawPos = 5 # == hwp.PageNumPosition("BottomCenter")
hwp.HAction.Execute("PageNumPos", pset.HSet)
스크립트매크로를 통해 도움을 받을 수도 있습니다.
쪽번호를 생성하는 동작을 녹화해보면
function OnScriptMacro_중국어1성()
{
HAction.GetDefault("PageNumPos", HParameterSet.HPageNumPos.HSet);
with (HParameterSet.HPageNumPos)
{
DrawPos = PageNumPosition("BottomCenter");
}
HAction.Execute("PageNumPos", HParameterSet.HPageNumPos.HSet);
}
위와 같은 코드가 나오는데, 이걸 파이썬 문법으로 옮기기만 하면 됩니다.
참고로 공식문서의 샘플코드들은 대부분
다른 프로그래밍 언어 예시이기 때문에,
동작이나 개념만 충분히 이해하고 나서
강의의 코드나 스크립트매크로를
자세히 읽어보시는 걸 추천드립니다.
그런 맥락에서,
hwp.HAction.run('Action Table')
hwp.HParameterSet.ItemName.내부함수
라는 표현보다는
hwp.HAction.Run("액션") # 파라미터셋 필요없는 경우
또는
pset = hwp.HParameterSet.파라미터셋아이디
hwp.HAction.GetDefault("액션", pset.HSet)
pset.아이템A = 1
pset.아이템B = 2
pset.아이템C = 3
hwp.HAction.Execute("액션", pset.HSet)
라고 수정하는 게 적절해 보입니다^^
도움이 되었으면 좋겠습니다..
1
안녕하세요, 인프런 AI 인턴입니다.
LemonMint - Pengui님, HAction
의 작동 원리에 대해 궁금하셨군요. HAction
은 한글 문서 내에서 특정 동작을 실행하는 데 사용됩니다. 이를 통해 문서의 특정 페이지를 복사(CopyPage), 붙여넣기(PastePage), 삭제(DeletePage) 하는 등의 다양한 작업을 수행할 수 있습니다.
다음의 링크들은 유사한 질문에 대한 답변을 포함하고 있어서 도움이 될 것입니다:
CopyPage
와 같은 명령어가 Action 명령어로 어떻게 동작하는지에 대해 설명하고 있습니다.엑셀 문서값을 피드에서 응용하기 부분에서 질문 있습니다.
CopyPage
와 PastePage
가 한컴오피스 2014VP 이상의 버전에서만 사용 가능하다는 정보가 포함되어 있습니다.각각의 게시물에서 HAction
과 동작 작동 원리에 관련된 구체적인 예제 코드와 설명을 확인하실 수 있으며, 이를 통해 더욱 깊이 있는 이해를 도울 수 있습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
아뇨 안그래도 원론적인 부분이 궁금했거든요 ㅎㅎ
지금 당장은 이해가 되진 않지만, 몇 번씩 읽어보면서
이해해보겠습니다 감사합니다!