Для выполнения этого проекта необходимо:
• Visual C++ 6
• Crystal Reports 8
Приступим.
Для начала, создадим наш отчет. Запускаем Crystal Report Designer. Создаем blank report. Добавляем ODBC connection, указывающее, на пример, на БД pubs на вашем SQL сервере, или на какую-нибудь таблицу в mdb-файле. Выбираем таблицу pubs.dbo.authors, давим add кнопку, закрываем окно. В появившемся окне дизайнера отчетов перетаскиваем в область Details нужные поля: au_id, au_fname, au_lname. Сохраняем отчёт.
Создаём простой Dialog-based проект со всеми настройками по умолчанию. В меню Projects->Add to project->Components and controls добавляем Crystal Report Viewer Control. В окне Confirm classes давим OK. Закрываем окно Components and controls. Добавляем Crystal Report Viewer Control на диалог. В окне ClassWizard для диалога добавляем обработчик WM_SHOWWINDOW. At the Member variables tab добавляем переменную m_CRView1. В начало файла SampRepDlg.cpp добавляем строки
#import no_namespace
#import rename("EOF", "adoEOF")
(подразумевается, что файл craxdrt.tlb находится в одной из стандартных папок для include. Изначально он находится в каталоге C:\Program Files\Seagate Software\Crystal Reports\Developer Files\include\)
так же добавляем следующие строки в начале файла RepSampDlg.cpp
const CLSID CLSID_Application = {0xb4741fd0, 0x45a6, 0x11d1, {0xab, 0xec, 0x00, 0xa0, 0xc9, 0x27, 0x4b, 0x91}};
const IID IID_IApplication = {0x0bac5cf2, 0x44c9, 0x11d1, 0xab, 0xec, 0x00, 0xa0, 0xc9, 0x27, 0x4b, 0x91}};
const CLSID CLSID_ReportObjects = {0xb4741e60, 0x45a6, 0x11d1, 0xab, 0xec, 0x00, 0xa0, 0xc9, 0x27, 0x4b, 0x91}};
const IID IID_IReportObjects = {0x0bac59b2, 0x44c9, 0x11d1, 0xab, 0xec, 0x00, 0xa0, 0xc9, 0x27, 0x4b, 0x91}};
Переходим к обработчику CRepSampDlg::OnShowWindow. Я обычно создаю стандартное окружение для работы с COM-объектами:
try {} catch(const _com_error& e) {
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
CString strError;
strError.Format("_com_error catched at CRepSampDlg::OnShowWindow\n"
"Source : %s\nDescription : %s", (LPCSTR)bstrSource,(LPCSTR)bstrDescription);
AfxMessageBox(strError);
}
В try-блоке присоединяем наш файл отчета:
HRESULT hr=S_OK;
IApplicationPtr pApp;
IReportPtr pRep;
hr = CoCreateInstance(CLSID_Application, NULL, CLSCTX_INPROC_SERVER, IID_IApplication,
(void **)&pApp);
if (FAILED(hr)) _com_issue_error(hr);
pRep = pApp->OpenReport(_bstr_t("d:\\projects\\RepSamp\\Report1.rpt"));
m_CRView1.SetReportSource(pRep);
m_CRView1.ViewReport();
Собираем проект, и запускаем. Появится отчет, который в качестве источника данных использует свои настройки по умолчанию. Теперь давайте подставим ему в качестве источника данных необходимый нам Recordset. Я предпочитаю ADO. Следующий код я добавил сразу после строки "HRESULT hr=S_OK;" :
ADODB::_ConnectionPtr pConn;
pConn.CreateInstance(__uuidof(ADODB::Connection));
if (FAILED(hr)) _com_issue_error(hr);
CString sConnStr("Provider=SQLOLEDB.1;"
"Integrated Security=SSPI;Persist Security Info= False;"
"Initial Catalog= pubs;Data Source= DATACENTER");
hr = pConn->Open(_bstr_t(sConnStr), _bstr_t(L""), _bstr_t(L""),
ADODB::adConnectUnspecified);
if(FAILED(hr)) _com_issue_error(hr);
ADODB::_RecordsetPtr pRs;
pRs.CreateInstance(__uuidof(ADODB::Recordset));
CString sSQL("SELECT * FROM authors");
pRs->Open(_bstr_t(sSQL), pConn.GetInterfacePtr(), ADODB::adOpenDynamic,
ADODB::adLockOptimistic, ADODB::adCmdText);
if (FAILED(hr)) _com_issue_error(hr);
теперь запихиваем наш recordset в отчет:
IApplicationPtr pApp;
IReportPtr pRep;
hr = CoCreateInstance(CLSID_Application, NULL, CLSCTX_INPROC_SERVER, IID_IApplication,
(void **) &pApp);
if (FAILED(hr)) _com_issue_error(hr);
pRep = pApp->OpenReport(_bstr_t("d:\\proj\\SampRep\\Report1.rpt"));
m_CRView1.SetReportSource(pRep);
IDatabasePtr pDatabase = 0;
IDatabaseTablesPtr pTables = 0;
IDatabaseTablePtr pTable = 0;
pRep->get_Database((IDatabase**)&pDatabase);
pDatabase->get_Tables((IDatabaseTables**)&pTables);
VARIANT var, var2;
VariantInit(&var);
VariantInit(&var2);
var.vt = VT_DISPATCH;
var.pdispVal = (IDispatch*)pConn;
var2.vt = VT_DISPATCH;
var2.pdispVal = (IDispatch*)pRs->GetActiveCommand();
hr = pDatabase->AddADOCommand(var, var2);
ASSERT(SUCCEEDED(hr));
собираем проект. Всё готово.
ВОПРОС-ОТВЕТ
Как сделать нестандартную кнопку на основе битмапа (без MFC, только WinAPI)?
Автор: Игорь Вартанов
Кнопка не обязательно должна иметь стандартный внешний вид (хотя лично я не нахожу внешний вид стандартной кнопки скучным или "простецким"). Однако для многих разработчиков и пользователей кнопки, имеющие нестандартный вид, выглядят более привлекательными. Поэтому для придания некоего стиля интерфейсу собственных программ можно использовать кнопки, отображающие некий битмап (bitmap – растровое изображение).
Кроме эффектов изображения можно использовать еще и эффекты формы – к примеру, круглая или овальная кнопка также достаточно оригинальны внешне, – но данная статья не рассматривает технику создания кнопок, имеющих форму, отличную от прямоугольной.
Windows имеет встроенные механизмы и API, поддерживающие создание кнопок (а также и других контролов), имеющих нестандартный внешний вид. Способ отрисовки внешнего вида контрола зависит от его стиля. В данном случае, стиль, нужный нам – это BS_OWNERDRAW. Из его названия видно, что отрисовку вида кнопки выполняет код пользователя, помещенный в оконную (диалоговую) функцию окна-владельца контрола.
Читать дальше