Главная

Вопрос по BMenu

Мне нужно сделать нечто, похожее на Calendar Control Алексея Сарикова. Функциональность почти такая же, только мой календарный контроль должен уметь работать с различными календарями, выделять другим цветом выходные дни, уметь начинать неделю в разные дни, поддерживать вывод «справа налево» и делать много других вещей, которые оригинальный Calendar Control делать не умеет.

Тем не менее, внешний вид моего Control`а должен быть похож на вышеупомянутый Calendar Control. Скриншотов, увы, нет, поэтому включаем воображение.

Я решил сделать BView, детьми которого будут BTextControl для того, чтобы выводить дату текстовой строкой, и какая–нибудь кнопка, выводящая средство выбора даты. Средство выбора даты — это таблица 8х7, в первой строке которой можно выбрать месяц и год, затем идёт строка названий дней недели, а затем — до шести строк по семь ячеек в каждой, где располагаются индивидуальные дни. Пока всё логично, верно?

(На самом деле, размеры таблицы рассчитываются динамически, потому что мой Control работает и с французским революционным календарём, в неделе которого 10 дней, и с советским календарём с 5–дневной неделей, но не суть).

Алексей Сариков строит это «средство вывода даты» в BBitmap. То есть — создаётся BBitmap достаточного размера, чтобы внутри поместились все числа месяца, затем идёт заполнение этого BBitmap осмысленной информацией чуть ли не вручную: в цикле перемещение «ручки» из квадрата в квадрат и отрисовка в BBitmap даты для каждого отдельного дня. По нажатию кнопки этот BBitmap просто рисуется поверх всех остальных элементов интерфейса, следующий клик мышки перехватывается, и, исходя из места щелчка, отображённая дата меняется или не меняется.

Я решил пойти другим путём (помнится, в начале XX века этот способ привёл одного парнишку из уездного сибирского городка на вершину власти) и использовать BMenu. Для этого я создаю обычный BMenuBar, который будет содержать одно–единственное меню. Отдельно я создаю это меню, с раскладкой B_ITEMS_IN_MATRIX, и передаю ему длину и ширину достаточного размера, чтобы в полученном поле отобразить весь месяц. Затем я начинаю набивать это меню вкусняшками, в цикле создавая BMenuItem`ы и располагая их в BMenu в нужных квадратиках. Соответственно, при щелчке выбранный BMenuItem пошлёт мне сообщение, я его получу, изменю дату, в случае нужды перерисую меню, и все будут счастливы.

Так это должно было работать в теории. Чтобы проверить, как оно будет работать на самом деле, я начал с маленького: добавил только одно меню, для выбора месяца. И сразу столкнулся с проблемами:

1) BMenu приобретает размеры BMenuItem, который я пытаюсь в него загнать.

Создание BMenuBar:
openMenuButton = new BMenuBar(button,
"openMenu",
B_FOLLOW_RIGHT | B_FOLLOW_TOP,
B_ITEMS_IN_ROW,
false);
openMenuButton–>AddItem(dateSelector); // dateSelector — это и есть меню, показывающее дни.
openMenuButton–>SetTargetForItems((BHandler*)this);
AddChild(openMenuButton);

Создание меню dateSelector: (до этого я рассчитал размеры, нужные для того, чтобы вместить весь месяц, и записал их в rectangle).
dateSelector = new BMenu("↓", // Имя для меню — стрелка вниз
rectangle.Width(),
rectangle.Height());
// Build the list of months and year.
BMenu* listOfMonths = CreateMonthsMenu(monthNames);
dateSelector–>AddItem(listOfMonths, BRect(10, 10, 150, 150)); // Цифры взяты от балды

И я получаю такую картину:
27.62 КБ

Дело в том, что, согласно BeBook, если вызывать AddItem(BMenu*, BRect), то этот BRect определит местоположение контролирующей подменю BMenuItem. BRect при этом должен быть в координатной системе меню, и (0, 0) соответствует верхнему левому углу BMenu. Передавая BRect(10, 10, 150, 150), я ожидал создания контролирующего BMenuItem в 10 пикселях от верхней границы BMenu view и в 10 пикселях от его левой границы. Как видно из скриншота, 10 пикселей от левой границы выдерживаются, но от верхней границы созданный BMenuItem отделяют пикселей сто, не меньше.

Если же изменить последнюю строку в куске кода выше на что–то более осмысленное — к примеру, BRect(0, 0, 98, 20), то есть прямоугольник, достаточный для показа любого месяца, и начинающийся прямо из верхней левой точки контролирующего BMenu — я получаю следующую феерическую картину:

5.74 КБ

Я менял размер одного BMenuItem, а изменил размер всего меню, которое этот BMenuItem в себя включает. Само меню listOfMonths создаётся и инициализируется, но находится вне пределов этого крохотного окошка.

Это у меня кривые руки, или в Гайке что–то недокручено? Куда крутить / как исправлять? Есть ли у кого ссылки на работающий пример меню, использующий BMenu с layout B_ITEMS_IN_MATRIX, потому что MenuWorld из BeOS R5 работает точно так же (то есть никак, см. скриншот ниже)?

2.71 КБ

Отбой боевой

Отбой боевой тревоги. Проблема была в Гайке, и она уже решена в версии 38828.

Правда, другая проблема — которую я загнал в Trac под номером 6600 — всё равно осталась.

Кстати, есть ли у кого–нибудь идеи, как её решить? А то сеть из–под Гайки нужна.

А под каким

А под каким VirtualBox–ом (с бриджем на ipro1000) на той–же машинке не проверял? Очень уж на на какую–то специфику окружения смахивает. Если–бы было что–то системное — народ бы уже давно выл за отсутствием интернета.

В VirtualBox всё

В VirtualBox всё в порядке… Я уж не знаю, что и думать. :(

Может быть

Может быть проблема с конкретным драйвером сетевой карты. А в VMWare есть возможность разные сетевухи эмулировать?

Во–первых,

Во–первых, в старой версии Гайки, но в той же версии программы VMWare всё работает. Во–вторых, UDP и сейчас работает без проблем. Только TCP не работает.

Ну это сколько

Ну это сколько угодно — забыть в драйвере настроить мультикаст — и получается отвал через 1200 секунд. Вернуть ошибку раньше чем другие драйвера это делают — и вот тебе облом в первой DHCP сессии и вообще драйвер стеком после этого воспринимается как не работающий. sis900 вон до сих пор починить не могут как он перестал работать после акселевских улучшений в сетевом стеке. Или DHCP сервер живёт в другой подсети — виртуальные машинки на две недели выпадают из жизни после очередного «рефакторинга». В общем, не мне тебе рассказывать о причудах софтовой разработки. ;–)
Попробуй в виндовой хост машине WireShark–ом посмотреть как пакеты ходят от гайко–машинки к интересующему тебя хосту и обратно. По крайней мере может локализуется проблема. Если не запамятовал в твоем tcpdump–е на Траке нету ответов от ремоты, да?

Ещё один вопрос

Ещё один вопрос по тому же BMenu: а как его программно открыть?

Мне нужно по определённому событию открыть BMenu, которое привязано к BMenuBar и управляется самым обычным BMenuItem (который BMenuBar создаёт сама при вызове AddItem(BMenu*)). У меня есть пойнтер на это BMenu и на BMenuBar. В BMenuBar только один BMenuItem, поэтому BMenuBar–>ItemAt(0) даст мне и BMenuItem, контролирующий нужное меню. Казалось бы, есть всё необходимое, да?

Фиг там.

1) BMenuBar::MouseDown(BPoint (верхний левый угол BMenuBar по X плюс 10 пикселей, верхний левый угол BMenuBar по Y плюс 10 пикселей) ) ничего не делает.
2) У BMenuItem вообще нет никакого MouseDown, ей управляет то меню, в котором она находится (в данном случае — BMenuBar).
3) Если взять BPoint из первого пункта, перевести его в координаты окна и выполнить BWindow::MouseDown(BPoint converted_to_window), то BWindow получает соответствующий message и забивает на него большой болт.
4) Если то же самое сделать с BView, в котором находится BMenuBar, то есть вызвать BView::MouseDown(BPoint converted_to_window), то сообщение приходит, но ничего не происходит. Координаты точки правильные, потому что этот BView занимает всё окно целиком. Ну и я ещё на всякий случай по пикселю посчитал: точка и правда находится над BMenuBar и точно над BMenuItem, которая контролирует меню, которое мне нужно открыть.
5) BMenuItem–>Invoke() вызвать нельзя, это функция protected. Да и если бы можно было: этот конкретный BMenuItem создаю не я, а BMenuBar, когда к нему BMenu присобачивают. Создавать свой класс мне кажется несколько геморно.
6) Естественно, MakeFocus() на что бы то ни было не помогает.
7) Самых многообещающих результатов я достиг с помощью BMenu::Show(). Меню рисуется на экране — и зависает намертво, не реагируя на щелчки мышкой, перетаскивания окна и т. д.. Вызов BMenu::Track(), BMenu::AttachedToWindow() или ещё чего–нибудь подобного не помогает. Единственный способ его «оживить» — закрыть его щелчком на BMenuItem, которая его контролирует, и открыть снова. Но, естественно, мне это не нужно; мне надо, чтобы оно сразу работало.

Возможно, я смог бы решить свою проблему с помощью BPopUpMenu, но оно меньше отвечает другим моим потребностям… В общем, ваше слово.

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Allowed HTML tags: <a> <em> <i> <img> <strong> <b> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Строки и параграфы переносятся автоматически.

Подробнее о форматировании

CAPTCHA
Введите перечисленные символы, чтобы мы убедились, что вы не робот. Не требуется для зарегистрированных пользователей.
1
9
U
2
9
A
Enter the code without spaces and pay attention to upper/lower case.