Итак, у меня есть приложение, поведение окна которого я хотел бы больше походить на Photoshop CS. В Photoshop CS окна документов всегда остаются за окнами инструментов, но остаются окнами верхнего уровня. Для дочерних окон MDI, поскольку окно документа на самом деле является дочерним, вы не можете переместить его за пределы главного окна. В CS, однако, вы можете перенести изображение на другой монитор, что является большим преимуществом перед пристыкованными приложениями, такими как Visual Studio, и над обычными приложениями MDI.
Во всяком случае, вот мои исследования. Я попытался перехватить сообщение WM_MOUSEACTIVATE и использовать команды DeferWindowPos для моего собственного упорядочивания окна, а затем вернуть MA_NOACTIVATEANDEAT, но это приводит к тому, что окно не активируется должным образом, и я считаю, что есть другие команды, которые «активируют» "окно без вызова WM_MOUSEACTIVATE (как я думаю, SetFocus ()), так что этот метод, вероятно, все равно не сработает.
Я считаю, что процедура Windows для "активации" окна проста. 1. уведомить неактивированное окно сообщениями WM_NCACTIVATE и WM_ACTIVATE 2. переместить окно в верхнюю часть z-порядка (отправка сообщений WM_POSCHANGING, WM_POSCHANGED и перерисовка сообщений) 3. уведомить новое активированное окно сообщениями WM_NCACTIVATE и WM_ACTIVATE.
Кажется, самый чистый способ сделать это - перехватить первое сообщение WM_ACTIVATE и каким-то образом уведомить Windows, что вы собираетесь переопределить их способ выполнения z-упорядочения, а затем использовать команды DeferWindowPos, но я не могу понять как это сделать. Похоже, что как только Windows отправит сообщение WM_ACTIVATE, она уже будет выполнять переупорядочение по-своему, поэтому любые команды DeferWindowPos, которые я использую, переопределяются.
Прямо сейчас у меня есть базовая реализация квази-работы, которая делает окна инструментов наверху, когда приложение активировано, но затем делает их не наверху, когда это не так, но это очень причудливо (иногда оно оказывается поверх других окон, таких как диспетчер задач, тогда как Photoshop CS этого не делает, поэтому я думаю, что Photoshop каким-то образом делает это по-другому), и кажется, что есть более интуитивный способ сделать это.
Во всяком случае, кто-нибудь знает, как это делает Photoshop CS, или способ лучше, чем использовать topmost?





Я предполагаю, что они, поскольку они не используют .NET, свернули свой собственный оконный код за многие годы его существования, и теперь, как и оригинальный ОБИДОС Amazon, он настолько адаптирован к их продукту, что готовый ( aka .NET MDI support) просто не собираются подходить близко.
Я не люблю отвечать без реального ответа, но, скорее всего, вам придется потратить много времени и усилий, чтобы получить что-то подобное, если подобная Photoshop действительно ваша цель. Стоит ли потратить на это время? Просто помните, что программисты много за годы и версии много собрались вместе, чтобы заставить простое на вид поведение окна Photoshop работать правильно и чувствовать себя естественным для вас.
Похоже, вам уже нужно довольно глубоко вникнуть в функции и значения Win32 API, чтобы хотя бы мельком увидеть «решение», и это должно быть вашим первым красным флагом. Возможно ли это в конце концов? Наверное. Но в зависимости от ваших потребностей, вашего времени и множества других факторов, которые вы можете решить, это может оказаться непрактичным.
Не будучи знакомым с Photoshop CS, немного сложно точно знать, какой внешний вид вы пытаетесь достичь.
Но я бы подумал, если бы вы создали немодальное диалоговое окно как окно инструментов и убедились, что оно имеет стиль WS_POPUP, тогда результирующий окно инструментов не будет обрезан в главном родительском окне, и Окна будет автоматически управлять z-порядок, следя за тем, чтобы окно инструментов оставался поверх родительского окна.
И поскольку диалог окно инструментов немодален, он не будет мешать работе главного окна.
Управление Z-порядком окон, как в Photoshop CS
Вы должны создать окно инструментов с изображением в качестве родителя, чтобы окна управляли zorder. Нет необходимости устанавливать WS_POPUP или WS_EX_TOOLWINDOW. Эти флаги управляют только отображением окна.
Вызовите CreateWindowEx с hwnd окна изображения в качестве родительского.
Я не видел ничего примечательного в Photoshop CS, требующего чего-либо, близкого к этому уровню взлома, что нельзя было бы сделать, просто указав правильные отношения между окнами владельца при создании окон. то есть любое окно, которое должно быть показано над другим окном, определяет это окно как его владельца при создании - если у вас есть несколько окон документов, каждое из них получает свой собственный набор дочерних окон, которые вы можете динамически показывать и скрывать по мере увеличения окна документа и теряет активацию.
В ответ Крису и Эммануэлю проблема с использованием функции окна владельца заключается в том, что окно может принадлежать только одному другому окну, и вы не можете изменить владельца окна. Итак, если окна инструментов A и B всегда должны быть поверх окон документов C и D, тогда, когда окно документа C активно, я хочу, чтобы оно принадлежало окнам A и B, чтобы A и B всегда были поверх него. Но когда я активирую окно документа D, мне придется сменить владельца окон инструментов A и B на D, иначе они будут находиться за окном D (поскольку они принадлежат окну C). Однако Windows не позволяет менять владельца окна, поэтому этот параметр недоступен.
На данный момент у меня он работает с самой верхней функцией, но в лучшем случае это взлом. Меня действительно утешает тот факт, что GIMP пробовал имитировать Photoshop в своей версии 2.6, но даже их реализация иногда работает странно, что наводит меня на мысль, что их реализация тоже была взломом.
Вы пытались сделать окна инструментов наверху, когда основное окно получает фокус, и не наверху, когда оно теряет фокус? Похоже, вы уже начали искать такого рода решения ... но гораздо более сложные.
В качестве примечания, кажется, довольно хорошо задокументировано, что окна инструментов демонстрируют неожиданное поведение, когда дело доходит до z-упорядочения. Я не нашел ничего в MSDN, чтобы подтвердить это, но, возможно, Windows управляет ими специально.
Вы можете попробовать обработать событие WM_WINDOWPOSCHANGING, чтобы предотвратить перекрытие других окон (с псевдо-верхним флагом). Таким образом, вы избегаете всех проблем с установкой / сбросом флага TopMost.
public class BaseForm : Form
{
public virtual int TopMostLevel
{
get { return 0; }
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumThreadWindows(uint dwThreadId, Win32Callback lpEnumFunc, IntPtr lParam);
/// <summary>
/// Get process window handles sorted by z order from top to bottom.
/// </summary>
public static IEnumerable<IntPtr> GetWindowsSortedByZOrder()
{
List<IntPtr> handles = new List<IntPtr>();
EnumThreadWindows(GetCurrentThreadId(),
(hWnd, lparam) =>
{
handles.Add(hWnd);
return true;
}, IntPtr.Zero);
return handles;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)WindowsMessages.WM_WINDOWPOSCHANGING)
{
//Looking for Window at the bottom of Z-order, but with TopMostLevel > this.TopMostLevel
foreach (IntPtr handle in GetWindowsSortedByZOrder().Reverse())
{
var window = FromHandle(handle) as BaseForm;
if (window != null && this.TopMostLevel < window.TopMostLevel)
{
//changing hwndInsertAfter field in WindowPos structure
if (IntPtr.Size == 4)
{
Marshal.WriteInt32(m.LParam, IntPtr.Size, window.Handle.ToInt32());
}
else if (IntPtr.Size == 8)
{
Marshal.WriteInt64(m.LParam, IntPtr.Size, window.Handle.ToInt64());
}
break;
}
}
}
base.WndProc(ref m);
}
}
public class FormWithLevel1 : BaseForm
{
public override int TopMostLevel
{
get { return 1; }
}
}
Итак, FormWithLevel1 всегда будет поверх любой BaseForm. Вы можете добавить любое количество уровней Z-порядка. Windows на том же уровне ведет себя как обычно, но всегда будет находиться под Windows с уровнем Current + 1 и над Windows с уровнем Current-1.
Вкратце, это, вероятно, веская причина, почему в программе Poor-Man's-Photoshop, также известной как GIMP (которую я использую постоянно, поэтому не хлопая), нет такого же типа окон. На самом деле, это одно из моих главных раздражений при использовании GIMP. То же самое для версии Photoshop для Mac.