| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Visual C++/MFC/WTL > Не перекрашиваются контролы |
| Автор: Dreamer_0x01 5.12.2005, 19:18 | ||||||
| А конеретно - кнопки. Все остальные элементы, включая фон диалога, ведут себя нормально. Делаю так: В описании класса:
В конструкторе:
В обработчике сообщения WM_CTLCOLOR:
|
| Автор: Dov 5.12.2005, 23:04 | ||
имхо, нужно писать свой класс, производный от CButton, хотя могу ошибаться. |
| Автор: dont 6.12.2005, 00:58 |
| The color of a standard CButton object is determined by system settings. If you want a different color for push buttons, use a CBitmapButton P.S. Copyright by MSDN |
| Автор: Earnest 6.12.2005, 09:00 | ||
Так что... owner draw по тебе плачет. |
| Автор: Dreamer_0x01 6.12.2005, 19:10 |
| Earnest сделал OWNERDRAW. Теперь кнопка действительно перекрашивается, но и не более. То есть вместо кнопки теперь однородное пятно цвета задаваемого фона кнопки. Ни натписей, ни границ кнопки, ничего нет.. |
| Автор: Любитель 7.12.2005, 11:47 |
| Можно использовать ещё Custom Draw (переопределяем только цвет), в XP - точно работает, раньше - вообще не уверен, могу прислать пример. |
| Автор: Dreamer_0x01 7.12.2005, 16:54 |
| Нужно, чтобы работало и в 98. |
| Автор: JoyEx 7.12.2005, 21:36 | ||
Dreamer_0x01, ну тогда http://www.codeproject.com/ |
| Автор: takedo 8.12.2005, 09:15 | ||
| Dreamer_0x01 Наверное ты хочешь, чтобы кнопка у тебя отображала твое устройство, и в зависимости от его состояния имела разный цвет? У меня так и есть, но я воспользовался DrawItem - в мсдн в мемберсах CButton есть примерчик. Там немного доработать в плане более правильной отрисовки, добавить в класс, производный от CButton переменную Condition и т.д. Если тебе ещё хочется, чтобы при выборе соотв. аппарата вылазили его настройки и кнопка в этот момент была нажата(когда на экране настройки), производи от CBitmapButton, только мне эта идея не понравилась - там конкретные рисунки надо сразу рисовать, немаштабируемые... А с Button я и сам разобрался в свое время за 20 минут, без знания англ, так что у тебя не должно быть проблем. Добавлено @ 09:19 Dreamer_0x01
Добавлено @ 09:20 после стиля BS_OWNERDRAW Добавлено @ 09:24 Кто знает как нарисовать объемный эллипс? В том смысле, честь ли функция типа ::DrawFrameControl только рисующая эллипс или произвольный многоугольник. Можно и самому отрисовывать, но с объемом проблемы. |
| Автор: AlexPro 8.12.2005, 13:41 |
| Dreamer_0x01, думаю, стоит прислушаться к совету JoyEx (имею в виду посещение сайтов Есть также класс CButtonST того же автора - всякие там плоские, прозрачные, текстурные кнопки - в демо-проекте выглядит весьма симпатично. Вроде как раз то, что тебе надо. Легко подключается к проекту (CXPStyleButtonST по крайней мере, второй класс не использовал) - мне понравилось. |
| Автор: Dreamer_0x01 8.12.2005, 18:46 |
| Не думал, что с кнопками все так сложно...Ладно, переопределим класс, что ж тут поделать... |
| Автор: Earnest 8.12.2005, 19:22 |
| Сочувствую и понимаю... из-за такой ерунды всю кнопку самому рисовать. Но, в общем, кнопку нарисовать не так сложно. Посмотри функцию DrawFrameControl. У нее есть такой чудесный флажок DFCS_TRANSPARENT. Обещает, что фон не поменяет. Т.е. красишь фон как надо, и рисуешь DrawFrameControl с флагами DFC_BUTTON и этим транспарент, ну и другие флажки посмотри. Именно это сама не пробовала, но вроде должно получиться. Это, так сказать, программа-минимум. Но можно и советом AlexPro воспользоваться - готовое решение поискать. |
| Автор: Dreamer_0x01 8.12.2005, 20:07 | ||
| Earnest Я вот поглядел функцию DrawItem,там я так понял контест устройства передается для различных состояний кнопки. Я правильно понимаю, что нарисовав что-то в этом контексте, я получу изображения кнопок для различных ее состояний? Или опять какая-то тонкость функция мне весь кайф испортит? И надо ли будет в этом случае DrawFrameControl вызывать (либо как-то наоборот запрещать его вызов, если он будет мешать?) Просто я хочу полностью свой дизайн приложения сделать, ни на что не похожий, но сохраняющий некие стандарты. (в том числе это касается контролов). Битмапы лепить не хочется, я наоборот, хочу как можно менее загруженный всякими объемностями/выпуклостями/рендерами интерфейс сделать, "строгий" и "максимально наглядный". Поэтому нарисовать нужные мне рамочки/значки в контексте устройства мне труда не составит. (Если это конечно тот самый контекст, в котором можно рисовать.) Битмапами принципиально делать не хочу, так как мне нужно будет еще и ресайзинг контролов делать, то есть желательно все размеры каждый раз высчитывать динамически.
Во-первых, там все по-английски, а меня от таких страниц мутит =) Во-вторых, там есть действительно очень хорошие примеры,может быть, возьму их за основу, но все равно, слишком много лишнего, и опять же, слишком "избыточно". |
| Автор: Earnest 8.12.2005, 21:07 | ||
| Не очень поняла твой вопрос. C таким же успехом, как DrawItem, ты мог бы переопределить OnPaint - как для любого своего окна. Но Windows делает за тебя часть работы: набивает структуру DRAWITEMSTRUCT и посылает паренту кнопки WM_DRAWITEM. Это стандартный путь Windows API. А MFC перехватывает это сообщение и вызывает виртуальную функцию DrawItem. Контекст, который туда передается - это текущий контекст PAINT DC, ровно тот, где и надо рисовать. Ты должен отрисовать туда кнопку в текущем состоянии. Это состояние ты можешь получить из той же структуры DRAWITEMSTRUCT. Собственно, в описании функции DrawItem для CButton есть пример кода:
В этом примере, правда, наоборот, фон стандартный, а текст рисуется другим цветом. Я вот подумала, что зря посоветовала тебе DrawFrameControl: все, что она может для тебя сделать - это нарисовать правильную рамку (вдавленную или выдавленную). Но для этого есть отдельные функции DrawEdge и Draw3DRect (выбирай какая больше нравится). Рамку фокуса рисовать - DrawFocusRect, дизабленный текст - GrayString. |
| Автор: Dreamer_0x01 8.12.2005, 22:00 |
| Сморел я этот пример, еще тогда, когда takedo про него сказал. Пробовал, перекрашивается...Но вот если присмотреться к стандартной кнопки, то при ее нажимании текст кнопки нажимается вместе с ней. А тут он остается неподвижным. Хотя, мне это как раз и не надо, я пожалуй так и сделаю, создам switch на lpDrawItemStruct->itemState и в его пунктах нарисую нужные мне рамки и значки. Кстати, если в этом примере устроить в качестве фона SetBkColor - то получится мягко говоря не очень красивая надпись =) Так что пришлось фон принудительно заливать в обработке OnPaint. |
| Автор: takedo 9.12.2005, 09:01 | ||||
Dreamer_0x01
Earnest Я вот и спрашивал
|
| Автор: Earnest 9.12.2005, 09:04 | ||
| Лучше бы все делать в одном месте, т.е. в DrawItem. Кто тебе мешает заливать фон здесь? В этой функции можешь делать все то же самое - вызываешь какой-нибудь FillRect, и все. Конечно, пример - это только пример, далеко не полный. При нажатии текст кнопки действительно надо сдвигать, примерно на 1,1 вниз по диагонали. Не забудь после отрисовки состояние DC поменять на исходное - MSDN на этом очень настаивает. Я обычно, чтобы не парится с востановлением всего, что наменяла, использую SaveDC - RestoreDC. Еще удобнее - завернуть все в классик:
Ставишь в начала функции SAVE_DC_STATE() и больше ни о чем не заботишься. Добавлено @ 09:08 takedo, на пару минут опередил |
| Автор: takedo 9.12.2005, 09:13 | ||
Я вот так сделал, много лишнего, но это вырезка из кода, думаю не страшно
|
| Автор: takedo 9.12.2005, 09:32 |
| Earnest посмотрел SaveDC так в мсдн говорят, что все текущее состояние сохраняется в "context stack" - это куда, можно узнать? Спрашиваю потому, что как и обычно твой классик - весьма удобен, но вот сомнения терзанули, а сколько может быть сохранено в этом контексте? |
| Автор: takedo 9.12.2005, 12:05 |
| Earnest Я почему спросил, мотому что не понял в каком стеке? То есть у каждого DC есть свой стек? В который мы и записываем. Но вот какая мне проблема видится: есть функция обработчик1 и функция обработчик2 сообщения 1 и 2. В фукнции 1 мы сохраняем SaveDC(hdc), в это время, приходит сообщение, вызывающее обработчик 2, в котором мы тоже SaveDC(hdc). В итоге, если сохраняем в одно и то же место можем восстановить по Restore не то. Или как то возвращаемый SaveDC параметр влияет. Вот не могу этого понять |
| Автор: JoyEx 9.12.2005, 15:27 | ||||||
Где-то в GDI-памяти, механизм стека для этих целей можно и самому сделать, но лучше не быть SaveDC(hdc) ==> RestoreDC(hdc, -1) ведь очень удобно!
Пока SaveDC() не вернет 0
Да-да, "возвращаемый SaveDC параметр" и нужен для того, чтобы не появился хаос: RestoreDC(hdc, сюда его прописывай). |
| Автор: Earnest 9.12.2005, 19:56 |
| JoyEx все правильно говорит. takedo Честно говоря, я не знаю, сколько состояний выдержит этот стек, не экспериментировала. Обычно я ставлю сохранение DC контекста в начале самой внешней функции отрисовки (которую Windows или MFC вызывают), а во внутренних уже не забочусь о том, что изменилось - внешняя функция, завершаясь, все подчистит. Пользуюсь давно, проблем не было. |
| Автор: Dreamer_0x01 10.12.2005, 15:25 |
| А может, кто на пальцах пояснит, для чего вообще этот RestoreDC нужен? Только в MSDN просьба не отсылать, на английском не пойму... |
| Автор: JoyEx 10.12.2005, 16:34 | ||
Нуууу... |
| Автор: Earnest 12.12.2005, 08:56 | ||
Да ровно для того, чтобы не писать все эти многочисленные pDC->SelectObject(pOldPen) и не запоминать олд-пены. Есть такая весьма распространенная ошибка: создаем в функции GDI-объект, выбираем его в контекст, по выходе из функции созданный объект удаляем, но забываем восстановить старый. Так вот, в этом случае GDI-объект вовсе не удаляется. Особенно в 98 это весело выглядит: пара минут работы, и все рисуется белым - кончились GDI-ресурсы, остались одни стандартные. А когда пишешь более-менее сложный код, согласись, есть о чем думать, кроме того, чтобы запомнить, что ты там выбрал в контекст. В идеале - совсем об этом не заботиться. Вот для этого идеально подходит парочка SaveDC-RestoreDC. |