天天看點

在ObjectARX中使用MFC-标簽式對話框

先附上流程圖:

在ObjectARX中使用MFC-标簽式對話框

(1) 建立工程

在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框

 (2)插入一個對話框

輕按兩下.rc檔案

在ObjectARX中使用MFC-标簽式對話框

右鍵-》選中添加資源

在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框

修改對話框ID:IDD_OPTION_SHEET

在ObjectARX中使用MFC-标簽式對話框

 在上面添加一個Tab控件, 修改ID:IDC_TAB

在ObjectARX中使用MFC-标簽式對話框

(3)為此對話框添加映射類COptionSheet,基類為CAcUiTabMainDialog

在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框

 (4)再插入一個對話框資源(IDD_TEXT_PAGE)

右擊,選“插入dialog”

在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框

放置一個文本框

在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框

 (5)建立文字頁籤的映射類CTextPage

在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框

 (6)插入第二個頁籤對應的資源對話框(IDD_CONREOL_PAGE)

添加Group Box按鈕

在ObjectARX中使用MFC-标簽式對話框

 内部放置兩個單選按鈕(ID分别為:IDC_RADIO1和IDC_RADIO2),隻勾選第一個按鈕的Group選項

在ObjectARX中使用MFC-标簽式對話框

 添加一個複選框控件

在ObjectARX中使用MFC-标簽式對話框

點選一下對話框,修改屬性

在ObjectARX中使用MFC-标簽式對話框

 建立這個頁籤對話框的映射類CControlPage

在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框

 (7)在COptionSheet類中,為Tab控件添加映射成員變量

點選Tab控件框,右鍵選擇“添加變量”

在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框

(8) 在COptionSheet類中添加兩個成員變量

CTextPage m_textPage;

CControlPage m_controlPage;

在ObjectARX中使用MFC-标簽式對話框

 注:上圖中的變量名應為:m_textPage

在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框

 (9)建立IDD_OPTION_SHEET對話框的初始化事件

在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框

 (10)在指令的實作函數中加入下面的代碼,并添加頭檔案:#include "OptionSheet.h"

在ObjectARX中使用MFC-标簽式對話框

 這時候 編譯程式,并打開CAD,看看是否能彈出對話框

在ObjectARX中使用MFC-标簽式對話框

(11)添加一個新類CIniFile(C++正常類) ,用于讀寫INI檔案中的鍵值

在ObjectARX中使用MFC-标簽式對話框
在ObjectARX中使用MFC-标簽式對話框

(13)類的實作内容 

 IniFile.h:

#pragma once
class CIniFile
{
public:
	CIniFile();
	//~CIniFile();

	CIniFile(const TCHAR* fileName);

	virtual ~CIniFile();

	//指定字段和鍵的名稱,獲得對應的鍵值
	bool GetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, CString &strValue, int bufferLength = 1000) const;
	bool GetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, int &nValue) const;

	bool GetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, byte &byteValue) const;
	bool GetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, bool &bValue) const;

	bool GetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, double &dValue) const;

	//指定字段名和鍵的名稱,寫入對應的鍵值
	bool SetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, const TCHAR* strValue);
	bool SetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, int nValue);

	bool SetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, byte byteValue);
	bool SetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, bool bValue);

	//decimalplaces小數點位數
	bool SetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, double dValue, int decimalPlaces = 2);

private:
	CString m_strFile;//INI檔案的儲存位置
};
           

IniFile.cpp

#include "stdafx.h"
#include "IniFile.h"


CIniFile::CIniFile()
{
}


CIniFile::~CIniFile()
{
}

CIniFile::CIniFile(const TCHAR* fileName)
{
	m_strFile = fileName;
}

//指定字段和鍵的名稱,獲得對應的鍵值
bool CIniFile::GetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, CString &strValue, int bufferLength) const
{
	assert(m_strFile.GetLength() > 0);

	CString strDefault = TEXT("NotExist");//如果找不到對應的鍵,則傳回該值
	CString strTemp;

	DWORD dwCharacters = ::GetPrivateProfileString(strFieldName,
		strKeyName,
		strDefault,
		strTemp.GetBuffer(bufferLength),
		bufferLength,
		m_strFile);
	strTemp.ReleaseBuffer();

	//注意GetPrivateProfileString函數的錯誤形式
	if (strTemp.Compare(strDefault) == 0)
	{
		return false;
	}
	else
	{
		strValue = strTemp;
		return true;
	}
}

bool CIniFile::GetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, int &nValue) const
{
	CString strValue = TEXT("");
	if (GetValueOfKey(strFieldName, strKeyName, strValue))
	{
		nValue = _ttoi(strValue);
		return true;
	}
	else
	{
		return false;
	}
}

bool CIniFile::GetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, byte &byteValue) const
{
	CString strValue = TEXT("");
	if (GetValueOfKey(strFieldName, strKeyName, strValue))
	{
		byteValue = (byte)(_ttoi(strValue));
		return true;
	}
	else
	{
		return false;
	}
}

bool CIniFile::GetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, bool &bValue) const
{
	CString strValue = TEXT("");
	if (GetValueOfKey(strFieldName, strKeyName, strValue))
	{
		bValue = bool(_ttoi(strValue) == 1);
		return true;
	}
	else
	{
		return false;
	}
}

bool CIniFile::GetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, double &dValue) const
{
	CString strValue = TEXT("");
	if (GetValueOfKey(strFieldName, strKeyName, strValue))
	{
		//dValue = _tstof(strValue)//CString轉double
		TCHAR* szStop = NULL;
		dValue = _tcstod(strValue, &szStop);//CString轉double
		return true;
	}
	else
	{
		return false;
	}
}

//指定字段名和鍵的名稱,寫入對應的鍵值
bool CIniFile::SetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, const TCHAR* strValue)
{
	//防止在調用函數之前m_strFile未被初始化
	if (m_strFile.IsEmpty())
	{
		AfxMessageBox(TEXT("在調用函數SetValueOfKey時,m_strFile未被指派,異常退出"));
		return false;
	}

	BOOL bRet = ::WritePrivateProfileString(strFieldName,
		strKeyName,
		strValue,
		m_strFile);

	if (bRet)
	{
		return true;
	}
	else
		return false;
}

bool CIniFile::SetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, int nValue)
{
	CString strValue = TEXT("");
	strValue.Format(TEXT("%d"), nValue);//returns the string format
	return SetValueOfKey(strFieldName, strKeyName, strValue);
}

bool CIniFile::SetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, byte byteValue)
{
	CString strValue = TEXT("");
	strValue.Format(TEXT("%u"), byteValue);
	return SetValueOfKey(strFieldName, strKeyName, strValue);
}

bool CIniFile::SetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, bool bValue)
{
	CString strValue = TEXT("");
	strValue.Format(TEXT("%d"), bValue);
	return SetValueOfKey(strFieldName, strKeyName, strValue);
}

//decimalplaces小數點位數
bool CIniFile::SetValueOfKey(const TCHAR* strFieldName, const TCHAR* strKeyName, double dValue, int decimalPlaces)
{
	assert(decimalPlaces >= 0);
	CString strFormat = TEXT("");
	strFormat.Format(TEXT("%%0.%df"), decimalPlaces);

	CString strValue = TEXT("");
	strValue.Format(strFormat, dValue);
	return SetValueOfKey(strFieldName, strKeyName, strValue);
}
           

(13)為CTextPage窗體中的文字高度的文本框映射double類型的成員變量m_textHeight

在ObjectARX中使用MFC-标簽式對話框

 同理,為文字樣式組合框映射CComboBox成員變量m_cboTextStyle

在ObjectARX中使用MFC-标簽式對話框

(14)建立CTextPage窗體的初始化事件

在ObjectARX中使用MFC-标簽式對話框

 填充文字樣式組合框,從INI檔案中加載預設的參數值:

//填充文字樣式組合框
	std::vector<CString> textStyles;
	CTextStyleUtil::GetAll(textStyles);
	for (int i = 0; i < textStyles.size(); i++)
	{
		m_cboTextStyle.AddString(textStyles[i]);
	}
	if (m_cboTextStyle.GetCount() > 0)
	{
		m_cboTextStyle.SetCurSel(0);
	}

	//從INI檔案中加載參數值
	CIniFile iniFile(CAppDirectoryUtil::GetCurrentDirectory() + TEXT("\\OptionSheet.ini"));
	CString field = TEXT("OptionSheet");
	iniFile.GetValueOfKey(field, TEXT("textHeight"), m_textHeight);
	CString strTextStyle;
	iniFile.GetValueOfKey(field, TEXT("textStyle"), strTextStyle);

	//設定組合框的目前選擇項
	for (int i = 0; i < m_cboTextStyle.GetCount(); i++)
	{
		CString strItem;
		m_cboTextStyle.GetLBText(i, strItem);//retrieves a string from the list box of a combo box
		if (strItem.CompareNoCase(strTextStyle) == 0)//Zero if the strings are identical (ignoring case), 
		{
			m_cboTextStyle.SetCurSel(i);
			break;
		}
	}
	UpdateData(FALSE);
           

添加類AppDirectoryUtil

在ObjectARX中使用MFC-标簽式對話框

 類AppDirectoryUtil的實作

AppDirectoryUtil.h

// AppDirectoryUtil.h: interface for the CAppDirectoryUtil class.


#if !defined(AFX_APPDIRECTORYUTIL_H__DD493023_982A_4370_8A6F_C271F5FD388F__INCLUDED_)
#define AFX_APPDIRECTORYUTIL_H__DD493023_982A_4370_8A6F_C271F5FD388F__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CAppDirectoryUtil
{
public:
	CAppDirectoryUtil();

	// 功能: 獲得目前的ARX檔案所在的路徑
	static CString GetCurrentDirectory(HMODULE hInstance = _hdllInstance);

	// 功能: 獲得目前的ARX檔案所在的檔案夾的上級目錄
	static CString GetParentDirectory(HMODULE hInstance = _hdllInstance);

	~CAppDirectoryUtil();
};

#endif // !defined(AFX_APPDIRECTORYUTIL_H__DD493023_982A_4370_8A6F_C271F5FD388F__INCLUDED_)
           

AppDirectoryUtil.cpp

#include "stdafx.h"
#include "AppDirectoryUtil.h"


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif

//
// Construction/Destruction
//


CAppDirectoryUtil::CAppDirectoryUtil()
{
}


CAppDirectoryUtil::~CAppDirectoryUtil()
{
}

CString CAppDirectoryUtil::GetCurrentDirectory(HMODULE hInstance)
{
	TCHAR szPath[256];
	GetModuleFileName(hInstance, szPath, sizeof(szPath));
	*(_tcsrchr(szPath, '\\')) = 0;		// 将最後一個\所在的位置修改為\0

	CString strResult = szPath;
	return strResult;
}

CString CAppDirectoryUtil::GetParentDirectory(HMODULE hInstance)
{
	TCHAR szPath[256];
	GetModuleFileName(hInstance, szPath, sizeof(szPath));
	*(_tcsrchr(szPath, '\\')) = 0;		// 将最後一個\所在的位置設定為\0
	*(_tcsrchr(szPath, '\\')) = 0;		// 繼續将最後一個\所在的位置設計為\0

	CString strResult = szPath;
	return strResult;
}

           

 添加C++正常類:CTextStyleUtil

CTextStyleUtil.h:

#if !defined(AFX_TEXTSTYLEUTIL_H__F392A987_01EA_4AD0_BCE3_C39921CAC013__INCLUDED_)
#define AFX_TEXTSTYLEUTIL_H__F392A987_01EA_4AD0_BCE3_C39921CAC013__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <vector>
class CTextStyleUtil
{
public:
	CTextStyleUtil();
	virtual ~CTextStyleUtil();

	// 獲得某個文字樣式的ID
	static AcDbObjectId GetAt(const TCHAR* name);

	// 獲得文字樣式名稱清單
	static void GetAll(std::vector<CString> &textStyles);

	// 建立一種文字樣式
	static AcDbObjectId Add(const TCHAR* name, const TCHAR* fontFileName = TEXT("txt.shx"),
		const TCHAR* bigFontFileName = TEXT("gbcbig.shx"));
	//~CTextStyleUtil();
};

#endif // !defined(AFX_TEXTSTYLEUTIL_H__F392A987_01EA_4AD0_BCE3_C39921CAC013__INCLUDED_)

           

 CTextStyleUtil.cpp:

#include "stdafx.h"
#include "TextStyleUtil.h"
#include <dbsymtb.h>
#include <acutmem.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif

//
// Construction/Destruction
//


CTextStyleUtil::CTextStyleUtil()
{
}


CTextStyleUtil::~CTextStyleUtil()
{
}

AcDbObjectId CTextStyleUtil::GetAt(const TCHAR* name)
{
	AcDbObjectId textStyleId;

	if (_tcslen(name) > 0)//Unicode字元串的長度
	{
		AcDbTextStyleTable* pTextStyleTable = NULL;
		acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pTextStyleTable, AcDb::kForRead);
		pTextStyleTable->getAt(name, textStyleId);	// 如果不存在,textStyleId不會被指派
		pTextStyleTable->close();
	}

	return textStyleId;
}

void CTextStyleUtil::GetAll(std::vector<CString> &textStyles)
{
	textStyles.clear();

	AcDbTextStyleTable *pTextStyleTbl = NULL;
	acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pTextStyleTbl, AcDb::kForRead);
	AcDbTextStyleTableIterator *pIt = NULL;
	pTextStyleTbl->newIterator(pIt);

	for (; !pIt->done(); pIt->step())
	{
		AcDbTextStyleTableRecord *pRcd = NULL;
		if (pIt->getRecord(pRcd, AcDb::kForRead) == Acad::eOk)
		{
			TCHAR *szName = NULL;
			pRcd->getName(szName);
			if (_tcslen(szName) > 0)		// 過濾掉名稱為空的文字樣式
			{
				textStyles.push_back(szName);
			}
			acutDelString(szName);

			pRcd->close();
		}
	}
	delete pIt;
	pTextStyleTbl->close();
}

AcDbObjectId CTextStyleUtil::Add(const TCHAR* name, const TCHAR* fontFileName, const TCHAR* bigFontFileName)
{
	Acad::ErrorStatus es;
	AcDbTextStyleTable* pTextStyleTable = NULL;
	es = acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pTextStyleTable, AcDb::kForWrite);

	AcDbTextStyleTableRecord* pTextStyleRecord = new AcDbTextStyleTableRecord();
	es = pTextStyleRecord->setName(name);
	es = pTextStyleRecord->setBigFontFileName(bigFontFileName);		// 大字型檔案
	es = pTextStyleRecord->setFileName(fontFileName);	// 字型檔案
	es = pTextStyleRecord->setXScale(1.0);		// 文字高寬比(一般這裡都設定為1,在文字屬性中決定高寬比)
	es = pTextStyleTable->add(pTextStyleRecord);
	AcDbObjectId styleId = pTextStyleRecord->objectId();
	pTextStyleTable->close();
	pTextStyleRecord->close();

	return styleId;
}
           

在TextPage.cpp檔案中添加以下頭檔案:

#include "AppDirectoryUtil.h"
#include "IniFile.h"
#include <vector>
#include <string.h>
#include "TextStyleUtil.h"
           

這時候編譯會出錯:

在ObjectARX中使用MFC-标簽式對話框

需要強制類型轉換:

在ObjectARX中使用MFC-标簽式對話框

(15)在CTextPage類中添加公有成員函數SaveProfiles,用于将使用者在控件中輸入的參數值儲存到INI中

在ObjectARX中使用MFC-标簽式對話框

 函數的代碼:

bool CTextPage::SaveProfile()
{
	if (!UpdateData())
	{
		return false;
	}

	//儲存參數值
	CIniFile iniFile(CAppDirectoryUtil::GetCurrentDirectory() +
		TEXT("\\OptionSheet.ini"));
	CString field = TEXT("OptionSheet");
	iniFile.SetValueOfKey(field, TEXT("textHeight"), m_textHeight);
	CString strTextStyle;
	m_cboTextStyle.GetLBText(m_cboTextStyle.GetCurSel(), strTextStyle);
	iniFile.SetValueOfKey(field, TEXT("textStyle"), strTextStyle);
	return false;
}
           

 (16)對CControlPage窗體中的單選按鈕映射int類型的成員變量m_nRadio1

在ObjectARX中使用MFC-标簽式對話框

對CControlPage窗體中的複選框按鈕映射BOOL類型的成員變量m_bCheck1

在ObjectARX中使用MFC-标簽式對話框

這是編譯發現出錯:

在ObjectARX中使用MFC-标簽式對話框

 強制類型轉換:

在ObjectARX中使用MFC-标簽式對話框

 (17)建立CControlPage窗體的初始化事件

BOOL CControlPage::OnInitDialog()
{
	CAcUiTabChildDialog::OnInitDialog();

	// TODO:  在此添加額外的初始化

	//從INI檔案中加載參數值
	CIniFile iniFile(CAppDirectoryUtil::GetCurrentDirectory() +
		TEXT("\\OptionSheet.ini"));
	CString field = TEXT("OptionSheet");
	iniFile.GetValueOfKey(field, TEXT("nRadio1"), m_nRadio1);
	iniFile.GetValueOfKey(field, TEXT("bCheck1"), m_bCheck1);

	UpdateData(FALSE);

	return TRUE;  // return TRUE unless you set the focus to a control
				  // 異常: OCX 屬性頁應傳回 FALSE
}
           

添加頭檔案

#include "AppDirectoryUtil.h"
#include "IniFile.h"
           

(18)在CControlPage 類中添加函數SaveProfiles

bool CControlPage::SaveProfiles()
{
	CIniFile iniFile(CAppDirectoryUtil::GetCurrentDirectory() +
		TEXT("\\OptionSheet.ini"));
	CString field = TEXT("OptionSheet");
	iniFile.SetValueOfKey(field, TEXT("nRadio1"), m_nRadio1);
	iniFile.SetValueOfKey(field, TEXT("bCheck1"), m_bCheck1);

	return false;
}
           

(19)為COptionSheet窗體添加OnOK消息處理函數

在ObjectARX中使用MFC-标簽式對話框
void COptionSheet::OnOK()
{
	// TODO: 在此添加專用代碼和/或調用基類
	if (!m_textPage.SaveProfile() || !m_controlPage.SaveProfiles())
	{
		return;
	}

	CAcUiTabMainDialog::OnOK();
}
           

效果:

在ObjectARX中使用MFC-标簽式對話框

項目源代碼:在ObjectARX中使用MFC-标簽式對話框 項目源代碼 

參考資料:

《AutoCAD ObjectARX(VC)開發基礎與執行個體教程》