Управление окном Z-Order Like Photoshop CS - PullRequest
2 голосов
/ 30 сентября 2008

Итак, у меня есть приложение, поведение окна которого я хотел бы вести себя как 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, которые я использую, переопределяются.

Прямо сейчас у меня есть базовая реализация quasy -work, которая делает окна инструментов самыми верхними, когда приложение активировано, но затем делает их не самыми верхними, когда это не так, но это очень странно (иногда это происходит поверх других Windows, как диспетчер задач, в то время как Photoshop CS не делает этого, поэтому я думаю, что Photoshop каким-то образом делает это по-другому), и кажется, что есть более интуитивный способ сделать это.

В любом случае, кто-нибудь знает, как это делает Photoshop CS, или лучше, чем использование topmost?

Ответы [ 7 ]

3 голосов
/ 16 октября 2008

Я не видел ничего примечательного в Photoshop CS, которое требовало бы чего-либо, близкого к этому уровню взлома, которое вместо этого нельзя сделать, просто указав правильные отношения окон владельца при создании окон. то есть любое окно, которое должно быть показано над каким-либо другим окном, указывает, что это окно является его владельцем при создании - если у вас есть несколько окон документов, каждое из них получает свой собственный набор дочерних окон, которые вы можете динамически отображать и скрывать по мере увеличения окна документа и теряет активацию.

2 голосов
/ 14 ноября 2011

Вы можете попробовать обработать событие 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.

1 голос
/ 02 октября 2008

Не будучи знакомым с Photoshop CS, довольно сложно точно знать, какой внешний вид и ощущения вы пытаетесь достичь.

Но я бы подумал, что если бы вы создали немодальное диалоговое окно как окно инструмента и вы убедились, что оно имеет стиль WS_POPUP , то результирующее окно инструмента не будет привязан к главному родительскому окну, а Windows будет автоматически управлять z-Order , гарантируя, что окно инструментов останется поверх родительского окна. .

А так как диалоговое окно инструмента немодально, оно не будет мешать главному окну.

0 голосов
/ 28 января 2009

Вы пытались сделать окна инструментов верхними, когда основное окно получает фокус, и не верхними, когда оно теряет фокус? Похоже, вы уже начали смотреть на такого рода решение ... но гораздо сложнее.

Как примечание, кажется, довольно хорошо задокументировано, что окна инструментов демонстрируют неожиданное поведение, когда дело доходит до z-упорядочения. Я не нашел в MSDN ничего, что могло бы подтвердить это, но, возможно, Windows управляет ими специально.

0 голосов
/ 29 декабря 2008

В ответ Крису и Эммануэлю проблема с использованием функции окна владельца заключается в том, что окно может принадлежать только одному другому окну, и вы не можете изменить того, кому принадлежит окно. Таким образом, если окна инструментов A и B всегда должны быть поверх окон документов C и D, тогда, когда окно документов C активно, я хочу, чтобы оно имело окна A и B, чтобы A и B всегда были поверх него. Но когда я активирую окно документа D, мне придется изменить владельца окон инструментов A и B на D, иначе они пойдут за окном D (так как они принадлежат окну C). Однако Windows не позволяет менять владельца окна, поэтому этот параметр недоступен.

На данный момент у меня это работает с самой лучшей функцией, но в лучшем случае это хак. Меня действительно утешает тот факт, что GIMP пытался эмулировать Photoshop с их версией 2.6, но даже их реализация иногда ведет себя странно, что заставляет меня полагать, что их реализация также была хакерской.

0 голосов
/ 16 октября 2008

Управление окном Z-Order Like Photoshop CS

Вы должны создать окно инструментов с изображением в качестве родителя, чтобы окна управляли zorder. Нет необходимости устанавливать WS_POPUP или WS_EX_TOOLWINDOW. Эти флаги управляют только рендерингом окна.

Вызовите CreateWindowEx с hwnd окна изображения в качестве родителя.

0 голосов
/ 30 сентября 2008

Я полагаю, что они, поскольку они не используют .NET, развернули свой собственный оконный код на протяжении многих лет своего существования, и теперь он, как и оригинальная OBIDOS Amazon, настолько удобен для их продукт, который в продаже (он же .NET поддержка MDI) просто не собирается приближаться.

Мне не нравится отвечать без реального ответа, но, вероятно, вам придется потратить много времени и усилий, чтобы получить что-то похожее , если Photoshop-like действительно ваша цель. Это стоит вашего времени? Просто помните, многие программисты в течение многих лет и версий объединились, чтобы заставить простое на вид поведение окон Photoshop работать правильно и чувствовать себя естественно для вас.

Похоже, вам уже нужно довольно глубоко вникать в функции и значения Win32 API, чтобы хотя бы взглянуть на "решение", и это должно быть вашим первым красным флагом. Возможно ли это в конце концов? Наверное. Но в зависимости от ваших потребностей, вашего времени и множества других факторов, которые вы можете решить, это может оказаться непрактичным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...