Как предотвратить перемещение строки меню вниз, когда всплывающее окно открыто?

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

Кто-нибудь знает какой-нибудь способ решить эту проблему? Я пытался прикрепить невидимое меню к всплывающему окну, но не могу сделать так, чтобы меню было невидимым.

Скриншот для ясности, раздражает то, где я машу мышью:

введите описание изображения здесь


person tbodt    schedule 21.01.2016    source источник
comment
Кстати, у вас будет эта проблема не только при переходе в полноэкранный режим. В версии 10.11 можно всегда автоматически скрывать строку меню: tekrevue.com/tip/hide-menu-bar-os-x-el-capitan   -  person cacau    schedule 26.01.2016
comment
Возможно, вы захотите проверить эту тему, звучит как чистое решение вашей проблемы: stackoverflow.com/questions/35008501/   -  person Jay    schedule 28.01.2016
comment
К сожалению, ни один из ответов на этот вопрос не помог мне в моем случае. Лучшее, что мне удалось получить, это определить, когда панель меню снова становится скрытой или видимой.   -  person Josh    schedule 25.01.2019


Ответы (4)


Всплывающее окно перемещается, потому что его родительское окно является окном элемента состояния, и когда родительское окно перемещается, дочернее окно перемещается вместе с ним. (До того, как я исследовал это, я даже не знал, что у Cocoa есть родительские и дочерние окна.) Я решил проблему с этим кодом сразу после показа всплывающего окна:

NSWindow *popoverWindow = self.popup.contentViewController.view.window;
[popoverWindow.parentWindow removeChildWindow:popoverWindow];

Теперь строка меню все еще движется вверх, но, по крайней мере, всплывающее окно остается на том же месте.

person tbodt    schedule 27.01.2016
comment
Возиться с окнами, которых у тебя нет... на твоем месте я бы не пошел по этому пути. Из опыта, который вызывает проблемы и может сломаться с предстоящими выпусками ОС (или даже более старыми версиями, чем ОС, на которой вы его тестировали) - person cacau; 28.01.2016
comment
@cacau Есть идеи получше? - person tbodt; 28.01.2016
comment
Единственным другим решением, которое я нашел, было отсоединение всплывающего окна, когда панель меню скрывается (см. для отсоединения всплывающего окна) - person Josh; 15.07.2019

Либо используйте События углерода, либо следите за тем, что происходит в строке меню (окно типа NSStatusBarWindow):

Уведомления типа

  • NSWindowDidChangeOcclusionStateNotification
  • NSWindowDidMoveNotification
  • NSWindowWillCloseNotification
  • NSWindowDidCloseNotification

с объектом класса NSStatusBarWindow должен дать вам достаточно информации о показе или скрытии строки меню, чтобы добавить правильную обработку.

person Jay    schedule 28.01.2016
comment
И что такое правильная обработка? Сложность заключается не в том, чтобы узнать, когда перемещается элемент статуса, а в том, чтобы предотвратить перемещение всплывающего окна. - person tbodt; 28.01.2016

Суперхакерский подход:

Пользовательское окно с некоторым сверхвысоким уровнем окна, чтобы оно отображалось над строкой меню, а затем добавьте прозрачное пользовательское представление в новое окно, которое улавливает и обрабатывает/блокирует щелчки мыши в соответствии с вашими потребностями.

Или:

Получите экземпляр окна, который всплывающее окно использует для отображения и отслеживания/обработки NSWindowWillMoveNotification / NSWindowDidMoveNotification.

person cacau    schedule 21.01.2016
comment
Не совсем в чем моя проблема, добавил скриншот для пояснения. - person tbodt; 22.01.2016
comment
Ах, верно! Любые уведомления, которые отправляются, когда панель меню скрывается? Просто попробуйте слушать что угодно и обратите особое внимание на те, которые упомянуты в developer.apple.com/library/mac/documentation/General/ - person cacau; 25.01.2016
comment
Если есть какие-либо локальные уведомления, они будут отправлены программе, которая находится в полноэкранном режиме. Там может быть распределенное уведомление, но что я могу с этим поделать? Скрыть всплывающее окно? Это сделало бы невозможным использование всплывающего окна в полноэкранном режиме. - person tbodt; 25.01.2016
comment
..AppKit постоянно отправляет кучу уведомлений, стоит проверить. Для вашего окна не вызывается метод делегата? Для строки меню приложения? - person cacau; 26.01.2016
comment
@tbodt Или просто следите за перемещением всплывающего окна (см. измененный ответ выше) - person cacau; 26.01.2016
comment
Я понял это сам. Проверьте мой ответ, если хотите узнать, как это сделать. - person tbodt; 27.01.2016

Я преобразовал ответ @tbodt в Swift 4 и подтвердил, что он решает эту проблему:

let popoverWindow = popup.contentViewController.view.window as? NSWindow
popoverWindow?.parent?.removeChildWindow(popoverWindow!)
person Jacob Torres    schedule 17.04.2018
comment
Как упомянул Какау, не стоит возиться с внутренними окнами. Почему бы не разместить маленькое скрытое окно рядом с элементом строки состояния, когда должно быть представлено всплывающее окно, и связать его с представлением в скрытом окне. Я использовал эту технику много лет назад, чтобы предотвратить мерцание во время открытой анимации. Вы можете использовать различное поведение всплывающих окон, и для меня удаление его из родительского окна может иметь побочный эффект. - person Marc T.; 27.05.2018
comment
@МаркТ. Не будете ли вы так любезны и предоставите фрагмент кода? Сам столкнулся с похожей проблемой и не совсем понял, что вы имеете в виду. - person Pavel Lobodinský; 27.08.2018
comment
Мне тоже было бы очень интересно увидеть такой пример. Я хотел бы, чтобы всплывающее окно следовало за строкой меню вверх, но останавливалось, когда оно достигало верхней части экрана, чтобы ни одно из всплывающих окон не было обрезано. - person Josh; 25.01.2019