РАССЫЛКА ЯВЛЯЕТСЯ ЧАСТЬЮ ПРОЕКТА RSDN , НА САЙТЕ КОТОРОГО
ВСЕГДА МОЖНО НАЙТИ
ВСЮ НЕОБХОДИМУЮ РАЗРАБОТЧИКУ ИНФОРМАЦИЮ, СТАТЬИ, ФОРУМЫ, РЕСУРСЫ, ПОЛНЫЙ АРХИВ ПРЕДЫДУЩИХ ВЫПУСКОВ
РАССЫЛКИ И МНОГОЕ ДРУГОЕ.
Недавно я начал писать один
небольшой проект на VC с отчетом Crystal Reports 8 и
столкнулся со следующей проблемой: я не знал, как
написать отчет. После поиска материалов на эту
тему в интернете, у меня сложилось впечатление,
что перед разработчиками на VC не стоит проблема
создания отчетов. На CodeGuru в разделе Databases я не
нашел ни одного материала на эту тему. Пришлось
копать эту тему самому. К сожалению, у меня
оказался только один пример, в котором довольно
сложный отчет полностью создаётся в run-time без
использования редактора отчетов. Это
автоматически означало, что мне нужно будет
изучить несколько десятков, а то и сотен килобайт
текста, прежде чем я выдам первый отчет. Времени
на это у меня не было. Поэтому для создания отчета
я воспользовался следующей технологией, которая
и описывается ниже.
Для выполнения этого
проекта необходимо:
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 добавляем строки
(подразумевается, что файл craxdrt.tlb
находится в одной из стандартных папок для include.
Изначально он находится в каталоге C:\Program Files\Seagate
Software\Crystal Reports\Developer Files\include\)
так же добавляем следующие строки в
начале файла RepSampDlg.cpp
Собираем проект, и запускаем. Появится
отчет, который в качестве источника данных
использует свои настройки по умолчанию.
Теперь давайте подставим ему в качестве
источника данных необходимый нам Recordset. Я
предпочитаю ADO. Следующий код я добавил сразу
после строки "HRESULT hr=S_OK;" :
Как сделать нестандартную кнопку на основе битмапа (без MFC, только
WinAPI)?
Автор: Игорь Вартанов
Кнопка не обязательно должна иметь стандартный внешний вид (хотя лично я не
нахожу внешний вид стандартной кнопки скучным или "простецким"). Однако для
многих разработчиков и пользователей кнопки, имеющие нестандартный вид, выглядят
более привлекательными. Поэтому для придания некоего стиля интерфейсу
собственных программ можно использовать кнопки, отображающие некий битмап
(bitmap - растровое изображение).
Кроме эффектов изображения можно использовать еще и эффекты формы
- к примеру, круглая или овальная кнопка также достаточно оригинальны внешне, -
но данная статья не рассматривает технику создания кнопок, имеющих форму,
отличную от прямоугольной.
Windows имеет встроенные механизмы и API, поддерживающие создание кнопок (а
также и других контролов), имеющих нестандартный внешний вид. Способ отрисовки
внешнего вида контрола зависит от его стиля. В данном случае, стиль, нужный нам
- это BS_OWNERDRAW. Из его названия видно, что отрисовку
вида кнопки выполняет код пользователя, помещенный в оконную (диалоговую)
функцию окна-владельца контрола.
Рассмотрим основные этапы отрисовки контрола, имеющего стиль xx_OWNERDRAW.
Родительскому окну контрола приходит сообщение WM_MEASUREITEM, в котором передается указатель на структуру
MEASUREITEMSTRUCT через параметр lParam. Обработчик сообщения должен установить значения
полей itemWidth и itemHeight
структуры так, чтобы они содержали ширину и высоту контрола соответственно.
Если мы обработали сообщение, обработчик должен вернуть значение TRUE из оконной процедуры. Это сообщение приходит владельцу
один раз при создании контрола.
Каждый раз при необходимости перерисовать
контрол его владельцу приходит сообщение WM_DRAWITEM.
Параметр lParam сообщения содержит указатель на
структуру DRAWITEMSTRUCT, подготовленную системой. В
задачу данного сообщения входит предоставление контекста, в котором будет
происходить отрисовка контрола. Хэндл контекста сопровождает дополнительная
информация о внутреннем состоянии контрола, необходимая (возможно) для
изменения его внешнего вида, а также информация о виде действия, производимого
в настоящий момент с контролом. Далее мы увидим, каким образом эта информация
может быть использована для изменения внешнего вида кнопки. И, опять-таки,
если мы обрабатываем данное сообщение, обработчик обязан вернуть из оконной
процедуры значение TRUE.
Поскольку мы реализуем, хотя и самостоятельно отрисовываемую, но все же
кнопку, то было бы неплохо, если бы она имела поведение обычной кнопки - края
кнопки в нормальном состоянии должны имитировать выпуклый контрол, при нажатом
состоянии - вдавленный, при установленном фокусе кнопка должна иметь на себе
прямоугольник, выполненный пунктирной линией, и в неактивном состоянии кнопка
должна резко отличаться по цвету (либо фона, либо надписи, либо и того, и
другого).
Выполняя указанные требования, мы можем подготовить четыре битмапа,
реализующие внешний вид каждого из состояний кнопки, и отрисовывать в нужный
момент (вот где появляется необходимость знать текущее состояние кнопки) одно из
них. В этом случае мы сами полностью контролируем внешний вид кнопки в каждом из
состояний. Впечатление, которое вы произведете на пользователя, будет целиком
зависеть от вашего вкуса и умения создавать растровые изображения.
Что касается кода, реализующего необходимую логику работы, то его реализация
может быть следующей:
Как видим, ничего сложного. Код распадается на две части: в первой на основе
сведений о выполняемых действиях (itemAction) и текущем
состоянии кнопки (itemState) производится выбор
необходимого битмапа, во второй части происходит вывод выбранного битмапа в
контекст кнопки. Код обрамляется проверкой на необходимый идентификатор
контрола, поскольку в рабочей программе подобных контролов может быть несколько.
Внимательный читатель готов задать вопрос о том, что в самом начале
упоминались не только механизмы (реализованные, как мы выяснили, через сообщения
WM_MEASUREITEM и WM_DRAWITEM),
но и API?
Действительно, имеется несколько функций, облегчающих придание стандартного
вида OWNERDRAW-контролам. Разработчик готовит только основной битмап для кнопки,
а для отрисовки границ и состояний кнопки (неактивное и в фокусе) пользуется
функциями WinAPI - DrawEdge() (границы контрола -
"выпуклый/вдавленный"), DrawState() (состояние
"активный/неактивный") и DrawFocusRect() (состояние "в
фокусе"). В таком случае вышеприведенный код примет вид:
Выигрыш подобного подхода состоит в меньшем использовании самостоятельно
подготавливаемых ресурсов и меньшем их потреблении при работе программы. К
недостаткам (и весьма заметным, на мой взгляд) можно отнести то, что происходит
потеря контроля над внешним видом кнопки в различных ее состояниях. Впрочем,
работа этих упомянутых функций ориентирована на поддержание стандартного
внешнего вида контролов, поэтому и результат не очень выразителен. На мой
взгляд, данная техника больше подходит к выполнению кнопок, имеющих в основном
стандартный внешний вид, но снабженных небольшими изображениями по соседству с
текстом кнопки.
Следует заметить, что при необходимости можно (а иногда и
нужно) пользоваться комбинацией приведенных методик: предположим, использовать
для отрисовки чертыре битмапа, но границу рисовать функцией DrawEdge().
При подготовке данного
материала мною использован код, опубликованный в одном из сообщений
эхоконференции SU.WIN32.PROG (FidoNet). Автор кода - Dmitry Timoshkov
<dmitry@sloboda.ru> - вполне может и не узнать его, поскольку код был мною
довольно сильно переработан и дополнен :-))).