인프런 커뮤니티 질문&답변

한파엑셀님의 프로필 이미지
한파엑셀

작성한 질문수

직장인에게 꼭 필요한 파이썬-아래아한글 자동화 레시피

질문을 남겨주세요.

Hset, Pset 질문드립니다.

해결된 질문

작성

·

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에 대한 원론적인;;; 설명을 간략히 드리겠습니다.

(설명이 다소 장황할 수 있다는 점, 양해 부탁드립니다.)

 

1. 한/글 오토메이션 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를 사용하는 개발자 입장에서는 굉장히 까다로운 인터페이스지만,
속도나 메모리 측면에서 우위가 있어 이렇게 설계한 게 아닐까 추측만 해봅니다.

 

2. 새로운 방식의 인터페이스 개발

그리고, 무슨 연유인지는 정확히 모르겠지만

(위와 완전히 동일한 동작을 하는) 비슷한 인터페이스를 하나 더 개발합니다.

비교적 "새로운" 방식일 뿐, 20여년 가까이 되었습니다.

기존의 문법도 그대로 남겨두고요.

아래 코드는 완전히 동일한 동작을 합니다.

pset = hwp.HParameterSet.HInsertText
hwp.HAction.GetDefault("InsertText", pset.HSet)
pset.Text = "Hello world!"
hwp.HAction.Execute("InsertText", pset.HSet)

이는 스크립트매크로를 통해 공개되는 API로,

기존의 CreateAction 이나 CreateSet 명령어를 쓰지 않는 대신

예전에는 사용하지 않던 HActionHParameterSet 이라는 멤버를 사용하는데요.

각 오브젝트명 앞에 붙은 H는 Hangul의 H가 아니라, Handle을 뜻하는 H입니다.
H나 I, X 같은 접두사는 윈도우API 코딩 컨벤션 같은 겁니다.
핸들은 일종의 "포인터"같은 개념인데, 실제 메모리주소를 가리키는 건 아니지만
내부적인 자원의 참조를 해줍니다.

(드디어 본론인 HAction 오브젝트가 나왔네요ㅎ)

 

3. HAction의 기능과 역할

사실 HAction 오브젝트에는 새로운 기능이 없습니다. 그 대신,

기존의 act.GetDefault, act.PopupDialog , act.Executehwp.Run 등의 액션메서드를

hwp.HAction이 중복으로 가지고 있는 형태입니다.

 

① 기존에는 hwp.CreateAction메서드와 액션아이디를 통해

액션오브젝트인 act를 먼저 생성한 후에,

act.GetDefault, act.PopupDialog, act.Execute 명령어로 액션을 실행했는데

새로운 방식은, hwp.HAction 하나가 모두 담당하기 때문에

굳이 act 객체를 생성할 필요가 없다는 점, 그리고

 

② 기존에는 파라미터셋(pset)이 act에 종속되어 생성되는 방식인 반면,

새 인터페이스에서는 act와 완전히 독립된 HParameterSet이라는 오브젝트를 통해

아이템을 조회하고 설정할 수 있게 되었습니다.

 

③ 사용자 입장에서 새 인터페이스(HActionHParameterSet를 사용하는 방식)의 가장 큰 장점은

파라미터셋의 아이템 목록이 문자열이 아닌 프로퍼티 형태로 매핑되어 있기 때문에

에디터를 통해 직접 조회할 수 있게 되었다는 점인데요. (이 부분 때문에 저도 새 방식을 선호하고요.)

녹화_2024_09_18_12_48_22_368.gif

 

④ 질문의 제목에도 언급하신 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)  # ???

 

4. Run 메서드의 정체는?

간혹 어떤 액션들은 파라미터셋이 전혀 필요없거나, 기본값으로 충분한 것들이 있습니다.

예를 들어 CopyPaste 같은 단순한 액션들요.

이런 것들을 위해서까지

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를 리턴해준다는 차이가 있습니다.

그럼 이제 마지막으로,

 

5. pyhwpx의 인터페이스

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에서는 액션아이디를 간편하게 쓰려고 함수를 짜 두었고요.)

 

① Run 액션은 한 줄이면 됩니다.

hwp.Run(액션아이디) 방식은 다른 코드 없이 한 줄만 실행하시면 됩니다.

공식문서 중 actionobject.pdfAction Table.hwp를 보시면

파라미터셋이 "없음"으로 표시돼 있는 액션아이디가 많이 보입니다.

그런 액션은 모~두 예외없이 Run으로 실행 가능합니다.

image.png

 

② 그 외의 경우는 hwp.HAction.Execute로만 실행 가능하고요.

예를 들어 "쪽번호 매기기"로 공식문서 중 액션테이블을 검색해보면

"PageNumPos"라는 액션아이디가 나옵니다.

image.png

이건 파라미터셋아이디 이름도 (특이하게) 액션과 동일한 "PageNumPos"네요.

 

이 문자열을 가지고 파라미터셋 문서에서 검색해보시면

아래와 같이 나옵니다. (H가 붙어있지만 같은 객체입니다. H는 핸들을 의미합니다.)

 

image.png

 

이를 참고해서 하단 중앙에 쪽번호를 넣는 코드를 짜면 아래와 같습니다.

pset = hwp.HParameterSet.HPageNumPos
hwp.HAction.GetDefault("PageNumPos", pset.HSet)
pset.DrawPos = 5  # == hwp.PageNumPosition("BottomCenter")
hwp.HAction.Execute("PageNumPos", pset.HSet)
녹화_2024_09_18_17_24_37_938.gif

 

스크립트매크로를 통해 도움을 받을 수도 있습니다.

쪽번호를 생성하는 동작을 녹화해보면

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) 하는 등의 다양한 작업을 수행할 수 있습니다.

다음의 링크들은 유사한 질문에 대한 답변을 포함하고 있어서 도움이 될 것입니다:

  1. copypage 라는 명령어는 어디서 보나요?

    • 이 링크에서는 CopyPage와 같은 명령어가 Action 명령어로 어떻게 동작하는지에 대해 설명하고 있습니다.
  2. 엑셀 문서값을 피드에서 응용하기 부분에서 질문 있습니다.

    • CopyPagePastePage가 한컴오피스 2014VP 이상의 버전에서만 사용 가능하다는 정보가 포함되어 있습니다.
  3. 한글-파이썬 : 바탕쪽, 다단

    • HAction을 사용한 여러 다른 명령어의 예제와 함께 기본적인 사용법을 설명합니다.

각각의 게시물에서 HAction과 동작 작동 원리에 관련된 구체적인 예제 코드와 설명을 확인하실 수 있으며, 이를 통해 더욱 깊이 있는 이해를 도울 수 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

한파엑셀님의 프로필 이미지
한파엑셀

작성한 질문수

질문하기