Подтвердить что ты не робот

Создание профессионального дизайнера (и поведения!)

Когда я начал программировать (около 10 лет назад), меня удивило три вещи:

  • Составители/интерпретаторы (тогда я знал их как "программы, которые заставляют мои программы работать", за которыми часто следует спецификатор "независимо от того, что они есть" )
  • Редакторы кода
  • Дизайнеры форм

В то время я принимал их как факты жизни. Я смог сделать свои собственные специальные программы, но "программы, которые делали мои программы", редакторы кода и редакторы форм были сделаны богами, и я не мог с ними связаться.

Затем я пошел в университет и прошел курс по формальной обработке языка. После изучения формальных грамматик, парсеров, абстрактных синтаксических деревьев и т.д.; все волшебство в отношении компиляторов, переводчиков и редакторов кода вскоре исчезло. Составители и интерпретаторы могут быть написаны разумно и просто, и единственной неприменимой вещью, которую может потребоваться редактор кода подсветки синтаксиса, были хаки Windows API.

Однако, по сей день редакторы формы остаются для меня загадкой. Либо мне не хватает технических знаний, необходимых для создания конструктора форм, либо у меня есть такие знания, но я не могу найти способ использовать его для реализации конструктора форм.

Используя Visual С++ и MFC, я хотел бы реализовать конструктор форм, вдохновленный лучшим дизайнером форм:

Visual Basic 6's form designer

В частности, я хотел бы подражать двум его особенностям, которые мне больше всего нравятся:

  • Обрабатываемая форма находится внутри контейнера. Таким образом, произвольно большая форма может быть спроектирована, не тратя слишком много экранной недвижимости, просто изменив размер контейнера на соответствующий размер.

  • Параметр "Выровнять по сетке" позволяет значительно упростить проектирование пользовательских интерфейсов расстраивает. На самом деле, я бы сказал, что создание профессиональных пользовательских интерфейсов с использованием конструктора форм Visual Basic на самом деле просто, весело и приятно. Даже для программистов с левым мозгом, таких как я.

Итак, у меня есть следующие вопросы:

  • Как создать конструктор форм, в котором разрабатываемая форма находится внутри контейнера? Является ли форма созданной фактическим окном, содержащимся внутри другого окна? Или это просто макет "вручную", написанный дизайнером формы?

  • У Windows API и/или MFC есть функции, классы, все, что облегчает создание "выбираемых" элементов (в окружении маленьких белых или синих квадратов при их выборе, изменяемых по размеру, когда они "схвачены" "одним из этих" ребер ")?

  • Как реализовать функциональность "Выровнять по сетке"?

4b9b3361

Ответ 1

Оба ответа здесь хороши, но не учитывают то, что я считаю действительно интересными битами (включая пару, о которой вы не спрашивали напрямую, но вы можете найти интерес в любом случае), так что вот мой 2c:

Рисование элементов управления

В идеале вы просто продолжаете и создаете обычный экземпляр элемента управления. Вы хотите что-то похожее на кнопку? Создайте настоящую кнопку. Трудность заключается в том, чтобы остановить его от поведения, как кнопка: вы хотите, чтобы клики активировали его для перемещения, а не на самом деле 'click'.

Один из способов решения этого вопроса - если предположить, что рассматриваемые элементы управления являются "основаны на HWND" (например, стандартный набор окон кнопки, редактирование, статический, список, древовидная структура и т.д.) - это создание элемента управления, а затем подкласс - т.е. переопределите wndproc с помощью SetWindowLongPtr (GWLP_WNDPROC,...), чтобы код дизайнера мог перехватить ввод мыши и клавиатуры и использовать его для инициирования перемещения, например, вместо того, чтобы вход мыши прошел до фактического кода кнопки, который вместо этого интерпретирует его как событие 'click'.

Альтернативным подходом к подклассу является установка невидимого окна над кнопкой для захвата ввода. Такая же идея перехвата ввода, просто различная реализация.

Вышеупомянутое относится к управляемым (VB.Net, С#) и неуправляемым (C/С++) элементам управления; они оба по существу представляют собой окна HWND; управляемые версии имеют только управляемый код обертки, передаваемый базовому неуправляемому элементу управления.

Старый (предварительно управляемый код) элемент управления ActiveX, используемый в pre-.Net VB, был совершенно другой игрой в мяч. Там довольно сложная взаимосвязь между контейнером ActiveX и элементами ActiveX внутри него, причем многие COM-интерфейсы обрабатывают такие вещи, как согласование свойств, событий, рисования и т.д. (Там есть набор интерфейсов, который позволяет элементу управления ActiveX получать ввод и рисовать сам, не имея собственного HWND.) Одно из преимуществ, которое вы получаете от этой сложности, однако, состоит в том, что элементы управления ActiveX имеют явный "режим разработки"; поэтому контроль знает, что нужно ответить соответствующим образом в этом случае и может сотрудничать со всей процедурой.

Сама форма...

Таким образом, в основном элементы управления - это просто регулярные элементы управления. Итак, вы ожидаете, что форма сама будет обычной формой? - Почти. Насколько я знаю, это просто другое окно на основе HWND, которое является дочерним элементом конструктора (поэтому оно обрезается и может быть прокручено внутри него); но я думаю, что разработчик здесь немного "обманывает", потому что обычно Windows только рисует фреймы - с кнопками заголовка и min/max, которые для реальных окон верхнего уровня. Я не знаю точно, какую именно технику они используют здесь, но некоторые параметры могут включать: рисовать вручную, чтобы имитировать внешний вид Windows; используя API-интерфейсы "темы" Windows, которые позволяют вам получать доступ к графическим элементам, используемым для бит и частей заголовков, и рисовать их везде, где вы хотите; или, возможно, менее вероятно, установив окно в виде окна "MDI Child" - это один случай исключения, когда окна будут рисовать рамку вокруг вложенного окна.

Перетаскиваемые ручки

Самый простой подход заключается в том, чтобы разработчик создал восемь маленьких квадратных всплывающих окон без заголовка, которые сидят над всеми другими элементами, - которые инициируют соответствующий код изменения размера при нажатии. Когда пользователь нажимает элемент управления на управление, просто переместите окна дескриптора перетаскивания в текущий активный элемент управления. (Обратите внимание, что во всех вышеперечисленных случаях сама Windows выясняет, кто был нажат, вам никогда не придется сравнивать координаты мыши с координатами прямоугольника элемента и самостоятельно их выполнять.)

Сохранение и восстановление

Для простых системных элементов управления Windows, которые используются неуправляемым C/С++, это относительно просто: существует хорошо известный текстовый формат файла -.rc - который описывает элементы управления и местоположения. Попросите дизайнера выплюнуть (и, вероятно, файл resource.h также), и все готово: любой проект C/С++ может собирать эти файлы и компилировать их. Управляемый код (С#, VB.Net) имеет несколько больше сложная схема, но она по-прежнему остается той же основной идеей: выпишите описание в стиле, который ожидают управляемые инструменты, и они с радостью скомпилируют его и будут использовать.

(Элементы ActiveX - вы уже догадались - целая "история". Нет стандартного формата, о котором я знаю, поэтому редактор формы и среда выполнения, которая потребляет данные, будут тесно связаны друг с другом - например, редактор формы из pre-.Net VB6 создает формы, которые могут использовать только VB. - Думаю, это было давно...)

Что касается воссоздания формы: если у вас есть .rc файл, он скомпилируется в ресурс диалога, Windows имеет встроенную поддержку для их воссоздания. Аналогично, библиотеки поддержки управляемого кода знают, как воссоздать форму из своего конкретного формата. Оба в основном анализируют описание и для каждого элемента, создают элементы соответствующих классов и задают соответствующий стиль, текст и другие свойства, как указано. Это не делает ничего, что вы не можете сделать сами, его код полезной помощи.

Обработка фокуса

Для коллекции HWND в любом контейнере, будь то в режиме "тест" или фактически запущенном в реальном приложении, и независимо от того, разрешаете ли вы Windows или Winforms создавать форму или создаете ли вы каждый HWND самостоятельно, вы можете добавить поддержка табуляции, вызвав IsDialogMessage в вашем цикле сообщений: см. MSDN странице примечаний. (Хотя WinForms может это сделать, я думаю на самом деле делает свою собственную обработку фокуса, так что он может иметь порядок вкладок независимо от визуального укладки Z-Order.)

Другие вещи для изучения...

Подружитесь с приложением Spy ++ (часть SDK, устанавливается с помощью Visual Studio). Если вы собираетесь делать что-либо с HWND, управляемым или неуправляемым, это действительно хорошая идея, чтобы знать, как использовать этот инструмент: вы можете указать его на любой пользовательский интерфейс в Windows и посмотреть, как он построен из дерева различные типы HWND. Направьте его на дизайнера VB и посмотрите, что на самом деле происходит для вас. (Щелкните значок "бинокль" на панели инструментов, затем перетащите перекрестие в интересующее вас окно.)

Также взгляните на файлы ресурсов, которые выкладывает дизайнер. Все, что вы можете настроить или переместить или изменить в дизайнере форм, соответствует некоторому элементу где-то в одном из этих файлов ресурсов. Сделайте копию из них, настройте некоторые настройки, а затем сравните файлы с двумя наборами и посмотрите, что изменилось. Попытайтесь изменить некоторые вещи в файлах вручную (я думаю, что они почти весь текст), перезагрузите и посмотрите, нашел ли дизайнер ваши изменения.

Другие примечания...

Большая часть из приведенных выше относится к Windows - в частности, тот факт, что, поскольку мы используем собственные строительные блоки Window - HWND - мы можем заставить Windows самостоятельно выполнять некоторые из трудных работ для нас: это дает нам возможности для повторного использования самих элементов управления во время разработки, поэтому нам не нужно рисовать макеты; чтобы перехватить входные данные на других элементах управления, чтобы мы могли сделать щелчок в движении или каким-либо другим другим действием, которое мы хотим, или выяснить, какой элемент управления щелкнут, без необходимости выполнять математику местоположения. Если это был дизайнер для некоторых других интерфейсов пользовательского интерфейса - скажем, Flash - который не использует HWND внутри, скорее всего, вместо этого использует , что собственные внутренние средства для выполнения аналогичной работы.

Кроме того, это намного проще, если вы ограничите количество элементов управления в палитре небольшим конечным множеством, по крайней мере, вначале. Если вы хотите, чтобы какой-либо элемент управления вообще был перетащен - например. сторонний, или тот, который вы использовали в другом проекте; вам обычно требуется какой-то способ, чтобы этот элемент управления был "зарегистрирован", чтобы дизайнер знал, что он доступен в первую очередь. И вам также может понадобиться какой-то способ узнать, какой значок он использует на панели инструментов, каково его имя, какие свойства он поддерживает и т.д.

Получайте удовольствие от изучения!

Ответ 2

Вы реализуете конструктор форм почти как обычный графический интерфейс. У вас есть вещи, которые вы можете перетащить (ваши виджеты), у вас есть вещи, которые вы можете щелкнуть (ваши кнопки), и у вас есть вещи, которые вы можете выбрать (ваши размещенные виджеты) и это действительно об этом.


Q: Теперь, как вы отображаете окно в графическом интерфейсе?
A: Вы рисуете это, просто так.

Q: И как вы сохраняете материал внутри этого окна?
A: Вы проверяете границы "родительского" объекта. Вы могли бы почти сказать, что дизайнер форм похож на маленькую игру, и у вас есть график сцены, содержащий все ваши виджеты, связанные родительскими отношениями.

Q: Затем, как вы выбираете материал в графическом интерфейсе?
A: Проверяйте текущую позицию мыши на границах всех (близких) виджетов (здесь используется только график сцены, например квадрант).

В: Как вы выравниваете виджеты на сетке?
A: Для выравнивания сетки давайте попробуем пример: скажите, что ваше реальное разрешение 100px по оси x, но вы хотите, чтобы ваша сетка имела только разрешение 10px по x. Теперь скажите, что вы перемещаете свой виджет на 28px в реальном разрешении. Чтобы получить разрешение сетки, вы просто делите на 10, получите 2.8, округлите это и, наконец, переместите виджет 3 плитки на x. Здесь закругление - это ключ. только если движение сетки >= ?.5, вы привязываетесь к следующей плитке. В противном случае вы просто останетесь на прежнем.


Надеюсь, это может дать вам общий намек на то, как запустить конструктор форм. Повеселись.:)
(PS: Не знаете о каких-либо конкретных функциях/классах WinAPI/MFC, чтобы помочь вам, извините.)

Ответ 3

Просто добавьте точку или два к тому, что уже сказал @Xeo:

Прежде всего, нет, вы не всегда рисуете все содержимое самостоятельно. Во время нормальной фазы проектирования вы просто рисуете что-то похожее на элемент управления, но (по крайней мере, IIRC) он также позволяет вам "запускать" форму в тестовом режиме (конечно, конструктор диалогового окна VС++ делает, и хотя VB более примитивен, Я думаю, что у него действительно была и эта особенность). Режим тестирования состоял в том, что вы можете "запустить" форму до того, как вы (обязательно) приложите к ней какой-либо код - даже если нажатие кнопки (например) ничего не делает в окружающей программе, сам контроль работает как обычно - кнопка нажимает обычно, элемент управления редактирования позволяет редактировать и т.д.

Это делается путем фактического создания элемента управления, указывая правильное положение, размер и свойства. Элементы ActiveX довольно немного поддерживают это, и предыдущие "пользовательские элементы управления Windows" также сделали, хотя и со значительно меньшей степенью сложности. С точки зрения элемента управления он работает примерно так же, как обычно, получает вход, отправляет уведомление своему родительскому объекту и т.д. Единственное, что изменилось, это то, что родитель больше игнорирует большинство уведомлений, которые он получает, но элемент управления не работает На самом деле это знаю.

Есть два основных способа сделать это. Один из них - создать набор элементов управления самостоятельно, вместе с их позициями, размерами и т.д., И использовать CreateWindow (или CreateWindowEx и т.д.), Чтобы создать окно соответствующего класса. Несмотря на то, что он относительно прост в обращении, у него есть недостаток, заключающийся в том, что он оставляет вам всю обработку вкладок.

Другая возможность заключается в создании структуры DLGTEMPLATE для хранения данных о диалоговом окне и некоторых DLGITEMTEMPLATES для отдельных элементов управления и, наконец, использования CreateDialogIndirect для создания диалогового окна с этими спецификациями, управления. Это утомительно, но оно работает, и когда вы закончите, он автоматически выполняет автоматическую привязку между элементами управления (и работает так же, как и любой другой диалог, так как тот же код Windows создает его в любом случае).

Во-вторых, поскольку вы отметили этот С++, вы можете взглянуть на code на CodeProject, который на самом деле реализует диалогового редактора. Хотя это не так сложно, как некоторые из коммерческих, это достаточно полный редактор форм/диалогов, в котором содержится большая часть того, о чем вы просили.