Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Разрабатываем крутой интерфейс, Или утираем другим библиотекам нос! 
:(
    Опции темы
Coocky
Дата 5.6.2006, 17:59 (ссылка) |    (голосов:12) Загрузка ... Загрузка ... Быстрая цитата Цитата


GUI гуру
****


Профиль
Группа: Участник Клуба
Сообщений: 2879
Регистрация: 16.2.2004
Где: Украина. Запорожь е

Репутация: 25
Всего: 62



Всем начинающим -привет!
В завершении своей форумской карьеры решил я вас, друзья мои, порадывать методиками разработки красивого( т.е. своего и нестандартного) интерфейса.
Мы научимся с вами создавать свои кнопки с подсветкой и анимацией, прозрачностью, свои окна, с различными заливками и фоном на бекграунд, своим заголовком. Перерисуем правильно CListCtrl, CTabCtrl,  Сделаем свой CProgressCtrl,Scroll,CSliderCtrl, поборемся с мерцанием и т.д.
А главное поймем как все это правильно делается. Раз и навсегда.
Большая просьба, сюда вопросы не задавать, а писать в ПМ. Если где будет ошибка (все мы люди smile )-писать то же в ПМ.
 Модераторов прошу закрепить эту темку если не трудно smile 
Сейчас пора домой. а вот завтра мы с вами начнем с теории перерисовок и сделаем свои кнопки -чек ,радио и простые smile 
И так до завтра smile   

Это сообщение отредактировал(а) Coocky - 5.6.2006, 18:07


--------------------
Верю в смерть после жизни, в любовь после секса ,в крем после бритья smile        
PM ICQ   Вверх
Coocky
Дата 6.6.2006, 10:44 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


GUI гуру
****


Профиль
Группа: Участник Клуба
Сообщений: 2879
Регистрация: 16.2.2004
Где: Украина. Запорожь е

Репутация: 25
Всего: 62



Итак продолжаем... smile 
Для того, что б создать красивый элемент управления, нужно создать свой,отличный от стандарного ,элемент управления-другими словами -перерисовать.
Где же производится перерисовка элементов управления?
Обычно для этого служит обработчик сообщения WM_PAINT- OnPaint();
Однако не для всех элементов управления целесообразно это . Дальше вы увидите-что ,где когда и как делается, в каких обработчиках или функциях.
Итак теперь о главнов-как правильно рисовать или другими словами : 
                                     Оптимизация графики  
Первое, с чем сталкивается начинающий программер при попытки рисования или отрисовки элементов управления-это мигание/мерцание/блики. Это связано с тем, что наш человеческий глаз иногда замечает процесс перерисовки,когда он совпадает с определеной частотой обновления (ну вообщем я не медик и не физик, кому интересно частота-идем дружно в Google).
Для того, что б избежать видимости отрисовки мы должны весь процесс скрыть. Все это уже изобретено до вас и ничего здесь нового нет. Мы будем использовать двойную буфферизацию (надеюсь правильно написал smile )
Что же это такое? Слово может и страшное (для некоторых может даже и пошлое smile ), но на самом деле все просто "до немогу". Мы рисуем все на "заднем", невидимом плане. А после этого всю картинку передаем битовыми блоками в один прием на "видимое полотно" (передача блитов из памяти-самый быстрый метод. Насколько я знаю smile ). Вообщем все до банальности просто. Мигания вы не увидите. Максимум что вам светит-медленая (заторможеная прорисовка), если приходится много рисовать или передовать большие растровые изображения.
Итак-рисуем с использованием двойной буфферизации smile 
Создадим функцию SuperDraw(); Это будет функция вашего класса. Далее код с комментариями
Код

CRect rect;// Это нам для координат
GetClientRect(rect);// Получим координаты
CClientDC dc (this); // Создаем контекст для рисования
CDC mem; //Вспомогательный контест
mem.CreateCompatibleDC(&dc); Создаем его в памяти
CBitmap btmp;// "Пустой вспомогательный растр"
btmp.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());//Создаем и его в памяти
mem.SelectObject(&btmp);// Выбираем этот растр, тем самым создав "невидимое полотно"
//Начинаем рисовать на "невидимом полотне". Рисуем все что угодно. Даже можем передовать туда растр и т.д.
..........

mem.FillSolidRect(.......
mem.TextOut(.....
.........
// Теперь все , что нарисовали в один прием передаем на "видимое полотно"
dc.BitBlt(0,0,rect.Width(),rect.Width(),&mem,0,0,SRCCOPY);


Вот и все. Надеюсь все понятно. smile 
Теперь о том, как же использывать эту функцию.
Там, где мы будем обрабатывать сообщение WM_PAINT, в обработчик вставляем эту функцию.
Код

void MyСlass::OnPaint()
{
    CPaintDC dc(this);
                // device context for painting
    // TODO: Add your message handler code here
    // Do not call CDialog::OnPaint() for painting messages
   SuperDraw();
}

Теперь избавимся от перерисовки фона нашего окна (он тоже блики дает smile )
Отловим сообщение WM_ERASEBKGND  и изменим возращаемое значение обрабочика
Код

BOOL MyDlg::OnEraseBkgnd(CDC* pDC)
{
    // TODO: Add your message handler code here and/or call default
 return TRUE;
}

Мы вернули TRUE, тем самым дали понять, что мы не хотим, что б система заливала наш фон своим цветом. Иначе вся графика коту под хвост.
Это сообщение приходит раньше , чем WM_PAINT, и заливает наше окно свои фоном, если ему не запретить. Оно нам надо? smile 
Теперь еще одно. Для принудительной перерисовки элемента не надо вызывать Invalidate(); Нужно вызывать SuperDraw(); Почему? А это вы увидите (ощущите и заметите, когда мы с вами будем делать свой скрол smile ). Замечу лишь то, что поместив SuperDraw() в обработчик 
OnPaint() мы избавили себя от отрисовке окна тогда , когда этого нужно системе (ну например при перекрытии окна или его SHOW/HIDE).
А почему мы не рисуем с помощью CPaintDC dc(this); спросят некоторые,? Отвечу-поищите топик про использование контекстов устройств. Я уже как-то писал, поэтому повторятся не буду. Скажу лишь то, что CPaintDC доставляем частенько проблемы. Но я про это писал. Ищите smile 
Да , кстати, иногда, ели много однотипных элементов со сложной прорисовкой. то это дело можно немного ускорить, поместив SuperDraw(); не в OnPaint(), а в OnEraseBkgnd(CDC* pDC), это даст нам немного более ранню прорисовку, по сравнению с другими окнами. Хотя злоупотреблять не советую. Ибо OnEraseBkgnd(CDC* pDC) нам иногда будет нужен при определеных "махинациях" в дальнейшем.
Ну вот. Почва подготовлена , теперь будем рисовать.
Начнем (дальше), с кнопок smile  


--------------------
Верю в смерть после жизни, в любовь после секса ,в крем после бритья smile        
PM ICQ   Вверх
Coocky
Дата 14.6.2006, 14:16 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


GUI гуру
****


Профиль
Группа: Участник Клуба
Сообщений: 2879
Регистрация: 16.2.2004
Где: Украина. Запорожь е

Репутация: 25
Всего: 62



Заждались? smile 
Ну как говорит Ф. Бондарчук в рекламе -"И  н-н-н-начали!" smile 
Кнопки. Часть 1.
Нажми на кнопку-получишь результат,
И твоя мечта осуществится..


Сегодня мы создадим ХР кнопки радио и чек. Без всякого манифеста. smile 
Итак. Создаем диалог. Сразу говорю, на будущее, в его свойствах выставим WS_CLIPCHILDREN , которое скажет ему. что при своей перерисовке, он не будет перерисовывать дочерние элементы. На одно мигание меньше smile 
Создадим две кнопки-butt1 и butt2 (пардон за неоригинальность smile ) Поставим им свойство BS_OWNERDRAW- значит, что рисовать будем сами.
Создадим два класса class CRadioButton : public CButton и class CheckButton : public CButton (далее буду рассматоривать один класс, а в примере есть все для всех smile )
Перегрузим виртуальную функцию 
void CheckButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
Эта функция вызывается вседа, когда элемент требует перерисовки.
Заполняем ее smile 
Код

void CheckButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
  CDC dc;  // Контекст для рисования
  CRect rect;
  GetClientRect(&rect);//Координаты (хотя можно брать из структуры lpDrawItemStruct)
  dc.Attach(lpDrawItemStruct->hDC);  // Присоединяем контекст кнопки
  CDC mem;
  mem. CreateCompatibleDC(&dc);  //Создаем контекст в памяти
  CBitmap bit_map;
  bit_map.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());  // Битмап в памяти
  mem.SelectObject(&bit_map);
  mem.FillSolidRect(&rect,RGB(212,208,200));//Заливаем цветом окна
  mem.SelectObject(font2);  //шрифт
  if(check)  //Если нажата
  {
    if(over==FALSE)  //Если не подсвечена
    {
      CPoint pt( 0,0);
      imgList.Draw(&mem, 2, pt, ILD_NORMAL); //Выводим из заранее подготовленого списка
    }
    if(over==TRUE)  //Если подсвечена
    {
      CPoint pt( 0,0);
      imgList.Draw(&mem, 3, pt, ILD_NORMAL); //Выводим из заранее подготовленого списка
    }

  }
  else  //Если нажата
  {
    if(over==FALSE) //Если не подсвечена
    {
      CPoint pt( 0,0);
      imgList.Draw(&mem, 0, pt, ILD_NORMAL); //Выводим из заранее подготовленого списка
    }
    if(over==TRUE) //Если подсвечена
    {
      CPoint pt( 0,0);
      imgList.Draw(&mem, 1, pt, ILD_NORMAL); //Выводим из заранее подготовленого списка

    }

  }
  
  CString s;
  GetWindowText(s); //Получаем текст
  rect.left=rect.left+16; //Размещаем левее от иконки
  rect.right+=16;
  mem.SetBkMode(TRANSPARENT); // Цвет фона
  mem.SetTextColor(RGB(0,0,255)); //Красный
  mem.DrawText(s,rect,DT_LEFT); //Выводим текст

  dc.BitBlt(0,0,rect.Width(),rect.Height(),&mem,0,0,SRCCOPY); //Выводим всю картинку
  dc.Detach(); //Отсоединяем (Можно не делать, если обьект локальный)
}



Там все с коментариями smile 
Теперь ловим сообщение WM_ERASEBKGND
Код

BOOL CheckButton::OnEraseBkgnd(CDC* pDC)
{
  // TODO: Add your message handler code here and/or call default

  return TRUE;
}


И ловим WM_MOUSEMOVE
Если мышь над кнопкой подсветим ее
Код

void CheckButton::OnMouseMove(UINT nFlags, CPoint point)
{
  //  Расмотрим позже
  TRACKMOUSEEVENT tme;
  tme.cbSize = sizeof(tme);
  tme.hwndTrack = GetSafeHwnd();
  tme.dwFlags = TME_LEAVE;
  TrackMouseEvent(&tme);

  over=TRUE; //ставим флаг подсветки

  Invalidate(); //Перерисуем кнопку

  CButton::OnMouseMove(nFlags, point);
}

Теперь подробнее о TRACKMOUSEEVENT

Нам нужно знать о том, когда же "погасить кнопку".  Гасить нужно тогда, когда мышь выходит за пределы кнопки.
Для этого мы должны сделать
Код

//Параметры смотрим в МСДН
TRACKMOUSEEVENT tme;
  tme.cbSize = sizeof(tme);
  tme.hwndTrack = GetSafeHwnd();
  tme.dwFlags = TME_LEAVE;
  TrackMouseEvent(&tme);

Это позволить нам ловить сообщение WM_MOUSELEAVE,что означает-мышь не над кнопкой
Ну и соотвествено поймам сообщение.обработать его
Код

ON_MESSAGE(WM_MOUSELEAVE,Hover)
.......
........
.......
.......
LRESULT  CheckButton:: Hover(WPARAM wParam,LPARAM lParam)
{
  over=FALSE;
  Invalidate();
  return 0;
}

Ну и соотвествено теперь обработаем нажатие кнопки (я это сделал,для простоты, в классе окна. Хотя можно пойти дальше и обработать нажатие и тпускание кнопки в классе кнопки)
Для этого создаем две функции :
Код

// Устанавливаем нажатие
void CheckButton::SetCheck(BOOL checks)
{
  check=checks;
  Invalidate(); //Не забываем перерисовать
}


И получение флага нажатия
Код

BOOL CheckButton::GetCheck(void)
{
  return check;
}


Ну и само нажатие
Код

void CbuttonDlg::OnBnClickedButton1()
{
  butt1.SetCheck(!butt1.GetCheck());
}

Вот и вся основа. Пример конечно очень простой. Все можно разширить функциями класса нашей кнопки. Вплоть до установления картинок, цвета текста ,размера шрифта и т.д.. В итоге можно создать свой универсальный класс кнопки. Или dll smile  . И ненадо лазить в поисках других библиотек.Это уже вам карты в руки smile 
Да, чуть не забыл. Обратите внимание на класс CRadioButton . Там я создал список изображения с маской прозрачности. Чтоб квадратная икона "обрезалась" до круглой.
Код

imgList.Create(    13, 
    13, 
    ILC_COLOR24|ILC_MASK, 4, 0); // добавляем флаг для маски
  m_Bmp.LoadBitmap(IDB_BITMAP6);
  imgList.Add(&m_Bmp, RGB(221,236,255)); //Цвет самой маски -  то , что указано в RGB- "не выводим"
  m_Bmp.DeleteObject();

далее при рисовании
Код

imgList.Draw(&mem, 2, pt, ILD_TRANSPARENT);// Выводим с маской прозрачности

Да..И еще. Нажати кнопки и подсветка происходит не только на самой картинки, а и чуть правее (по всей ширине кнопки.)
Кому не нравится, ограничте проверко попадание на прямоугольник функцией CRect::PtInRect();
 smile 
Это для самостоятельной работы smile 
Ну вроде и все. За код не ругайте. Если где ошибочка-издержки copy-paste smile  Ну нет у меня времени, нет smile 
Пример прилагается....


Далее мы продолжим изучение кнопок-в частности научимся делать плавную подсветку. 

Присоединённый файл ( Кол-во скачиваний: 803 )
Присоединённый файл  button.rar 54,83 Kb


--------------------
Верю в смерть после жизни, в любовь после секса ,в крем после бритья smile        
PM ICQ   Вверх
Coocky
Дата 14.6.2006, 14:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


GUI гуру
****


Профиль
Группа: Участник Клуба
Сообщений: 2879
Регистрация: 16.2.2004
Где: Украина. Запорожь е

Репутация: 25
Всего: 62



P.S.

На самом деле можно (и нужно-не берите дурной пример smile ) обойтись без всех сложных конструкций if else  в перерисовке (это сделано вам для наглядности процесса).Представьте сколько их будет когда мы захотим еще отрисовать и нажатие кнопки и отпускание и еще что-нибудь. smile  Вместо этого нужно использовать:
1.GetBitmap()-если вы не работаете со списком изображений, а конректно с битмапами.  Ну и соотвествено в своих созданых функциях ( SetPress(), SetHover(), SetCheck и т.д.) делать всю логику ну и SetBitmap() соответсвенно smile 
2. Для списков изображений держать переменную, которая ,исходя из вышесказаного в пункте 1, будет менять свое значение на нужное для всего одного вызова CImageList::Draw( // тут номер нужной картинки) в перерисовке. 


--------------------
Верю в смерть после жизни, в любовь после секса ,в крем после бритья smile        
PM ICQ   Вверх
takedo
Дата 6.7.2006, 07:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 501
Регистрация: 1.6.2005

Репутация: нет
Всего: 3



Coocky
Цитата

Теперь избавимся от перерисовки фона нашего окна (он тоже блики дает  )
Отловим сообщение WM_ERASEBKGND  и изменим возращаемое значение обрабочика
 BOOL MyDlg::OnEraseBkgnd(CDC* pDC)
{
    // TODO: Add your message handler code here and/or call default
 return TRUE;
}

Мы вернули TRUE, тем самым дали понять, что мы не хотим, что б система заливала наш фон своим цветом. Иначе вся графика коту под хвост.

Хочу заметить, что мы тем самым не только избавляемся от лишней перерисовки, но и от просто крайне неприятного закрашивания контролов -  см. пост: http://forum.vingrad.ru/index.php?showtopic=102364 - и картинку к нему.
 


--------------------
я не гольфист - я хоккеист
PM MAIL   Вверх
a11en
Дата 19.3.2007, 13:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 64
Регистрация: 4.11.2006
Где: Ставрополь

Репутация: нет
Всего: нет



Простите за глупый вопрос но как запустить пример, какой файл надо открыть или запустить?
PM MAIL ICQ   Вверх
vinter
Дата 19.3.2007, 23:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 4
Всего: 56



с расширением .project или .dsw


--------------------
Мой блог
PM MAIL WWW   Вверх
Samotnik
Дата 14.5.2007, 11:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Super star !
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 7192
Регистрация: 4.11.2006
Где: Минск City

Репутация: 1
Всего: 191



Цитата(a11en @  19.3.2007,  13:37 Найти цитируемый пост)
Простите за глупый вопрос но как запустить пример, какой файл надо открыть или запустить? 

А действительно!  Как его запустить ??   smile 

В том файле кот я скачал нету  расширений 
Цитата(vinter @  19.3.2007,  23:53 Найти цитируемый пост)
с расширением .project или .dsw 

Вод. 
 Любопытно узнать как его запустить уж больно посмотреть на ето все хочется!!
 smile 
PM MAIL   Вверх
Earnest
Дата 14.5.2007, 18:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Там есть *.sln. Вот его и загружай в среду.


--------------------
...
PM   Вверх
Samotnik
Дата 16.5.2007, 01:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Super star !
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 7192
Регистрация: 4.11.2006
Где: Минск City

Репутация: 1
Всего: 191



2 Earnest
У меня Visual 6 и .sln у мя не открывается
Я делаю следущее
1 Запускаю студию пустую
2 Перетаскиваю .dsw  в проект ну и тд работаю дальше
Вод.
Я открыл студию, перетащил 

Цитата(Earnest @  14.5.2007,  18:41 Найти цитируемый пост)
*.sln.
 у мя открылась среда а в ней 10-15 строчек кода кот даже откомпилить нельзя!!! Т.к. не посвечивается компиляция. Посоветуйте что нить мож я не правильно загружаю ????

PM MAIL   Вверх
Earnest
Дата 16.5.2007, 11:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Просто 6я среда не знает формата 7й, что понятно.
Сделай новый проект и добавь туда все исходники руками.


--------------------
...
PM   Вверх
Fighter
Дата 13.7.2007, 07:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 810
Регистрация: 5.1.2005

Репутация: нет
Всего: 2



В принципе понятна логика рисования на заднем плане. Я даже своё писал, вроде все работает. Но, вопрос такой. А что если мне нужно рисовать на устройстве, у которого режим координат например MM_HIMETRIC. Как я ни пробовал устанавливать его, не работает. Он даже содержимое окна отказывается отрисовывать.
PM MAIL   Вверх
NPU_gh0st
  Дата 7.12.2007, 11:44 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 22.10.2007

Репутация: нет
Всего: нет



а когда продолжение будет? CListCtrl и т.д. или я что-то пропустил???
PM MAIL   Вверх
black_priest
Дата 7.12.2007, 12:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 19.3.2007
Где: Minsk

Репутация: нет
Всего: нет



Да-да, между прочим, хотелось бы  smile 
PM MAIL   Вверх
mzconcept
Дата 2.6.2008, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 7.5.2008

Репутация: нет
Всего: нет




Модератор: Сообщение скрыто.

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.1803 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.