Личный кабинет
2008-11-04 11:42
Windows имеет два типа скролбаров. Это "встроенные" скролбары, которые мы получаем при использовании оконных стилей WS_HSCROLL и/или WS_VSCROLL, и скролбар контролы, которые фактически являются дочерними окнами и которые можно создавать в пределах окна. Сообщение WM_CTLCOLOR могут посылать только последние.
Естевственно, возникает вопрос, а почему существует два вида скролбаров ? Ответ кроется в истории. Давным давно, когда Windows была ещё очень маленькой, существовала необходимость экономить каждый бит памяти, а окна занимали значительное пространство. Так как почти в каждом окне присутствовали скролбары, то разработчики решили сделать их неотемлемой частью окон. С другой стороны, программистам не понравилось такое решение, так как им больше хотелось работать со скролбарами, как с отдельными окнами. С одной стороны, конечно же встроенные скролбары удобнее в использовании и требуют меньше кода, но с другой имеют меньше настроек, позволяющих менять их внешний вид.
А как насчёт MFC? Поумолчанию, MFC-шный CScrollView использует встроенные скролбары, у которых нельзя менять цвет. Однако, ничего страшного не случится, если мы заставим CScrollView использовать Ваш собственный контрол скролбара. Но перед тем, как мы решим данную задачу, я хочу заметить, что WM_CTLCOLOR позволяет устанавливать только цвет фона, но не цвет стрелки и бегунок. Поэтому, если Вы хотите менять все цвета, то скорее всего WM_CTLCOLOR окажется бесполезным. Позже я постараюсь подкинуть несколько идей по этому поводу, ну а теперь давайте посмотрим, как заставить CScrollView использовать Ваш скролбар вместо встроенного.
Итак, для начала, объявим экземпляры CScroll баров в основном фрейме:
class CMainFrame : public CFrameWnd {
protected:
CScrollbar m_wndHScroll;
CScrollBar m_wndVScroll;
...
};
Затем, при создании фрейма, создаём их окна:
int CMainFrame::OnCreate(...)
{
...
CRect rc(0,0,0,0);
VERIFY(m_wndSBHorz.Create(WS_VISIBLE|WS_CHILD|SBS_HORZ,
rc, this, AFX_IDW_HSCROLL_FIRST));
VERIFY(m_wndSBVert.Create(WS_VISIBLE|WS_CHILD|SBS_VERT,
rc, this, AFX_IDW_HSCROLL_FIRST+1));
VERIFY(m_wndSBBox.Create(WS_VISIBLE|WS_CHILD|SBS_SIZEBOX,
rc, this,-1));
return 0;
}
Обратите внимание, что Вам прийдётся создать бокс скролбара, это небольшой квадратик, где вертикальный и горизонтальный скролбары соединяются, чтобы можно было ресайзить окно и избежать пустого пятна.
Как только скролбары созданы, остаётся ещё несколько вещей, о которых необходимо позаботится. Это установить размер скролбаров, обработать уведомления, и получить для них вид (view). Последнее самое простое. CScrollView содержит виртуальную функцию GetScrollBarCtrl, которую можно переопределить.
CScrollBar* CPictureView::GetScrollBarCtrl(int nBar) const
{
CWnd* pParent = GetParent();
UINT nID = AFX_IDW_HSCROLL_FIRST;
if (nBar==SB_VERT)
nID++;
return (CScrollBar*)pParent->GetDlgItem(nID);
}
Она получает управление от родителя используя удобные идентификаторы (ID) AFX_IDW_HSCROLL_FIRST и AFX_IDW_HSCROLL_FIRST+1.
А как же уведомления? Когда пользователь перемещает полосу прокрутки, скролбар посылает WM_HSCROLL или WM_VSCROLL своему родителю, чтобы Вы могли что-нибудь сделать. Это есть очень хорошо, так как если Вы поместите свои скролбары во фрейм, то CFrameWnd уже имеет обработчики OnHScroll и OnVScroll, которые направляют WM_HSCROLL и WM_VSCROLL в вид (view):
// Из winfrm.cpp
void CFrameWnd::OnHScroll(...)
{
CWnd* pActiveView = GetActiveView();
if (pActiveView != NULL) {
pActiveView->SendMessage(WM_HSCROLL, ...);
}
}
Если Ваш вид наследован от CScrollView, то для того, чтобы обработать сообщения прокрутки, ничего делать не надо, так как MFC делает это автоматически!
Теперь о размерах. Это то место, где прийдётся проделать определённую работу. Для того, чтобы всё летало, необходимо управлять позицией скролбаров каждый раз, когда размер фрейма изменяется. Помните, что скролбары, это потомки фрейма а не вида. Обычно, обработка изменения размеров производится в OnSize, однако для фреймовых окон это делается в CFrameWnd::RecalcLayout. Применительно к программе (исходник которой можно скачать ниже) эта функция выглядит так:
//////////////////
// изменение размеров фрейма: перемещение вида и скролбаров
//
void CMainFrame::RecalcLayout(BOOL bNotify)
{
CFrameWnd::RecalcLayout();
CView* pView = GetActiveView();
if (pView) {
CRect rc;
pView->GetWindowRect(&rc);
ScreenToClient(&rc);
// shrink view by scrollbars
int cyHScroll = GetSystemMetrics(SM_CYHSCROLL);
int cxVScroll = GetSystemMetrics(SM_CXVSCROLL);
rc.right -= cxVScroll;
rc.bottom -= cyHScroll;
pView->MoveWindow(rc);
// next, move the scroll bars: horz, vert and box
rc.left = rc.right;
rc.right += cxVScroll;
m_wndSBVert.MoveWindow(rc);
rc.left = 0;
rc.right -= cxVScroll;
rc.top = rc.bottom;
rc.bottom+= cyHScroll;
m_wndSBHorz.MoveWindow(rc);
rc.left = rc.right;
rc.right+=cxVScroll;
m_wndSBBox.MoveWindow(rc);
}
} }
}
Естевственно, возникает вопрос, а почему существует два вида скролбаров ? Ответ кроется в истории. Давным давно, когда Windows была ещё очень маленькой, существовала необходимость экономить каждый бит памяти, а окна занимали значительное пространство. Так как почти в каждом окне присутствовали скролбары, то разработчики решили сделать их неотемлемой частью окон. С другой стороны, программистам не понравилось такое решение, так как им больше хотелось работать со скролбарами, как с отдельными окнами. С одной стороны, конечно же встроенные скролбары удобнее в использовании и требуют меньше кода, но с другой имеют меньше настроек, позволяющих менять их внешний вид.
А как насчёт MFC? Поумолчанию, MFC-шный CScrollView использует встроенные скролбары, у которых нельзя менять цвет. Однако, ничего страшного не случится, если мы заставим CScrollView использовать Ваш собственный контрол скролбара. Но перед тем, как мы решим данную задачу, я хочу заметить, что WM_CTLCOLOR позволяет устанавливать только цвет фона, но не цвет стрелки и бегунок. Поэтому, если Вы хотите менять все цвета, то скорее всего WM_CTLCOLOR окажется бесполезным. Позже я постараюсь подкинуть несколько идей по этому поводу, ну а теперь давайте посмотрим, как заставить CScrollView использовать Ваш скролбар вместо встроенного.
Итак, для начала, объявим экземпляры CScroll баров в основном фрейме:
class CMainFrame : public CFrameWnd {
protected:
CScrollbar m_wndHScroll;
CScrollBar m_wndVScroll;
...
};
Затем, при создании фрейма, создаём их окна:
int CMainFrame::OnCreate(...)
{
...
CRect rc(0,0,0,0);
VERIFY(m_wndSBHorz.Create(WS_VISIBLE|WS_CHILD|SBS_HORZ,
rc, this, AFX_IDW_HSCROLL_FIRST));
VERIFY(m_wndSBVert.Create(WS_VISIBLE|WS_CHILD|SBS_VERT,
rc, this, AFX_IDW_HSCROLL_FIRST+1));
VERIFY(m_wndSBBox.Create(WS_VISIBLE|WS_CHILD|SBS_SIZEBOX,
rc, this,-1));
return 0;
}
Обратите внимание, что Вам прийдётся создать бокс скролбара, это небольшой квадратик, где вертикальный и горизонтальный скролбары соединяются, чтобы можно было ресайзить окно и избежать пустого пятна.
Как только скролбары созданы, остаётся ещё несколько вещей, о которых необходимо позаботится. Это установить размер скролбаров, обработать уведомления, и получить для них вид (view). Последнее самое простое. CScrollView содержит виртуальную функцию GetScrollBarCtrl, которую можно переопределить.
CScrollBar* CPictureView::GetScrollBarCtrl(int nBar) const
{
CWnd* pParent = GetParent();
UINT nID = AFX_IDW_HSCROLL_FIRST;
if (nBar==SB_VERT)
nID++;
return (CScrollBar*)pParent->GetDlgItem(nID);
}
Она получает управление от родителя используя удобные идентификаторы (ID) AFX_IDW_HSCROLL_FIRST и AFX_IDW_HSCROLL_FIRST+1.
А как же уведомления? Когда пользователь перемещает полосу прокрутки, скролбар посылает WM_HSCROLL или WM_VSCROLL своему родителю, чтобы Вы могли что-нибудь сделать. Это есть очень хорошо, так как если Вы поместите свои скролбары во фрейм, то CFrameWnd уже имеет обработчики OnHScroll и OnVScroll, которые направляют WM_HSCROLL и WM_VSCROLL в вид (view):
// Из winfrm.cpp
void CFrameWnd::OnHScroll(...)
{
CWnd* pActiveView = GetActiveView();
if (pActiveView != NULL) {
pActiveView->SendMessage(WM_HSCROLL, ...);
}
}
Если Ваш вид наследован от CScrollView, то для того, чтобы обработать сообщения прокрутки, ничего делать не надо, так как MFC делает это автоматически!
Теперь о размерах. Это то место, где прийдётся проделать определённую работу. Для того, чтобы всё летало, необходимо управлять позицией скролбаров каждый раз, когда размер фрейма изменяется. Помните, что скролбары, это потомки фрейма а не вида. Обычно, обработка изменения размеров производится в OnSize, однако для фреймовых окон это делается в CFrameWnd::RecalcLayout. Применительно к программе (исходник которой можно скачать ниже) эта функция выглядит так:
//////////////////
// изменение размеров фрейма: перемещение вида и скролбаров
//
void CMainFrame::RecalcLayout(BOOL bNotify)
{
CFrameWnd::RecalcLayout();
CView* pView = GetActiveView();
if (pView) {
CRect rc;
pView->GetWindowRect(&rc);
ScreenToClient(&rc);
// shrink view by scrollbars
int cyHScroll = GetSystemMetrics(SM_CYHSCROLL);
int cxVScroll = GetSystemMetrics(SM_CXVSCROLL);
rc.right -= cxVScroll;
rc.bottom -= cyHScroll;
pView->MoveWindow(rc);
// next, move the scroll bars: horz, vert and box
rc.left = rc.right;
rc.right += cxVScroll;
m_wndSBVert.MoveWindow(rc);
rc.left = 0;
rc.right -= cxVScroll;
rc.top = rc.bottom;
rc.bottom+= cyHScroll;
m_wndSBHorz.MoveWindow(rc);
rc.left = rc.right;
rc.right+=cxVScroll;
m_wndSBBox.MoveWindow(rc);
}
} }
}
- Фреймы в HTML документах (2008-11-04)
- 10 признаков дурного тона в web-дизайне (2008-11-04)
- 800 и 1024. Пиксели или проценты? (2008-11-04)
- Как работает формат JPEG? (2008-11-04)
- О композиции в дизайне (2008-11-04)
- Психология в дизайне (2008-11-04)
- Шрифты (2008-11-04)
- Как сделать качественный веб-сайт (2008-11-04)
- Какой вид дизайна выбрать? (2008-11-04)
- Выпадающие меню с помощью CSS (2008-11-04)
- Создание веб-страниц для различных разрешений м... (2008-11-04)
- Веб-дизайн и анимация (2008-11-04)
- Немного об index.html (2008-11-04)
- Психология дизайна (2008-11-04)
- Что такое стильный web-сайт? (2008-11-04)
- Web дизайн :: Что такое хорошо и что такое плохо (2008-11-04)
- Лево, Право или Центр? (2008-11-04)
- Оптимизация изображений в формате JPG (2008-11-04)
- Альтернативные редакторы Flash (2008-11-04)
- Что же такое web-дизайн? (2008-11-04)
- Сайты для тинейджеров: правила дизайна (2008-11-04)
- Маленькие проблемы больших таблиц - HTML (2008-11-04)
- Особенности web-дизайна (2008-11-04)
- Подсказки и советы для веб-мастеров - Топ 100+ (2008-11-04)
- Единицы измерения CSS (2008-11-04)
- Состав изображений (2008-11-04)
- FLASH - ЧТО МОЖЕТ БЫТЬ ХУЖЕ? (2008-11-04)
- FAQ по графическим форматам файлов (2008-11-04)
- ПО необходимое для web-дизайнера (2008-11-04)
- Должностная инструкция веб-мастера (2008-11-04)
- Стиль Вашего сайта (2008-11-04)
- Стиль Вашего сайта (2008-11-04)
- Orange color: теория и практика (2008-11-04)
- Расположение баннера (2008-11-04)
- Советы "чайникам" (2008-11-04)
- С чего начать (2008-11-04)
- С чего начать (2008-11-04)
- Организация - вот ключ к успеху (2008-11-04)
- Подбор шрифта и верстка текста (2008-11-04)
- Обзор Gif-аниматоров (2008-11-04)
- Каскадные таблицы стилей (преимущества и недост... (2008-11-04)
- Фирменный шрифт (2008-11-04)
- Главные ошибки в web-дизайне (2008-11-04)
- CSS - Для чего нужны таблицы стилей? (2008-11-04)
- Таблицы или слои, что лучше? (2008-11-04)
- О скриптах (2008-11-04)
- Изучаем HTML (2008-11-04)
- Применение нескольких классов к элементу в CSS (2008-11-04)
- Создание сайта с помошью фреймов (2008-11-04)
- Основы работы со слоями в CSS (2008-11-04)
Нет похожих страниц.
Быстрый переход