뷰에서 다이얼로그 박스를 만들지 않고 버튼을 뷰 화면에 만드는 방법을 알고 싶습니다.
일반적으로 CWnd에서 상속받은 윈도우에 버튼을 넣고 싶으면 다음과 같이 해보세요.
[1] 자신이 특별히 사용할 버튼을 CButton으로부터 상속받는다.
class iMyButton : public CButton
{
...
};
[2] 윈도우 클래스(CChildView)에 멤버로 버튼을 가지게 한다.
class CChildView : public CWnd
{
// Construction
public:
CChildView();
private:
iMyButton
m_btn;
...
//
메시지 맵 함수를 생성
protected:
//
{{AFX_MSG(CChildView)
...
afx_msg
void OnParentNotify(UINT message, LPARAM lParam);
//
}} AFX_MSG
DECLARE_MESSAGE_MAP()
};
[3] 부모 윈도우가 생성될 때 버튼도 생성시킨다.
void CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
CRect
rcBtn(30, 50, 150, 90);
m_btn.Create("MyBtn",
BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
rcBtn,
this, IDC_MY_BUTTON);
}
[4] 버튼을 생성/소멸할 때나 버튼을 눌렀을 때 특별한 처리를 해주고 싶으면 WM_PARENTNOTIFY 메시지를 처리해준다.
void CChildView::OnParentNotify(UINT message, LPARAM lParam)
{
switch(message)
{
case WM_CREATE :
TRACE("CChildView::OnParentNotify
--> WM_CREATE\n");
break;
case
WM_DESTROY :
TRACE("CChildView::OnParentNotify
--> WM_DESTROY\n");
break;
case
WM_LBUTTONDOWN :
TRACE("CChildView::OnParentNotify
--> WM_LBUTTONDOWN\n");
break;
case
WM_MBUTTONDOWN :
TRACE("CChildView::OnParentNotify
--> WM_MBUTTONDOWN\n");
break;
case
WM_RBUTTONDOWN :
TRACE("CChildView::OnParentNotify
--> WM_RBUTTONDOWN\n");
break;
}
}
비주얼 C++ 5.0 으로 다이얼로그에서 프린트가 되는 기능을 구현하고 있는데, 프린트 미리보기를 어떻게 구현해야 할지를 모르겠습니다. 방법을 알려주세요.
미리보기에 대한 함수는 다음과 같습니다.
void 뷰클래스명::OnFilePrintPreview()
{
CFilePrintPreviewState
*pState = new CPrintPreviewState;
if(!DoPrintPreview(AFX_IDD_PREVIEW_TOOLBAR,
this,
RUNTIME_CLASS(뷰클래스명,
pState))
{
TRACE0("Error
: DoPrintPreview failed");
AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
delete
pState;
}
}
보다 자세한 것을 알고 싶으면 비주얼 C++의 도움말을 참조하세요. "도움말->SEARCH->QUERY" 에서 쿼리(Query) 안을 보면 에디트 박스가 있는데, 거기에서 CPrintPreviewState을 입력하고 엔터(혹은 밑에 있는 Query를 클릭)를 치면 됩니다.
CListCtrl에서 오른쪽 마우스 버튼을 눌렸을 때 데이터의 수정, 삽입, 삭제를 나타내는 팝업메뉴를 구현하고 싶습니다. 비주얼 C로 프로그래밍하는 것은 처음이라서 방법을 잘 모르겠습니다. 자세한 설명 부탁드립니다.
다음과 같이 해보면 해결할 수 있을 것입니다.
void CMyListCtrl::OnRButtonDown(UINT nFlags, CPoint point)
{
CMenu
menu;
// 물론 IDR_POPUP이란 메뉴가 리소스
편집기로
// 작성되 있어야 합니다.
VERIFY(menu.LoadMenu(IDR_POPUP));
//
첫 번째 서브메뉴를
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup
!= NULL);
CRect viewRect;
GetWindowRect(&viewRect);
//
화면에 출력합니다.
pPopup->TrackPopupMenu(
TPM_LEFTALIGN
| TPM_RIGHTBUTTON,
point.x
+ viewRect.left,
point.y
+ viewRect.top,
this
);
CListCtrl::OnRButtonDown(nFlags,
point);
}
다이얼로그 박스의 에디트 상자에서 값을 입력받아 부모 윈도우에 직선을 그리는 프로그래밍을 하고 있습니다. 다이얼로그 박스의 에디트 상자에서 입력받은 값을 뷰 클래스의 draw 함수와 연결하고 싶습니다.
질문한 내용의 해결 방법은 의외로 쉽습니다. 우선 다이얼로그 박스를 만들고 값을 입력받는 에디트 박스에 멤버 변수를 설정합니다. 이 과정은 클래스 위저드에 멤버 탭을 누르고 해당 컨트롤을 선택하면 변수를 입력할 수 있습니다. 여기서 만든 다이얼로그가 CInputDlg, 멤버 변수가 m_iVal이고, CView에서 특정 메뉴를 선택했다면 다음과 같이 하면 됩니다.
CView::OnInputValue()
{
CInputDlg MyDlg;
// 객체를 하나 만듭니다.
MyDlg.m_iVal
= 5; // 초기값을 여기서 설정해도 됩니다.
if(MyDlg.DoModal()
== IDOK) { // 설정이 완료되면
//
대화 상자의 값을 읽어 들입니다.
m_iLineWidth
= MyDlg.m_iVal;
//
//
원하는 작업을 수행합니다.
}
아스키 값을 Hex로 바꾸는 함수가 어떤 것인지 궁금합니다.
Hex 문자열을 정수값으로 변환하는 프로그램을 말하는 것 같은데 다음의 루틴을 이용해 보기 바랍니다. 런타임 라이브러리에는 그런 함수가 없는 걸로 알고 있습니다.
#include "math.h"
#ifdef _DEBUG
#undef THIS_FILE
static
char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#undef
//
UINT
StrHexToInt(LPCTSTR str)
{
return (UINT)StrHexToLong(str);
}
ULONG
StrHexToLong(LPCTSTR str)
{
CString work;
int
nLength;
ULONG ulRetVal;
work
= str;
if(strstr(str, "0x") !=
NULL)
work =
strstr(str, "0x") + 2;
//
nLength
= work.GetLength() - 1;
ulRetVal = 0;
work.MakeUpper();
for(int
i=0; i<work.GetLength(); i++, nLength--) {
switch(work.GetAt(i))
{
case '0' :
case
'1' :
case '2'
:
case '3' :
case
'4' :
case '5'
:
case '6' :
case
'7' :
case '8'
:
case '9' :
ulRetVal
+= (work.GetAt(i) - '0') * (int)pow(16, nLength);
break;
case
'A' :
case 'B'
:
case 'C' :
case
'D' :
case 'E'
:
case 'F' :
ulRetVal
+= (10 + work.GetAt(i) - 'A') * (int)pow(16, nLength);
break;
default
:
return
ulRetVal = 0;
}
}
return
ulRetVal;
}
십진수로 변환되면 다른 진수로도 충분히 바꿀 수 있을 것입니다.
프린트 프로그래밍을 하고 있습니다. 그런데 가로로 프린트를 해야 하는데 있어서 문제가 발생했습니다. 코드는 다음과 같습니다.
DEVMODE dm;
memset(&dm, 0, sizeof(dm));
dm.dmSpecVersion = DM_SPECVERSION;
dm.dmSize
= sizeof(dm);
dm.dmFields = DM_ORIENTATION;
dm.dmOrientation = DMORIENT_LANDSCAPE;
pDC->ResetDC(&dm);
이렇게 지정을 했는데 문제는 그 다음 페이지부터 가로로 인쇄가 된다는 것입니다. 그리고 윈도우 NT 환경에서는 이 작업이 진행되지 않습니다. 해결 방법을 알려주세요.
가로 인쇄 제어를 다음과 같은 방법으로 해 보세요.
CDC dc;
CPrintDialog dlg1(FALSE), dlg2(FALSE);
dlg1.GetDefaults();
LPDEVMODE
pDM = dlg1.GetDevMode();
// ++
if(pDM == NULL) {
AfxMessageBox(IDS_NOT_READY_PRINTER,
MB_ICONSTOP);
return;
}
pDM->dmOrientation
= DMORIENT_LANDSCAPE;
pDM->dmPrintQuality = 300;
pDM->dmYResolution
= 300;
dlg2.m_pd.hDevMode = (HANDLE)pDM;
if(dlg2.DoModal() ==
IDOK)
dc.Attach(dlg2.GetPrinterDC()); //
PrinterDC를 얻는다.
else
return;
DOCINFO
di;
::ZeroMemory(&di, sizeof(DOCINFO));
di.cbSize = sizeof(DOCINFO);
di.lpszDocName
= "Preset Pulse Graph Printing...";
if(dc.StartDoc(&di)
> 0) {
// 필요한 데이터를 출력한다.
}
내 컴퓨터에 깔려있는 폰트를 얻으려면 어떻게 해야 하나요? 예를 들어서 리스트 박스나 콤보 박스에 내 컴퓨터의 폰트가 모두 보이게 하려면 어떤 함수를 써야 하는지 궁금합니다.
다음의 함수를 사용하면 됩니다.
int EnumFontFamiliesEx(HDC hdc, //
DC 제어
LPLOGFONT lpLogFont, //
논리적인 폰트정보 포인터
FONTENUMPROC lpEnumFontFamExProc,
// 콜백함수 포인터
LPARAM lParam,
//
애플리케이션 데이터
DWORD dwFlags //
reserved; must be zero
);
위 함수는 lpLogFont에 지정된 폰트들이 존재하면 lpEnumFontFamExProc에 등록된 CALLBACK 함수를 호출합니다. lpEnumFontFamExProc의 원형은 다음과 같습니다.
int CALLBACK EnumFontFamExProc(
ENUMLOGFONTEX
*lpelfe, // 논리적인 폰트 데이터 포인터
NEWTEXTMETRICEX
*lpntme, // 물리적인 폰트 데이터 포인터
int
FontType, //
폰트 형태
LPARAM lParam //
정의된 애플리케이션 데이터
);
사용자는 이 함수에서 전달되는 폰트의 정보로 리스트 박스에 이름을 등록한다던가 아니면 다른 장소에 정보를 보관하면 됩니다. 이해를 돕기 위해 간단한 상황을 만들어 예를 보여드리겠습니다.
대화 상자에 IDC_LIST1 이라는 리스트 박스가 존재한다.
대화 상자가 열렸을 때 IDC_LIST1 박스에 폰트의 목록을 등록한다.
이때 대화 상자의 클래스명은 CMyFontDlg 이다.
우선 WM_INITDIALOG 메시지를 처리하는 OnInitDialog 함수를 살펴보겠습니다.
BOOL CMyFontDlg::OnInitDialog()
{
CDialog::OnInitDialog();
CListBox
*pList = (CListBox *)GetDlgItem(IDC_LIST1);
if(pList
!= NULL) {
CMainFrame
*pMain = (CMainFrame *)AfxGetMainWnd();
CView
*pView = pMain->GetActiveView();
CDC
*pDC = pView->GetDC();
LOGFONT
lfont;
lfont.lfCharset
= DEFAULT_CHARSET;
lfont.lfFaceName[0]
= '\0'; // NULL 스트링 설정
lfont.lfPitchAndFamily
= 0; // 모든 언어 선택
//
MyFontCallBack 함수에 lParam 인자로 pList의
//
포인터를 전달합니다.
EnumFontFamiliesEx(pDC->m_hDC,
&lfont,
MyFontCallBack,
(LPARAM)pList,
0
);
pView->ReleaseDC(pDC);
}
return
TRUE;
}
// OnInitDialog에서 EnumFontFamiliesEx 함수의 lParam 값에
// CListBox의
포인터를 넣었으므로 이 함수는 호출되면
// lParam에는 CListBox의 포인터가
전달된다.
// 그리고 계속 폰트 정보를 받으려면 0이 아닌 값을
// 리턴하고,
중지하려면 0을 리턴합니다.
int CALLBACK CMyFontDlg::MyFontCallBack(ENUMLOGFONTEX
*lpelfe,
NEWTEXTMETRICEX *lpntme,
int
FontType,
LPARAM lParam )
{
CListBox
*pList = (CListBox *)lParam;
// listbox에
폰트 이름을 넣습니다.
// lpelfe의 다른 정보를
사용하시려면 도움말을 참조..
if(pList->AddString(lpelfe->elfLogFont.lfFameName)
== LB_ERR)
return
0;
return 1;
}
동작을 살펴보면 만일 시스템에 '굴림체', '바탕체', '돋움체' 등 3개의 폰트가 설치돼 있다고 가정하면 MyFontCallBack 함수는 각 폰트마다 한번씩 호출되니까 총 3번 호출이 됩니다. 폰트에 대한 완전한 정보를 보관하고 싶으면 LOGFONT의 배열을 설정한 후 CallBack 함수가 호출될 때마다 그 정보를 저장하면 됩니다.
- the end of this article -