시스템 메뉴는 윈도우 에서 윈도우 타이틀 부분 왼쪽에 위치한 아이콘을 선택하면 나오는 메뉴를 말한다.
기본적으로 많은 윈도우의 시스템 메뉴는 이렇게 윈도우에 관한 이동이나 크기조정, 최대,최소화 그리고 닫기를 가지고 있는데 이 부분은 특별히 다루는 방법은 없다.
델파이나 라자루스에서는 메뉴에 관련된것은 TMainMenu 와 TPopMenu 를 제공해 주긴 하지만 이를 가지고 시스템 메뉴를 설정할수는 없다.
그동안 저 부분을 가지고 놀 기회가 없어서 몰랐는데 저 메뉴에 아이템을 추가해 달라는 요청이 있어서 잠시 검색을 해보니 니 딱히 방법은 없고 그냥 윈도우 API 를 통해서 코딩으로 처리 하는게 다다.
우선 고전적으로 다루어 보자. 이 윈도우 API는 Windows.pas 에 있으니 uses 절에 추가하고..
procedure TForm1.btnMenuAddClick(Sender:TObject);
var
nSysMenu: HMENU; //메뉴핸들 HMENU 가 없다면(없을리가없지만) 그냥 Handle 이나 Cardinal로..
begin
nSysMenu:= GetSystemMenu( self.Handle, false); //시스템메뉴 핸들을 구하고...
InsertMenu( nSysMenu, MF_BYPOSITION, MF_SEPARATOR, 0, ''); //메뉴에 구분선 하나 추가하고
InsertMenu( nSysMenu, MF_BYPOSITION , MF_STRING, 1, 'new menu1'); // new menu1 이름으로 하나 추가
InsertMenu( nSysMenu, MF_BYPOSITION , MF_STRING, 2, 'new menu2'); // new menu2 이름으로 하나 추가
DrawMenuBar ( nSysMenu ); //메뉴를 다시 그린다.
end;
이제 시스템 메뉴를 확인해 보면...
하단에 new menu1, new menu2 라는 이름(캡션) 으로 추가된것을 확인할수 있다.
GetSystemMenu 는 시스템 메뉴의 핸들값을 얻어온다. 두번째 파라미터를 true 로 설정하면 기본 시스템 메뉴로 설정할수 있다. 추가되거나 삭제해놔도 true 로 해서 호출하면 원래대로 돌아가니 주의하자.
메뉴를 추가하려면 InsertMenu 또는 AppendMenu 함수를 사용하는데 이 둘의 차이는 원하는 위치에 넣는가 아니면 맨 마지막에 추가 하는가 이다. 파라미터 갯수의 차이가 있지만 기본적으로 메뉴를 추가하는것은 동일하다.
InsertMenu( 메뉴핸들, 위치, 타입, 아이디, 캡션);
- 메뉴핸들은 GetSystemMenu 에서 받아온 핸들값이고
- 위치는 맨위가 0 이고 순차적으로 접근할수 있고 MF_BYPOSTION 은 맨 마지막(하단)에 MF_BYCOMMAND 는 아이디 기반이다.
- 타입은 여러가지가 있는데 우선 MF_SEPARATOR 는 TMainMenu 에서 캡션을 - 으로 설정하면 생기는 구분선 으로 설정되고 MF_STRING 은 문자열 로 기본적으로 사용된다. 나중에 더 다룰지는 모르겟지만 여러가지 값이 있어 이를 사용하려면 or 연산으로 여러가지를 함께 사용할수 있다.
- 아이디 는 해당 메뉴아이템이 사용하는 아이디(일련번호) 정도쯤으로 이해해도 되는데 그냥 겹치지 않는 번호로 관리 되는거 같은데 1024 이후의 번호를 사용하는게 좋을듯 싶다.
- 캡션은 메뉴에 보일 이름이다.
DrawMenuBar 는 변경된 메뉴를 다시 그려준다. Draw 라는 이름으로 봐서는 굳이? 안써도 될꺼 같긴 한데 일단 써주자.
일단 간단하게 추가는 해봤는데 그냥 정보를 보여주려는 용도로는 이정도만 해도 될것 같다.
만약 해당 메뉴를 선택(클릭) 했을때 이벤트를 발생하여 특정한걸 하려 한다면?
TMenuItem 처럼 이벤트를 바로 연결할수는 없는것 같고 WMSysCommand 의 메세지 처리나 아니면 윈도우 프로시져 서브클래싱을 사용하여 메세지 처리를 따로 해줘야 한다.
const
SC_USER_MENU1 = WM_USER+1; // 메뉴아이디1 //WM_USER는 1024로 선언되어져 있다.
SC_USER_MENU2 = WM_USER+2; // 메뉴아이디2
//선언부
procedure WMSysCommand(var Msg: TMessage); message WM_SysCommand;
//구현부
procedure TForm1.WMSysCommand(var Msg:TMessage);
begin
case Msg.wParam of
SC_USER_MENU1: Log('Menu1 Click');
SC_USER_MENU2: Log('Menu2 Click');
end;
inherited; // 기본처리 메세지 처리를 위해 빠트리지 말자..
end;
procedure TForm1.btnMenuAddClick(Sender:TObject);
var
nSysMenu: HMENU;
begin
nSysMenu:= GetSystemMenu( self.Handle, false);
InsertMenu( nSysMenu, MF_BYCOMMAND , MF_SEPARATOR, 0, '');
InsertMenu( nSysMenu, MF_BYPOSITION , MF_STRING, SC_USER_MENU1, 'new menu1');
InsertMenu( nSysMenu, MF_BYPOSITION , MF_STRING, SC_USER_MENU2, 'new menu2');
DrawMenuBar ( nSysMenu );
end;
WM_USER 는 Windows 에서 사용자 정의 로 사용하라고 기준번호인데 다른 메세지 번호와 겹치지 않고 사용할수가 있지만 혹시 모르니 주의해서 써야 하고 WM_APP 도 있다. 두개의 차이는 .... 멀까용~
고전적으로 WM_USER+1 부터 시작해서 사용들 하니 그런갑다 하자.
시스템메뉴 아이디 상수는 SC_ 로 시작되고 여러가지가 있으니 살펴보자.
기본적으로 이렇게 쓰면 된다. 상수 선언 하는게 맘에 안들지만 뭐 그냥 이정도로....삽질은 마감...
'삽질 > 델파이' 카테고리의 다른 글
델파이/라자루스 에서 IP Helper API 사용하기. (0) | 2025.03.22 |
---|---|
delphi Enum 에서 상수값을 문자열로... 또 반대로.. (0) | 2025.03.17 |
delphi / php 에서 강제 파일 다운로드 (0) | 2025.01.25 |
delphi / ip 문자열 <-> 숫자 (0) | 2025.01.21 |
키움증권 해외파생 - OpenAPI(w) 자동로그인/계좌비번설정 자동화 (0) | 2024.02.26 |