Мужики, есть старая, но по-прежнему интересная идея написать "свой GUI" для Винды. Причём это всё на D и для D.
Хочу изложить примерную схему для оценки (может и идею подкинете, как проще).
Основная идея — взять от Венды только примитивный элемент Window, а сами контролы полностью рисовать и обрабатывать самим (т.е. мы НЕ пользуемся стандартными Win32 BUTTON, COMBOBOX и т.п.)
Как и положено ООП либе, у нас будет базовый класс Widget, в котором будет находиться вся служебная фигня, нужная венде.
В Widget будет так же лежать своя (перегружабельная) WindowProc для обработки виндовых сообщений.
Как и положено, мы будем RegisterClass для всех наших виджетов и затем их CreateWindow.
И вот тут возникает засада, известная всем кульхацкерам: для RegisterClass нужен адрес обработчика сообщений (WindowProc), который в нашей либе... инстанс метод!
Шахматисты из Borland (да и в MFC тот же хак) решили эту задачу каким-то хитрым ассемблером, чтобы винда сама вызывала нужный метод нужного класса через манипуляцию стеком. Увы, в D я не знаю кишок и не смогу нахакать такой вызов.
Но почесать левое ухо правой рукой всё же можно: завести одну глобальную функцию WindowProc (вне всех классов) и зарегать её для всех виджетов. А уже ей параметром придёт хэндл hWnd любого нашего окна. А далее из глобального же Dictionary мы по hWnd достаём объект Widget, у которого и вызовем инстансную WindowProc.
Кратко: RegisterClass("любой виджет", ГлобальнаяWindowProc). ГлобальнаяWindowProc принимает ВСЕ сообщения приложения, а далее диспетчеризует по объектам.
Тут сложность в том, что придётся внимательно следить, чтобы этот Dictionary всегда был актуален — вовремя добавлять/убирать оттуда хэндлы, да ещё всё это в многопоточной среде.
А ещё маленький подвопрос: после GetMessage обязательно делать DispatchMessage или я сам могу раскидать структуру MSG по нужным объектам?
В общем, идея не новая, но не хочется наступать на пройденные грабли — может кто подкинет совет.
Здравствуйте, Kolesiki, Вы писали:
K>Мужики, есть старая, но по-прежнему интересная идея написать "свой GUI" для Винды. Причём это всё на D и для D.
Зачем?
K>Хочу изложить примерную схему для оценки (может и идею подкинете, как проще).
K>Основная идея — взять от Венды только примитивный элемент Window, а сами контролы полностью рисовать и обрабатывать самим (т.е. мы НЕ пользуемся стандартными Win32 BUTTON, COMBOBOX и т.п.)
Сразу минус — не нативно будет выглядеть.
K>Как и положено ООП либе, у нас будет базовый класс Widget, в котором будет находиться вся служебная фигня, нужная венде.
Перепиши Qt на D и успокойся
K>В Widget будет так же лежать своя (перегружабельная) WindowProc для обработки виндовых сообщений. K>Как и положено, мы будем RegisterClass для всех наших виджетов и затем их CreateWindow.
K>И вот тут возникает засада, известная всем кульхацкерам: для RegisterClass нужен адрес обработчика сообщений (WindowProc), который в нашей либе... инстанс метод! K>Шахматисты из Borland (да и в MFC тот же хак) решили эту задачу каким-то хитрым ассемблером, чтобы винда сама вызывала нужный метод нужного класса через манипуляцию стеком. Увы, в D я не знаю кишок и не смогу нахакать такой вызов.
Как MFC/WTL и Borland решает эту задачу — не помню. В MFC вроде есть словарь/map.
K>Но почесать левое ухо правой рукой всё же можно: завести одну глобальную функцию WindowProc (вне всех классов) и зарегать её для всех виджетов. А уже ей параметром придёт хэндл hWnd любого нашего окна. А далее из глобального же Dictionary мы по hWnd достаём объект Widget, у которого и вызовем инстансную WindowProc. K>Кратко: RegisterClass("любой виджет", ГлобальнаяWindowProc). ГлобальнаяWindowProc принимает ВСЕ сообщения приложения, а далее диспетчеризует по объектам. K>Тут сложность в том, что придётся внимательно следить, чтобы этот Dictionary всегда был актуален — вовремя добавлять/убирать оттуда хэндлы, да ещё всё это в многопоточной среде.
Я в свое время в своей либе делал просто — CreateWindow получает пользовательский аргумент, который передает в WindowProc, вот там я и передавал указатель на объект. Глобальная static WindowProc просто кастила к базовуму Window и вызывала виртуальную WindowProc объекта. А если нужно пользовательские данные передавать — так в объекте пожалуйста.
K>А ещё маленький подвопрос: после GetMessage обязательно делать DispatchMessage или я сам могу раскидать структуру MSG по нужным объектам?
Можешь попробовать, но устанешь повторять логику DispatchMessage, ну или твои окна будут совсем неадекватно себя вести.
K>В общем, идея не новая, но не хочется наступать на пройденные грабли — может кто подкинет совет.
Хочешь совет? Ляг, поспи, может пройдет.
K>PS K>Никакие Qt/GTk не хочу. DLangUI — тем более.
Тебе сколько лет? Если 20 — то да, можно выкинуть несколько лет на это, опыта наберешься. Если за 30 уже — лучше не трать время, а заведи семью
Здравствуйте, Kolesiki, Вы писали:
K>Мужики, есть старая, но по-прежнему интересная идея написать "свой GUI" для Винды. Причём это всё на D и для D. K>Хочу изложить примерную схему для оценки (может и идею подкинете, как проще).
K>Основная идея — взять от Венды только примитивный элемент Window, а сами контролы полностью рисовать и обрабатывать самим (т.е. мы НЕ пользуемся стандартными Win32 BUTTON, COMBOBOX и т.п.) K>Как и положено ООП либе, у нас будет базовый класс Widget, в котором будет находиться вся служебная фигня, нужная венде. K>В Widget будет так же лежать своя (перегружабельная) WindowProc для обработки виндовых сообщений. K>Как и положено, мы будем RegisterClass для всех наших виджетов и затем их CreateWindow.
K>И вот тут возникает засада, известная всем кульхацкерам: для RegisterClass нужен адрес обработчика сообщений (WindowProc), который в нашей либе... инстанс метод! K>Шахматисты из Borland (да и в MFC тот же хак) решили эту задачу каким-то хитрым ассемблером, чтобы винда сама вызывала нужный метод нужного класса через манипуляцию стеком. Увы, в D я не знаю кишок и не смогу нахакать такой вызов.
K>Но почесать левое ухо правой рукой всё же можно: завести одну глобальную функцию WindowProc (вне всех классов) и зарегать её для всех виджетов. А уже ей параметром придёт хэндл hWnd любого нашего окна. А далее из глобального же Dictionary мы по hWnd достаём объект Widget, у которого и вызовем инстансную WindowProc. K>Кратко: RegisterClass("любой виджет", ГлобальнаяWindowProc). ГлобальнаяWindowProc принимает ВСЕ сообщения приложения, а далее диспетчеризует по объектам. K>Тут сложность в том, что придётся внимательно следить, чтобы этот Dictionary всегда был актуален — вовремя добавлять/убирать оттуда хэндлы, да ещё всё это в многопоточной среде.
K>А ещё маленький подвопрос: после GetMessage обязательно делать DispatchMessage или я сам могу раскидать структуру MSG по нужным объектам?
K>В общем, идея не новая, но не хочется наступать на пройденные грабли — может кто подкинет совет.
Подходов для привязки объекта к хэндлу окна несколько:
1) Использовать глобальный map <HWND, object*>. Вполне адекватный способ. MFC использует именно его.
2) Формирование ассемблерной инструкции, как делает ATL. Не рекомендуется, т.к. не переносимо и, вроде, есть проблемы с DEP.
3) GetProp — именованные свойства окна. Работает, но медленно.
4) Set/GetWindowLong c GWL_USERDATA.
Вам, по видимости, лучше всего подойдет 4-ый. Он быстрый, имеет сложность O(1).
Ограничения состоят в том, что при субклассинге чужих окон это поле может быть уже задействовано. Но, т.к. Вы собираетесь писать свои контролы, то это поле полностью в Вашем распоряжении.
Здравствуйте, Kolesiki, Вы писали:
K>есть старая, но по-прежнему интересная идея написать "свой GUI" для Винды.
Непродуктивно, тот же Qt сразу позволяет использовать готовое в нескольких семействах операционок, это не говоря уже про то, что винда мастдай. В наше время имело бы смысл писать кроссплатформенный интерфейс для 3D, причём не плоский, а именно 3D, так как 2D от того же Qt и так вставляется внутрь в виде свободных плоскостей в пространстве реагирующих на события. Что касается винды, то с учётом их проекта "Windows 10" лавочку для программистов могут вообще прикрыть. Потом денег на сертификаты от микрософта не напасёшься.
Здравствуйте, Marty, Вы писали:
K>>Мужики, есть старая, но по-прежнему интересная идея написать "свой GUI" для Винды. Причём это всё на D и для D.
M>Зачем?
На этот вопрос для себя я уже ответил. Зачем отвечать на него для вас?
K>>Основная идея — взять от Венды только примитивный элемент Window M>Сразу минус — не нативно будет выглядеть.
K>>Как и положено ООП либе, у нас будет базовый класс Widget, в котором будет находиться вся служебная фигня, нужная венде. M>Перепиши Qt на D и успокойся
Невнимательно читаете — в постскриптуме всё сказано.
M>Я в свое время в своей либе делал просто — CreateWindow получает пользовательский аргумент, который передает в WindowProc, вот там я и передавал указатель на объект.
Тоже вариант, причём даже лучший! Спасибо.
K>>А ещё маленький подвопрос: после GetMessage обязательно делать DispatchMessage или я сам могу раскидать структуру MSG по нужным объектам? M>Можешь попробовать, но устанешь повторять логику DispatchMessage, ну или твои окна будут совсем неадекватно себя вести.
Что именно в DispatchMessage делается, помимо раскидывания полей структуры в отдельные аргументы WindowProc? (не забываем — мы сами пишем библиотеку контролов)
K>>В общем, идея не новая, но не хочется наступать на пройденные грабли — может кто подкинет совет. M>Хочешь совет? Ляг, поспи, может пройдет.
За советами подобного рода я б пришёл на "TrolliRuneta.ru".
M>Тебе сколько лет?
Забыл спросить "скакова раёна". И кепку сними, когда со старшими разговариваешь.
Здравствуйте, cr8, Вы писали:
cr8>1) Использовать глобальный map <HWND, object*>. Вполне адекватный способ. MFC использует именно его. cr8>4) Set/GetWindowLong c GWL_USERDATA.
cr8>Вам, по видимости, лучше всего подойдет 4-ый. Он быстрый, имеет сложность O(1).
Вот! Что-то у меня перемешалось в голове — думаю, ведь ещё хэндлы хранить надо... да нафик не надо — сами придут в свойствах окна! Тут надо потестить, ведь получить USERDATA из хэндла — это ещё один вызов.
Спасибо за развёрнутый ответ без персональных наездов!
Здравствуйте, wildwind, Вы писали:
K>>Никакие Qt/GTk не хочу. DLangUI — тем более.
W>Извиняюсь за оффтопик, но что не так с DLangUI? А то я хотел его освоить, может не стоит время тратить?
Никакого оффтопика, вы как раз в тему! DLangUI смотрел мельком, что-то поковырял и понял, что такой футбол нам не нужен: Контролы отрисовываются заранее подготовленными глифами — для "обычного" DPI и HiRes. Соотв. ни о каких "нативных темах" речи не идёт, о гибкости и scalability тоже. Нормальное желание "закастомить тему" приведёт к полной перерисовке всех контролов, включая их состояния (disabled, checked и т.п.) — это вместо того, чтобы просто скомандовать "у всех контролов теперь рисуй синий бордюр".
Иерархия наследования. Выпишите основные контролы (особ. все виды Button) и посмотрите на этот саксаул — подобный бардак даже трогать не хочу, совершенно непрофессионально.
Оч много зависимостей от сторонних библиотек, ввиду того, что автор пишет очередной "межплатформенный" всемогутер. Включая отрисовку через SDL/OpenGL. Я не верю в межплатформенные павлиноуткаёжи, поэтому это тоже для меня значащий минус.
Много "детских болезней" из-за молодости проекта и не исключаю, слабоватой квалификации автора. (см. иерархию)
Иногда проект даже не собирается(!). Понимаю, тяжело тащить одну телегу в три стороны, но раз берёшься за такие амбициозные цели, будь готов каждый коммит обсасывать во всех возможных позах и платформах.
Концепция. Она всё такая же, как и 20 лет назад — "контрол-наследник-добавление рюшечек". Никакого тебе декларативного UI (есть какие-то зачатки инициализации с самописным форматом, но боюсь, этим всё и ограничивается), стилей, композиционных контролов и т.п. — всё пишется как в 90-ые. Вот в данном случае действительно не вижу смысла пахать "ещё один ГУЙ" — проще взять DWT/MinWin/DGUI и дизайнить с тем же успехом. Не говоря о байндингах к заскорузлым, но зрелым экскрементам типа GTk и Qt.
Сами контролы — тоже так себе, "стандартный набор школьника", тот же DFL/DGUI содержит их все. А ещё напрягают фразы "Android inspired" и "it's a port of GUI library ... of Cool Reader app... on C++". Мне уже хватит сипиписной вермишели, хочу писать максимально используя возможности Ди. И уж Ведроид — последнее, что я б взял за "пример"!
Это моё субъективное мнение, возможно вам и понравится эта либа. Но обязательно сначала попробуйте всё, что уже создано, чтобы почувстсовать всю тоску и однообразие мира ГУЁВ
Меня лично вдохновляет WPF, у которого надо лишь обуздать декларативность до приемлемого уровня, упростить XAML и превратить создание новых контролов из высирания ежей в приятное конструирование ЛЕГО.
Здравствуйте, Kolesiki, Вы писали:
K>DLangUI смотрел мельком, что-то поковырял и понял, что такой футбол нам не нужен: K>...
Я не понял суть претензий по существу, кроме пунктов 3 и отчасти 6. Хорошо понял, что библиотека тебе не понравилась, но это можно было и двумя словами сказать.
В любом случае, думаешь затевать свой велосипед с нуля лучше, чем помочь автору довести проект до ума и попутно реализовать то, чего тебе не хватает? Ту же декларативность.
Здравствуйте, wildwind, Вы писали:
W>Я не понял суть претензий по существу, кроме пунктов 3 и отчасти 6. Хорошо понял, что библиотека тебе не понравилась, но это можно было и двумя словами сказать.
Если не понял — это этажом выше, я высказал соображения, по которым я считаю это поделие недостойным будущего. И раз ты спросил "что не так с DLangUI?", я объяснил ЧТО не так. "В двух словах" это не расскажешь.
W>В любом случае, думаешь затевать свой велосипед с нуля лучше, чем помочь автору довести проект до ума и попутно реализовать то, чего тебе не хватает? Ту же декларативность.
Я так понимаю, все 7 пунктов ты пропустил мимо ушей, иначе бы не стал писать эту фигню.
Не надо думать, что знаешь всё на свете — если что-то кажется на первый взгляд велосипедом, то присмотревшись можно увидеть интересные вещи.
Я в ИТ вращаюсь уже много лет, чтобы правильно оценивать проекты. Особенно если в них есть перспектива. Ковыряться в изоленте и костылях, чтобы потом всё выкинуть и переписать заново — смысл?? Ещё раз перечитай пункт 2 — он говорит о многом (но не для всех).
Здравствуйте, Kolesiki, Вы писали:
K>>>Мужики, есть старая, но по-прежнему интересная идея написать "свой GUI" для Винды. Причём это всё на D и для D.
M>>Зачем?
K>На этот вопрос для себя я уже ответил. Зачем отвечать на него для вас?
Хамишь?
K>>>Основная идея — взять от Венды только примитивный элемент Window M>>Сразу минус — не нативно будет выглядеть.
K>Абсолютно никакой связи!
Ну, удачи.
K>>>Как и положено ООП либе, у нас будет базовый класс Widget, в котором будет находиться вся служебная фигня, нужная венде. M>>Перепиши Qt на D и успокойся
K>Невнимательно читаете — в постскриптуме всё сказано.
Я последовательно читаю.
Как "Перепиши Qt на D" противоречит "Никакие Qt/GTk не хочу. DLangUI — тем более."? Я не предлагал тебе делать биндинги к Qt на D. Если бы ты умел читать, то ты понял бы, что предлагается хорошенько изучить Qt и реализовать аналогичное на D. Вдумчивое изучение потрохов Qt поможет в написании windowless GUI библиотеки. А изучение MFC/WTL — поможет в реализации под винду. Еще можно wxWidgets изучить.
И тебе, похоже, эти знания пригодились бы, судя по вопросам.
K>>>А ещё маленький подвопрос: после GetMessage обязательно делать DispatchMessage или я сам могу раскидать структуру MSG по нужным объектам? M>>Можешь попробовать, но устанешь повторять логику DispatchMessage, ну или твои окна будут совсем неадекватно себя вести.
K>Что именно в DispatchMessage делается, помимо раскидывания полей структуры в отдельные аргументы WindowProc? (не забываем — мы сами пишем библиотеку контролов)
Ну да, ничего и не делается. Её можно вообще макросом оформить ::
В MFC они вроде свою реализацию сделали. Можешь глянуть.
K>>>В общем, идея не новая, но не хочется наступать на пройденные грабли — может кто подкинет совет. M>>Хочешь совет? Ляг, поспи, может пройдет.
K>За советами подобного рода я б пришёл на "TrolliRuneta.ru".
Это самый полезный в этой ветке совет.
M>>Тебе сколько лет?
K>Забыл спросить "скакова раёна". И кепку сними, когда со старшими разговариваешь.
Ну да, точно хамишь. Ты и раньше вежливостью не отличался, насколько я помню. Вообщем, я понял, не стоит отвечать на твои вопросы.
Здравствуйте, VTT, Вы писали:
VTT>Надо же, а вроде еще недавно D был молодым, перспективным языком, "убийцей с++". VTT>Сейчас, надо полагать, эту нишу занял rust.
Жду, когда он убьет C++. А пока потихоньку изучаю чего там новенького нагенерили в стандарт C++ за последние годы.
Здравствуйте, Kolesiki, Вы писали:
cr8>>1) Использовать глобальный map <HWND, object*>. Вполне адекватный способ. MFC использует именно его. cr8>>4) Set/GetWindowLong c GWL_USERDATA.
cr8>>Вам, по видимости, лучше всего подойдет 4-ый. Он быстрый, имеет сложность O(1).
K>Вот! Что-то у меня перемешалось в голове — думаю, ведь ещё хэндлы хранить надо... да нафик не надо — сами придут в свойствах окна! Тут надо потестить, ведь получить USERDATA из хэндла — это ещё один вызов.
№4 тебе не подойдет. Ибо garbage collector твои USERDATA не увидит. Только №1 как самый разумный способ.
Здравствуйте, c-smile, Вы писали:
CS>№4 тебе не подойдет. Ибо garbage collector твои USERDATA не увидит. Только №1 как самый разумный способ.
Он самый разумный, но вроде медленный? При наличии дохрена окон, оно будет в хендлере на каждый мессадж долго гонять эту мапу. Или нет? Я не в курсе, насколько быстро мапы работают
Здравствуйте, Kolesiki, Вы писали:
K>Основная идея — взять от Венды только примитивный элемент Window, а сами контролы полностью рисовать и обрабатывать самим (т.е. мы НЕ пользуемся стандартными Win32 BUTTON, COMBOBOX и т.п.)
Как-то странно. В чём выгода тут — непонятно. Ну будут те же ядерные объекты, те же окна, но нарисованные тобой. Если тебе мало интерактива и свойств текущего набора контролов — сабклассинг тебе поможет (GWL_WNDPROC/GWL_USERDATA с друзьями). Даже у микрософта в стандартном таск-манагере, графики всякие загрузки/памяти, посмотри, это всё засабклашенные обычные кнопки.
Я бы не брал за основу окно, я бы просто сделал абстрактный layer, в который можно рисовать, и который как-то взаимодействует и реагирует с вводом/выводом. Потом бы реализовал свой класс окон. А потом уже этот layer прикрутил к живому окну отдельно. Ну, собственно, я года три назад так и сделал, когда играми на GDI занимался.
Здравствуйте, CEMb, Вы писали:
CEM>Здравствуйте, c-smile, Вы писали:
CS>>№4 тебе не подойдет. Ибо garbage collector твои USERDATA не увидит. Только №1 как самый разумный способ. CEM>Он самый разумный, но вроде медленный? При наличии дохрена окон, оно будет в хендлере на каждый мессадж долго гонять эту мапу. Или нет? Я не в курсе, насколько быстро мапы работают
hashmap -> element это O(1) операция. Какие проблемы-то?
И потом к USERDATA имеют доступ все. Компоненты чужие уже не получится использовать.
Здравствуйте, Kolesiki, Вы писали:
K>Не надо думать, что знаешь всё на свете — если что-то кажется на первый взгляд велосипедом, то присмотревшись можно увидеть интересные вещи.
И какие интересные вещи ты хочешь реализовать?
K>Я в ИТ вращаюсь уже много лет, чтобы правильно оценивать проекты.
Что-то непохоже. Да и уровень вопросов намекает, если честно.
K>Особенно если в них есть перспектива.
У тебя нет перспективы даже попасть в этот список.
K>Ковыряться в изоленте и костылях, чтобы потом всё выкинуть и переписать заново — смысл??
Поэтому надо своей изолентой смотать свои костыли, да.
Правильно тебе говорят, не трать на это время, но ты что-то на хамство скатываешься
Здравствуйте, c-smile, Вы писали:
CS>>>№4 тебе не подойдет. Ибо garbage collector твои USERDATA не увидит. Только №1 как самый разумный способ. CEM>>Он самый разумный, но вроде медленный? При наличии дохрена окон, оно будет в хендлере на каждый мессадж долго гонять эту мапу. Или нет? Я не в курсе, насколько быстро мапы работают
CS>hashmap -> element это O(1) операция. Какие проблемы-то? CS>И потом к USERDATA имеют доступ все. Компоненты чужие уже не получится использовать.
Да, но там всё равно много вычислений по сравнению с тем, чтобы взять данные по смещению(userdata). С учётом того, что это всё надо обрабатывать в реалтайме, получение элемента из мапы по скорости становится критичным. А так я тоже за реализацию на основе мапы.