Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Отрисовка элементов комбобокса.  (Прочитано 11728 раз)
0 Пользователей и 1 Гость смотрят эту тему.
KBAC
Постоялец

ru
Offline Offline
Пол: Мужской

« : 14-11-2012 19:23 » 

Здравствуйте всем. Хочу такой виджет
, но получается не свосем то что хочу
.
Не понятно, во-первых: Как избавиться от грязи при отображении элемента, когда список не открыт (не в выпадающем списке).
во-вторых: почему у некоторых элементов размер не подходит по размеру к отображаемому элементу (как например у Andalus (2я картинка). Печатает по середине и все тут.)
Код: (C#)
public Form1()
        {
            InitializeComponent();

            System.Drawing.Text.InstalledFontCollection fontList = new System.Drawing.Text.InstalledFontCollection();
            foreach (System.Drawing.FontFamily ff in fontList.Families)
            {
                comboBoxFont.Items.Add(ff.Name);
            }
            comboBoxFont.DropDownWidth = 450;
            comboBoxFont.DropDownStyle = ComboBoxStyle.DropDownList;
            comboBoxFont.SelectedIndex = 0;
            comboBoxFont.MaxDropDownItems = 20;

        }

        private static int fontSize = 10;
        private static string illText = "The quick brown fox";
        private static System.Drawing.FontStyle availableFS = FontStyle.Regular;

        private void comboBoxFont_DrawItem(object sender, DrawItemEventArgs e)
        {

            e.DrawBackground();
                                   
            string text = comboBoxFont.GetItemText(comboBoxFont.Items[e.Index]);

            System.Drawing.FontFamily ff = new System.Drawing.FontFamily(text);

            if (ff.IsStyleAvailable(FontStyle.Regular))
                availableFS = FontStyle.Regular;
            else if (ff.IsStyleAvailable(FontStyle.Bold))
                availableFS = FontStyle.Bold;
            else if (ff.IsStyleAvailable(FontStyle.Italic))
                availableFS = FontStyle.Italic;


            Font ordinaryFont = new System.Drawing.Font("Arial", fontSize, FontStyle.Regular);
            Font illFont = new Font(text, fontSize, availableFS);

            // Setting dropdown list width
            SizeF sizeIllText = e.Graphics.MeasureString(illText, illFont);
            SizeF sizeText = e.Graphics.MeasureString(text, ordinaryFont);
            comboBoxFont.DropDownWidth = Convert.ToInt32(Math.Max(sizeIllText.Width + sizeText.Width + 50,
                comboBoxFont.DropDownWidth));
           
            e.Graphics.DrawString(text, ordinaryFont, System.Drawing.Brushes.Black,
                new RectangleF(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height));

            e.Graphics.DrawString(illText, illFont, System.Drawing.Brushes.Black,
                new RectangleF(e.Bounds.Right - sizeIllText.Width - 5, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height));
        }

        private void comboBoxFont_MeasureItem(object sender, MeasureItemEventArgs e)
        {
            string text = comboBoxFont.GetItemText(comboBoxFont.Items[e.Index]);

            System.Drawing.FontFamily ff = new System.Drawing.FontFamily(text);

            if (ff.IsStyleAvailable(FontStyle.Regular))
                availableFS = FontStyle.Regular;
            else if (ff.IsStyleAvailable(FontStyle.Bold))
                availableFS = FontStyle.Bold;
            else if (ff.IsStyleAvailable(FontStyle.Italic))
                availableFS = FontStyle.Italic;

            Font illFont = new Font(text, fontSize, availableFS);

            SizeF sizeIllText = e.Graphics.MeasureString(illText, illFont);

            if (e.ItemHeight < sizeIllText.Height)
                e.ItemHeight = (int)sizeIllText.Height;
        }

* sd.bmp (548.49 Кб - загружено 1647 раз.)
* sd1.bmp (414.8 Кб - загружено 1725 раз.)
Записан

У тебя все получится, главное -- верить и делать.
Порадоваться, когда все плохо -- легче, чем ты думаешь.
В действии счастье.
Вовлекая людей важно быть увлеченным чужой жизнью.
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #1 : 14-11-2012 22:23 » 

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

2. Проверь высоту items. Обрати внимание, в приведённом тобой примере, высота у них одинаковая, а у тебя разная. Проблема не только у Andalus. Batang обрезан снизу.
« Последнее редактирование: 14-11-2012 22:35 от Джон » Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
KBAC
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 15-11-2012 03:45 » 

Джон, там еще более выраженный косяк есть Улыбаюсь

Может, думаю, сделать элементы фиксированным размером (DrawMode.OwnerDrawFixed) и рисовать красивую строку в отдельном методе (Да, название и строка обязательно нужны). ? Тогда, может, появится возможность обработать элемент на комбобоксе как надо, т.е. не быду вызывать отрисовку строчки примера. Хотя и без метода можно..

От одной проблемы я избавился
Код: (C#)
if (e.Bounds.Width > (sizeIllText.Width + sizeText.Width))
                e.Graphics.DrawString(illText, illFont, System.Drawing.Brushes.Black,
                    new RectangleF(e.Bounds.Right - sizeIllText.Width - 5, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height));

Теперь нет "грязи" в верхнем элементе

* sd1.bmp (422.1 Кб - загружено 1806 раз.)
« Последнее редактирование: 15-11-2012 04:44 от KBAC » Записан

У тебя все получится, главное -- верить и делать.
Порадоваться, когда все плохо -- легче, чем ты думаешь.
В действии счастье.
Вовлекая людей важно быть увлеченным чужой жизнью.
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #3 : 15-11-2012 10:00 » 

Давай определимся с терминологией. Комбобокс называется так потому, что комбинирует в себе два элемента управления: редактор и список. В зависимости от типа (стиля) комбобокса возможны варианты: редактор read only, или нет; список видно всегда, или он распахивается.

(Да, название и строка обязательно нужны).

В редакторе? Зачем? Дополнительный текст можно отображать, тут можно согласиться, в списке, а в редакторе достаточно только имени шрифта. Как в твоём примере.

Цитата
Теперь нет "грязи" в верхнем элементе

Блин, как всё запущено. Жаль Если ты привыкнешь ТАК избавляться от проблем, то в будущем тебя ждут большие нехорошие сюрпризы.

"Я тебя полюбил, я тебя научу" (с) "Кин-дза-дза" Ага

Смотри. У комбобокса есть несколько типов, а точнее состояний, отрисовки items. Есть item, когда комбобокс "схлопнут" (в твоём случае это то место, где у тебя "грязь"). Есть item в распахнутом списке. Плюс к ним добавляются состояния select. В каком именно состоянии находится текущий отрисовываемый item, ты узнаешь из свойства State объекта DrawItemEventArgs e.
Например, ты рисуешь текст чёрным цветом. Хорошо? На системах в стиле w2k, когда отключена вся мишура, цвет выделения тёмно синий. Значит твой текст не будет видно, если его выделить. Значит, тебе надо менять цвет текста, в зависимости от состояния Selected. И тд. Точно так же ты можешь реагировать на запрещение отрисовки доп. текста, если это, например, item редактора.
Возможнные состояния описаны в MSDN DrawItemState


Насчёт высоты, как я уже сказал, решаешь сам, как тебе лучше, удобней, быстрей сделать (конечно, если нет ТЗ).
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
KBAC
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 15-11-2012 18:49 » 

Джон, да, с состояниями поленился я что-то и не стал читать. Изменил. Спасибо.

Цитата
Дополнительный текст можно отображать, тут можно согласиться, в списке, а в редакторе достаточно только имени шрифта. Как в твоём примере.
Тут я согласен. Сразу не понял о чем речь; говорил про выпадающий список Улыбаюсь .

Добавлено через 33 дня, 22 часа, 39 минут и 17 секунд:
Заметил такую хрень: Нажимаю первый раз - комбобокс не реагирует на клик, второй раз - все равно не реагирует.
В отладке посмотрел что происходит в эти моменты - оказывается обработчик DrawItem вызывается много раз. Но черт бы с ним, пусть вызывается раз надо, но почему щелчек не проходит?
« Последнее редактирование: 19-12-2012 17:29 от KBAC » Записан

У тебя все получится, главное -- верить и делать.
Порадоваться, когда все плохо -- легче, чем ты думаешь.
В действии счастье.
Вовлекая людей важно быть увлеченным чужой жизнью.
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #5 : 19-12-2012 18:23 » 

Сообшение про шелчек к нему проскальзывают?
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
KBAC
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 24-12-2012 15:51 » new

Если назначить обработчик на событие Click, то он благополучно запускается с первого раза. Но список при этом не выпадает.

Получилось узнать что происходит в этот момент за кадром.
Действующие лица.
Основная форма (Browser), которая открывает другую форму настроек (ConfigForm). Т.е. Browser родитель для ConfigFom'ы
Код:
ConfigForm.comboBoxFont_DrawItem(object sender, DrawItemEventArgs e)
является обработчиком DrawItem у комбобокса(comboboxFont), который (естественно) находится на ConfigForm.
Код:
protected override void WndProc(ref System.Windows.Forms.Message message);
переопределен в Browser'e (родителе ConfigForm). WndProc обрабатывает системный события, получается(?), ну или сообщения.

Вот сообщения, которые появляются в определенном порядке (порядок ниже) в WndProc.
номерописание
0x210WM_PARENTNOTIFY            
Sent to a window when a significant action occurs on a descendant window. This message is now extended to include the WM_POINTERDOWN event. When the child window is being created, the system sends WM_PARENTNOTIFY just before the CreateWindow or CreateWindowEx function that creates the window returns. When the child window is being destroyed, the system sends the message before any processing to destroy the window takes place.
0x1cWM_ACTIVATEAPP
Sent when a window belonging to a different application than the active window is about to be activated. The message is sent to the application whose window is being activated and to the application whose window is being deactivated
0x46WM_WINDOWPOSCHANGING
Sent to a window whose size, position, or place in the Z order is about to change as a result of a call to the SetWindowPos function or another window-management function.
0x47WM_WINDOWPOSCHANGED
Sent to a window whose size, position, or place in the Z order has changed as a result of a call to the SetWindowPos function or another window-management function.

С первым щелчком по combobox'у начинается цикл. Цифрами будут обозначены события захода в WndProc с соответствующим кодом сообщения, а заход в comboBoxFont_DrawItem буду обозначать как "Draw"

Занавес.
Начинается вот такой цикл (в скобках зацикливание).
Код:
Draw Draw* 1c Draw 201 Draw (46 47 1c Draw 1c Draw Draw)
Со временем он оканчивается, конечно, а выпадающего списка я не дожидаюсь.
Может еще полезным будет знать:
* после отработки функции подсвечивается кнопка, по которой открывается комбобокс (становится как бы нажатой).
В переходе между функциями 1с и drawItem стирается отображаемое значение в поле edit комбобокса.

Кому интересно, может помочь разобраться Улыбаюсь

Код WndProc
Код:
protected override void WndProc(ref System.Windows.Forms.Message message)
        {
            if (message.Msg == WM_OPENIETRWND) //WM_OPENIETRWND - пользовательское сообщение
            {
                // сюда не заходит вообще никогда :)
            }
            base.WndProc(ref message);
         }


Добавлено через 1 день, 19 часов, 3 минуты и 49 секунд:
Получается, что после первого щелчка по комбобоксу теряется фокус у окна, при втором щелчке фокус возвращается, и далее уже можно работать с комбобоксом.

Добавлено через 4 дня, 32 минуты и 46 секунд:
Оказалось все это из-за того, что я в Draw менял DropDownWidth. Т.е. постоянно вызывалась перерисовка.
« Последнее редактирование: 30-12-2012 13:06 от KBAC » Записан

У тебя все получится, главное -- верить и делать.
Порадоваться, когда все плохо -- легче, чем ты думаешь.
В действии счастье.
Вовлекая людей важно быть увлеченным чужой жизнью.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines