Рисование градиентов вручную для кнопок, панелей инструментов, вкладок и т. Д.? - PullRequest
3 голосов
/ 18 января 2010

Я хотел бы обновить код, похожий на панель инструментов, нам нужно иметь округлость градиента Vista / Win7.

В настоящее время кнопки выглядят как Windows 2000: блочные, однотонные.

Я играл с темами XP, используя DrawThemeBackground, DrawThemeEdge и т. Д .;но я очень недоволен механикой рисования темы (кнопки большие, а тема рисует их в виде 2-х тонов, верхней половины и нижней половины, что выглядит хорошо, когда кнопки маленькие - это дает им наполовину приличный видбудучи градиентом или имеет округлое качество для них. Но как бы ни велики эти кнопки, они выглядят глупо.

Экспериментируя, просто наблюдая, сколько элементов управления нарисовано в различных приложениях и элементах управления, я могу видеть, чтобольшинство из них, кажется, используют градиенты - когда верхняя часть элемента управления выглядит светлым и постепенно переходит в нижнюю часть к более темному цвету - ИЛИ - где он светлее, чем фон в верхней части, увеличивается почти до белого цвета напосередине, затем постепенно возвращается к более темному цвету внизу.

Я не совсем уверен, куда идти дальше. DrawThemeXXX кажется неадекватным. Я действительно не хочу заменять весь элемент управления нановый, который улучшил рисование, но потребовал бы, чтобы я поменял часть кода длякак работает текущий пользовательский элемент управления, и рискуйте различными проблемами с какой-либо другой библиотекой. Я бы предпочел просто нарисовать произвольные объекты в стиле текущей версии Windows, на которой я работаю. Я бы подумал, что функции рисования темы могли бы охватить это.Но они довольно сильно повреждены, как я описал.

Может кто-нибудь указать мне на 'Как современные приложения C ++ должны рисовать пользовательские элементы графического интерфейса, чтобы они могли разумно ожидать изящного внешнего вида под XP,Vista и Windows 7? '

В нашем коде в настоящее время мы используем API MFC, Gdiplus и сырые Win32.

Надеемся, что кто-то знает, как много рисовать современные графические интерфейсы.под Windows из C ++!

Только для того, чтобы это не стена текста, вот текущая версия обработчика рисования, который рисует кнопку с выгравированной границей при «горячем отслеживании» и одновременно с травлениемрамка и значок + текст «нажаты» (смещены на 1,1) в состоянии нажатия:

void CPlacesButton::PaintButton(CDC & dc, CRect & rcClient)
{
 const int kLabelHeight = 8;

 COLORREF clrHiLt = GetSysColor(COLOR_BTNHIGHLIGHT);
 COLORREF clrShdo = GetSysColor(COLOR_BTNSHADOW);
 COLORREF clrText = GetSysColor(COLOR_BTNTEXT);
 COLORREF clrFace = GetSysColor(COLOR_BTNFACE);

 // draw the button's background & border

 if (m_bPressed || m_bDrawPressed || m_bMouseOnButton)
 {
  COLORREF clrDarkened = Darken(clrFace, -0.01f);
  dc.FillRect(rcClient, &CBrush(clrDarkened));

  //dc.Draw3dRect(rcClient, clrShdo, clrHiLt);
  //dc.RoundRect(&rcClient, CPoint(10,10));
  dc.DrawEdge(&rcClient, EDGE_ETCHED, BF_RECT|BF_FLAT);
  //dc.DrawFrameControl(&rcClient, DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);
 }
//  else if (m_bMouseOnButton) // hot draw
//   //dc.Draw3dRect(rcClient, clrShdo, clrHiLt);
//   dc.DrawEdge(&rcClient, EDGE_ETCHED, BF_RECT);
//   //dc.RoundRect(&rcClient, CPoint(10,10));
 else
  dc.FillRect(rcClient, &CBrush(clrFace));

 // use transparent mode for everything that follows
 dc.SetBkMode(TRANSPARENT);

 // center icon
 CPoint ptIcon((rcClient.Width() - m_nIconSize) / 2, ((rcClient.Height() - m_nIconSize) / 2) - kLabelHeight);
 if (m_bPressed || m_bDrawPressed)
  ptIcon.Offset(1, 1);

 // determine the state to draw ourselves in
 const UINT nState = DST_ICON | (IsEnabled() ? DSS_NORMAL : DSS_DISABLED);

 // draw our icon
 dc.DrawState(ptIcon, CSize(m_nIconSize, m_nIconSize), m_hIcon, nState, (HBRUSH)NULL);

 // create & select the font to use for the button's label
 CFont guiFont;
 VERIFY(guiFont.CreateStockObject(DEFAULT_GUI_FONT));
 AutoSelectGDIObject select_font(dc, guiFont);

 // determine clipping rect for label
 CRect rcText(0, ptIcon.y+m_nIconSize+kLabelHeight, rcClient.Width(), ptIcon.y+m_nIconSize+kLabelHeight);
 rcText.InflateRect(0,20);
 if (m_bPressed || m_bDrawPressed)
  rcText.OffsetRect(1, 1);

 dc.SetTextColor(clrText);
 if (IsEnabled())
  dc.DrawText(m_strCaption, rcText, DT_VCENTER|DT_SINGLELINE|DT_CENTER);
 else
  dc.GrayString(NULL, NULL, (LPARAM)(LPCTSTR)m_strCaption, 0, rcText.TopLeft().x, rcText.TopLeft().y, rcText.Width(), rcText.Height());
}

Я оставил некоторые закомментированные варианты в коде, чтобы указать некоторые подсказки относительно того, что другоевозможности, которые я пробовалОднако это всего лишь подсказка, поскольку полных альтернативных примеров нет.

Ответы [ 3 ]

4 голосов
/ 18 января 2010

На самом деле дублирование внешнего вида различных версий Windows смехотворно сложно, особенно если ваше приложение может работать на нескольких версиях Windows.

Я думаю, что они намеревались дать вам API для этого в дни Win2k / Win95, но затем WinXP пришел с затенением и оверлеями, а старый API был совершенно неадекватным.

Таким образом, они придумали материал для темы, который на самом деле даже не API, а API и набор графических примитивов, все вместе. Но они не реализовали и не позволили расширить или заменить набор графических примитивов, поэтому темы работают только тогда, когда ваши элементы управления близко соответствуют стандартному набору.

Итак, для Win9x / Win2k. Вы используете

DrawFrameControl
DrawEdge

Для WinXP

DrawTheme

Для WinVista / 7

DrawTheme
DwmXXX functions
GradientFill ??

Теперь я подозреваю, что Windows на самом деле не использует GradientDraw. Я подозреваю, что на самом деле он использует некоторые шейдеры DX10, которые встроены в код менеджера окон, но я не знаю, как это сделать, поскольку вместо этого я использовал GradientDraw. Этот код даст вам линейное затухание от вершины элемента управления до низа.

INLINE void SetTrivertex(TRIVERTEX & vtx, int x, int y, COLORREF cr)
{
   vtx.x      = x;
   vtx.y      = y;
   vtx.Red    = (SHORT)(GetRValue(cr) * 256L);
   vtx.Green  = (SHORT)(GetGValue(cr) * 256L);
   vtx.Blue   = (SHORT)(GetBValue(cr) * 256L);
   vtx.Alpha  = (SHORT)(255 * 256L);
}

...

  // fill the interior from the top down with a gradient that starts at crTop
  // and ends with the crBottom
  TRIVERTEX vtx[2];
  SetTrivertex (vtx[0], prc->left+1, prc->top+1, crTop);
  SetTrivertex (vtx[1], prc->right-1, prc->bottom-1, crBottom);

  GRADIENT_RECT gRect = { 0, 1 };
  GradientFill(hdc, vtx, 2, &gRect, 1, GRADIENT_FILL_RECT_V); 
4 голосов
/ 18 января 2010

Вы никогда не упоминали MFC Feature Pack.Вы уже посмотрели на это?Скачать для VS2008, входит в комплект VS2008 SP1.CDrawingManager имеет множество специальных эффектов.Отличная поддержка тем приложений.

1 голос
/ 18 января 2010

MFC сам по себе не совсем подходит для снятия шкур. Помимо использования другого графического интерфейса пользователя ( Qt отлично подходит для создания пользовательских скинов), вы можете посмотреть на такие решения, как SkinCrafter .

...