간단하지만 경우에 따라 꽤 유용하게 쓸 수 있는 팁입니다.
(아쉽게도, Delphi/C++Builder의 XE2 버전 이상에서만 가능한 기능입니다 -.-;;)
VCL에 InputQuery와 InputBox라는 함수가 있습니다. 아주 초보적인 함수인데, 아주 자주 쓰는 개발자도 있고 전혀 존재조차 모르는 분들도 꽤 많이 있습니다. 이 두 함수는 본질적으로 거의 같은 함수인데, 조그만 다이얼로그가 떠서 문자열을 입력받아 전달해주는 함수입니다. 가령 다음과 같이 한줄을 코딩하면,
1 |
Label1.Caption := InputBox('아이디 입력', '아이디: ', 'imp'); |
이 코드가 실행될 때 다음과 같은 다이얼로그가 나타납니다.
파라미터를 자세히 설명할 것도 없이 위 코드와 그림을 비교해보시면, 첫번째 인자는 다이얼로그의 타이틀에, 두번째 인자는 입력할 에디트의 바로 위에, 세번째 인자는 에디트의 기본값으로 나타난다는 것을 아실 수 있겠지요? 그리고 짐작하시겠지만 여기에 입력한 내용은 Label1에 나타나게 됩니다. 즉 에디트에 입력한 내용이 InputBox()의 리턴값입니다.
InputQuery()는 기본적으로 같은 함수인데 약간 다릅니다. 리턴값이 boolean 타입이라, 사용자가 OK 혹은 Cancel을 누른 결과가 리턴됩니다. 즉 InputBox()에서는 사용자가 Cancel을 클릭하더라도 에디트를 비운 상태에서 OK를 클릭한 것과 구분이 되지 않습니다만, InputQuery()에서는 구분이 됩니다. 대신 입력한 리턴값은 마지막 인자로 돌아옵니다. 즉 InputQuery()에서는 마지막 인자를 var 타입 변수로 넘겨줘야 합니다.
(InputBox()는 내부적으로 InputQuery()를 호출합니다)
그런데, 패스워드를 입력받으려면 어떻게 해야 할까요? 패스워드를 입력받으려면 에디트에서 입력되는 글자들이 보이지 않아야 하는데요. 이게 그냥 TEdit를 액세스할 수 있다면 TEdit의 PasswordChar 속성을 ‘*’로 설정해버리면 간단히 되는데, 다이얼로그에 나타나는 에디트의 PasswordChar 속성을 직접 액세스하기 어렵지요. XE까지의 버전에서는 방법이 없었습니다. InputBox()나 InputQuery()에서 패스워드 기능을 너무나 원했던 외국의 개발자들은, 다이얼로그 안의 TEdit의 핸들을 찾아 윈도우 메시지로 PasswordChar를 설정해주는 방법을 쓰기도 했습니다.
물론 직접 폼을 만들어서 이런 다이얼로그를 만드는 일은 간단합니다. 그런데 아주 간단히만 쓰려고 하는데 폼을 하나 더 추가하기가 더 번거로울 때도 있습니다.
이게, XE2 버전부터는 간단히 되게 되었습니다. 마침 InputBox() 함수를 쓸 일이 있어 VCL의 소스를 뒤졌는데, 그런 기능이 추가되었더군요. 그런데 좋은 기능을 추가해놓고도 헬프와 문서에는 없습니다. 델파이, C++빌더의 헬프를 아무리 봐도 패스워드 입력 기능에 대한 아무런 언급이 없네요. VCL 소스를 직접 뒤져봐야지만 그런 기능이 추가되었다는 사실을 알 수 있습니다.
어쨌든, InputBox()와 InputQuery()에서 패스워드 입력 기능을 쓰려면, 방법은 아주 간단합니다. 두번째 인자 앞에, 문자코드가 32보다 작은 문자를 하나 더 붙여주기만 하면 됩니다. 앞에 덧붙여진 32보다 작은 문자 값은 화면에 나타나지 않고 무시됩니다. (InputQuery()도 마찬가지입니다)
1 |
Label1.Caption := InputBox('아이디 입력', #31 + '아이디: ', 'imp'); |
여기서, VCL의 개발자가 32보다 작은 값으로 정했던 이유는 간단합니다. 문자코드 32는 스페이스이고, 이 스페이스부터 화면에 보이는 영숫자 등의 문자들입니다. 31이나 그보다 작은 값들은 제어코드로서 화면에 나타나지 않는 문자들이기 때문에, 개발자가 화면에 표시할 문자열에 31이나 그보다 작은 문자를 포함시킬 리가 없으니까요.
아주 중요한 기능은 아니고 편의 기능에 불과하긴 하지만, 적지 않은 개발자들이 오랫동안 바랬던 기능인데, 드디어 추가하고도 문서에 추가하지 않은 것은 좀 어이가 없습니다.
쓴 김에 마저 언급하자면, XE2 이후의 InputQuery()에는 여러 값을 입력받을 수 있는 기능도 추가되었습니다. InputQuery() 함수 자체가 여러 버전으로 오버로드되어, 여러 값들을 전달하고 받을 수 있게 되었습니다. (InputBox()는 입력된 값을 단 하나의 결과값만 리턴받기 때문에 불가능합니다)
긴 설명보다는 간단한 예제 코드가 더 이해하기 쉽겠죠? 아래는 델파이 코드입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
procedure TForm1.Button1Click(Sender: TObject); var sValues: array[0..1] of string; sUserID, sPassword: string; begin if InputQuery('로그인', ['아이디: ', #31+'패스워드: '], sValues) then begin sUserID := sValues[0]; sPassword := sValues[1]; end else ShowMessage('로그인 취소하셨네용?'); end; |
C++빌더라면 다음과 같이 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void __fastcall TForm3::Button1Click(TObject *Sender) { String sUserID, sPassword; String sPrompts[2], sValues[2]; sPrompts[0] = "아이디: "; sPrompts[1] = String(Char(31))+"패스워드: "; if(InputQuery("로그인", sPrompts, 1, sValues, 1)) { sUserID = sValues[0]; sPassword = sValues[1]; } else ShowMessage("로그인 취소하셨네용?"); } |
위 코드의 결과는 다음과 같습니다.
즉, 두번째, 세번째 인자에 각각 두 개의 값을 전달하게 되는데요. 둘 다 array of string 입니다만 세번째 인자는 var로 받아야 하기 때문에 array of string 변수로 선언해놓고 넘겨줘야 합니다. 그리고 앞에서 설명했듯이, 두번째 입력 에디트는 패스워드를 입력받아야 하므로 두번째 인자 배열의 두번째 ‘패스워드:’ 문자열 앞에 #31을 붙여줬습니다. (물론 단지 두개만이 아니라 10개, 20개 이상도 가능합니다)
이렇게 여러 값을 입력받을 수 있다는 사실도, 문서에는 역시 안나와있습니다. 단지 오버로드된 함수들의 프로토타입들만 보여줄 뿐, 설명에는 하나의 입력만 가능했던 이전 버전들의 설명 텍스트가 그대로입니다. 그래서 오버로드된 선언을 유심히 보지 않으면 그런 기능이 있는줄 알 수조차 없습니다. 코드 샘플 페이지에도 이전의 단순한 예제만 그대로 있고요. 그래서, 지금도 구글링을 해보면, 델파이 최근 버전들에서 여러 값을 입력받기 위해 직접 구현해서 소스를 공개한 개발자들까지 있습니다. (대체 엠바카데로는 일을 어떻게 하는 거야? -.-;;)
뭐, 세심한 디자인이 필요한 프로젝트라면 당연히 이런 다이얼로그도 직접 디자인해서 폼으로 추가하는 게 맞겠지만, 간단한 프로젝트, 예를 들어 파일럿 프로그램 같은 것을 만드는 데에 일일이 입력용 다이얼로그를 다 디자인해서 폼으로 추가하기는 번거롭겠지요. 그럴 때 아주 유용하게 쓸 수 있겠습니다.
좋은 정보 감사합니다. 간단한 프로젝트에서 패스워드 입력폼 일일이 만들기 귀찮았었는데 이젠 안만들어도 되겠네요.
우앙.. 너무나 도움이 됐습니다. InputQuery 에 이런 기능이 있었다니…
좋은 정보 감사드립니다. 당연히 안된다고 생각해서 매번 폼을 만들었는데…;
Password 하니까 떠오르는 것인데….델파이에도 입력할 때는 글자가 표시되고 커서가 이동하고 나서는 암호처리가 되는 기능이 있으면 좋겠어요.
오 감사합니다!
좋은정보감사합니다 쉽게하는방법이 있을꺼라 생각해서 한참 찾았는데 알려주셔서 감사하여
업무에 바로 적용하였습니다