先附上流程圖:
(1) 創建工程
(2)插入一個對話框
雙擊.rc文件
右鍵-》選中添加資源
修改對話框ID:IDD_OPTION_SHEET
在上面添加一個Tab控件, 修改ID:IDC_TAB
(3)爲此對話框添加映射類COptionSheet,基類爲CAcUiTabMainDialog
(4)再插入一個對話框資源(IDD_TEXT_PAGE)
右擊,選“插入dialog”
放置一個文本框
(5)創建文字選項卡的映射類CTextPage
(6)插入第二個選項卡對應的資源對話框(IDD_CONREOL_PAGE)
添加Group Box按鈕
內部放置兩個單選按鈕(ID分別爲:IDC_RADIO1和IDC_RADIO2),只勾選第一個按鈕的Group選項
添加一個複選框控件
點擊一下對話框,修改屬性
創建這個選項卡對話框的映射類CControlPage
(7)在COptionSheet類中,爲Tab控件添加映射成員變量
點擊Tab控件框,右鍵選擇“添加變量”
(8) 在COptionSheet類中添加兩個成員變量
CTextPage m_textPage;
CControlPage m_controlPage;
注:上圖中的變量名應爲:m_textPage
(9)創建IDD_OPTION_SHEET對話框的初始化事件
(10)在命令的實現函數中加入下面的代碼,並添加頭文件:#include "OptionSheet.h"
這時候 編譯程序,並打開CAD,看看是否能彈出對話框
(11)添加一個新類CIniFile(C++常規類) ,用於讀寫INI文件中的鍵值
(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
同理,爲文字樣式組合框映射CComboBox成員變量m_cboTextStyle
(14)創建CTextPage窗體的初始化事件
填充文字樣式組合框,從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
類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"
這時候編譯會出錯:
需要強制類型轉換:
(15)在CTextPage類中添加公有成員函數SaveProfiles,用於將用戶在控件中輸入的參數值保存到INI中
函數的代碼:
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
對CControlPage窗體中的複選框按鈕映射BOOL類型的成員變量m_bCheck1
這是編譯發現出錯:
強制類型轉換:
(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消息處理函數
void COptionSheet::OnOK()
{
// TODO: 在此添加專用代碼和/或調用基類
if (!m_textPage.SaveProfile() || !m_controlPage.SaveProfiles())
{
return;
}
CAcUiTabMainDialog::OnOK();
}
效果: