Перейти к содержанию

GDI - Слова разного цвета в одном тексте


Рекомендуемые сообщения

  В 02.08.2022 в 12:38, youneuoy сказал:

Это не мой код🙂Я его взял у какого-то пользователя с форума когда программированию учился только и по этому шаблону наделал патчей в память.

Показать  

Понятно 🙂.

  В 02.08.2022 в 14:00, Xipho сказал:

Это на твоё усмотрение ) 

Показать  

Мы же вместе собрались изобретать велосипед. Пусть простой, но зато свой.

Вчера я даже не смог скачать QT Creator. Хотел посмотреть как там устроены сигналы, слоты.

VPN не стал организовывать, из роликов и документации я примерно понял что там и к чему. Мне кажется WGW в этом плане попроще будет.

 

Я заметил что в QT в параметре метода события (например кнопка нажата), передается определенный для этого типа события объект. И чтобы получить какие-либо его характеристики, нужно вызвать его методы.

//QPushButton Class
virtual void 	keyPressEvent(QKeyEvent *e) override

И некоторые методы QKeyEvent

  Показать контент

 

А в WGW немного по другому. Вместо QKeyEvent объекта передается тоже определенный для этого события объект , но он не имеет методов. Он имеет public поля с уже подсчитанными/полученными значениями (из wParam, lparam). Такой подход в сравнении с QT удобнее, как мне кажется. Но есть один минус, - даже если пользователю не нужны эти данные в методе события, они все равно подсчитываются/получаются. То есть холостая работа. Хотя опять же, она такая незначительная, что я подумал так и оставить, а не писать методы для их получения.

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

Ссылка на комментарий
Поделиться на другие сайты

  В 02.08.2022 в 15:42, Antonshka сказал:

Он имеет public поля с уже подсчитанными/полученными значениями (из wParam, lparam)

Показать  

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

Ссылка на комментарий
Поделиться на другие сайты

  В 02.08.2022 в 17:24, Xipho сказал:

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

Показать  

Графические артефакты? Я немного не понял тебя.

Если к примеру взять событие WM_PAINT.

Вот обычная функция для события рисования

  Показать контент

 

Это класс передаваемого объекта в параметре (указателя на него, сам он находится в классе окна, постоянно). Как видно из класса, только поля объявлены как public. Пользователь не может создать или обратится к этому объекту вне функции события. Создать его может только класс окна/контрола.

  Показать контент

 

А это то как заполняются поля при каждом сообщении WM_PAINT

  Показать контент

 

Поля объекта получают копии значений. Оригиналы не затрагиваются.

Если пользователь по ошибке запишет в поле compDC что-то свое, то да, код далее этого момента будет глючить. Но так подумать, это можно отнести вообще ко всем переменным.

 

Например

  Показать контент

 

В WGW этот вызов

HDC hDC = onPaintEvent->getMyCompatibleDC();

выполняется за пользователя, автоматически и заранее.

Все ошибки какие пользователь может совершить с переменными в данном случае в WGW, равны тем что в QT.

 

Поэтому я не понял тебя.

Ссылка на комментарий
Поделиться на другие сайты

  В 02.08.2022 в 18:09, Antonshka сказал:

Если пользователь по ошибке запишет в поле compDC что-то свое, то да, код далее этого момента будет глючить. Но так подумать, это можно отнести вообще ко всем переменным.

Показать  

Твоя обязанность как разработчика библиотеки - максимально обезопасить пользователя от подобных ошибок. Пользователь НЕ должен иметь доступа на запись полей внутри класса. Да, пользователь может сделать переменную и ее переназначить - и вот это уже будет на совести пользователя. А вот открытые к изменению публичные поля, это еще одна точка отказа, за которую ответственность несешь ты, как разработчик библиотеки. В идеальном мире ни одно поле не должно быть публичным, а сеттер поля должен делать валидацию поступающих на вход значений. У того же HDC в OnPaintEvent можно сеттер вообще сделать приватным, как и само поле, и тогда снаружи его изменить будет нельзя. Не устаю говорить всегда о том, что пользователю библиотеки ни в коем случае нельзя доверять. Потому нужно стараться максимально закрыть от пользователя детали реализации, и открыть ему только те части, в которых не сможет накосячить. Ну или накосячит по минимуму. В данном конкретном случае я сходу не подскажу, как это можно сделать, надо посидеть, подумать.

Ссылка на комментарий
Поделиться на другие сайты

  В 03.08.2022 в 04:24, Xipho сказал:

Твоя обязанность как разработчика библиотеки - максимально обезопасить пользователя от подобных ошибок. Пользователь НЕ должен иметь доступа на запись полей внутри класса. Да, пользователь может сделать переменную и ее переназначить - и вот это уже будет на совести пользователя. А вот открытые к изменению публичные поля, это еще одна точка отказа, за которую ответственность несешь ты, как разработчик библиотеки. В идеальном мире ни одно поле не должно быть публичным, а сеттер поля должен делать валидацию поступающих на вход значений. У того же HDC в OnPaintEvent можно сеттер вообще сделать приватным, как и само поле, и тогда снаружи его изменить будет нельзя. Не устаю говорить всегда о том, что пользователю библиотеки ни в коем случае нельзя доверять. Потому нужно стараться максимально закрыть от пользователя детали реализации, и открыть ему только те части, в которых не сможет накосячить. Ну или накосячит по минимуму. В данном конкретном случае я сходу не подскажу, как это можно сделать, надо посидеть, подумать.

Показать  

Я понял тебя. Ты говоришь вообще в целом. С этим я согласен, это я держу во внимании.

Сейчас в библиотеке все так и есть. Все закрыто, ничего лишнего пользователь не то что изменить, даже и создать не может. Например никакой объект класса свойства контрола.

Все что ему открыто, все безопасно.

 

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

LRESULT OnPaintFunctionName(WGW::OnPaintEvent* onPaintEvent) {
  	//Как в QT, получаем значение методом.
	HDC compDC = onPaintEvent->getMyCompatibleDC(); 
	FillRect(compDC, ...)

    //Как в WGW
    FillRect(onPaintEvent->compDС, ...)
}

 

Ссылка на комментарий
Поделиться на другие сайты

  В 03.08.2022 в 04:24, Xipho сказал:

Твоя обязанность как разработчика библиотеки - максимально обезопасить пользователя от подобных ошибок. Пользователь НЕ должен иметь доступа на запись полей внутри класса.

Показать  

А у тебя есть опыт работы с QT? В QT, как я понял, можно расширять классы контролов. Наследуясь от них.

В WGW же, создание интерфейса осуществляется как бы процедурно, не через наследование.

  Показать контент

 

В QT события как я понял обрабатываются в методах класса, а не в простых функция как в WGW.

И еще я кажется видел что в QT можно создать контрол через оператор "new". Не через наследование. То есть как я понял просто используя то что QT дает стандартно .

 

- в QT есть расширение классов

- в QT события обрабатываются в методах класса, а не в простых функцияч, как в WGW.

 

Интересно, WGW от этого сильно проигрывает QT?

 

Ну хорошо, наследовал в QT класс QPushButton, расширин функционал, добавил что новый класс при нажатии на кнопку пиликает. И теперь все кнопки созданные этим классом будут пиликать.

А в WGW, вместо этого, можно создать файл PilicedButtons.h, там определить функцию на событие кнопка нажата, а в ней уже делать пиликанье. Затем все простые кнопки направить при нажатии на эту функцию. Получаем что и в QT.

Ссылка на комментарий
Поделиться на другие сайты

  В 05.08.2022 в 05:59, Antonshka сказал:

А у тебя есть опыт работы с QT?

Показать  

Есть, но поверхностно - делал UI управления настройками устройства для депарафинизации нефтяных скважин. Там не было необходимости дорабатывать существующие контролы.

 

  В 05.08.2022 в 05:59, Antonshka сказал:

В QT события как я понял обрабатываются в методах класса, а не в простых функция как в WGW.

И еще я кажется видел что в QT можно создать контрол через оператор "new". Не через наследование. То есть как я понял просто используя то что QT дает стандартно .

 

Показать  

Да, всё так

 

  В 05.08.2022 в 05:59, Antonshka сказал:

Ну хорошо, наследовал в QT класс QPushButton, расширин функционал, добавил что новый класс при нажатии на кнопку пиликает. И теперь все кнопки созданные этим классом будут пиликать.

А в WGW, вместо этого, можно создать файл PilicedButtons.h, там определить функцию на событие кнопка нажата, а в ней уже делать пиликанье. Затем все простые кнопки направить при нажатии на эту функцию. Получаем что и в QT.

Показать  

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

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

Ссылка на комментарий
Поделиться на другие сайты

  В 05.08.2022 в 06:08, Xipho сказал:

Есть, но поверхностно - делал UI управления настройками устройства для депарафинизации нефтяных скважин. Там не было необходимости дорабатывать существующие контролы.

Показать  

Получается это коммерческая ситуация? Нужно было платить как-то за использование библиотеки QT?

  В 05.08.2022 в 06:08, Xipho сказал:

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

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

Показать  

Я сейчас посмотрел видео, где пишут калькулятор на QT. Мне понравилось. Что-то в этом наследование есть.

Нужно подумать, может получиться совместить то что сейчас в WGW с тем что в QT.

Ссылка на комментарий
Поделиться на другие сайты

  В 05.08.2022 в 07:25, Antonshka сказал:

Получается это коммерческая ситуация? Нужно было платить как-то за использование библиотеки QT?

Показать  

Нет, там использовалась 4 версия, она была бесплатной для коммерческого использования на тот момент.

Ссылка на комментарий
Поделиться на другие сайты

  В 05.08.2022 в 06:08, Xipho сказал:

Есть, но поверхностно - делал UI управления настройками устройства для депарафинизации нефтяных скважин. Там не было необходимости дорабатывать существующие контролы.

Показать  

У тебя только с QT мало опыта, или вообще с GUI?

Ссылка на комментарий
Поделиться на другие сайты

  В 05.08.2022 в 17:12, Xipho сказал:

С Qt

Показать  

Понятно.

Кстати я сейчас смотрел исходники QT. Там тоже есть интересные моменты в коде, как и у меня

  Показать контент

 

Я заметил что в WGW Layout система уступает той что в QT. Теперь хочу доработать.

Подумал, посмотрю как там сделано в QT. Но при виде кода решил что легче придумать самому. Пока разберешься, что там и к чему.

Как было с Docking.

Ссылка на комментарий
Поделиться на другие сайты

  • 2 месяца спустя...

Сегодня обнаружил интересный момент, связанный с утечкой GDI объектов.

Известно, что после того как созданный нами объект GDI нам больше не нужен, он должен быть удален специальной WinAPI функцией DeleteObject. Если этого не сделать, то произойдет утечка.

Для определения текущего количества GDI объектов для процесса, есть также специальная функция, GetGuiResources. Есть в интернете и специальная программа, которая позволяет определить не только общее количество GDI объектов, но и распределить их по типу. Название программы - GDIView.

 

Так вот, интересный момент связан с кистями и регионами. Даже если удалить их с помощью функции DeleteObject, количество объектов, возвращаемое функцией GetGuiResources, не измениться. Все потому, что система их кеширует.

Это не значит, что не нужно вызывать DeleteObject. Нет, ее нужно вызывать, но нужно просто всегда учитывать такую особенность реализации.

 

Например, вызовем функцию CreateRectRgn. Эта функция создаст для нас регион, увеличив при этом количество GDI объектов на 1. Позднее, вызвав для этого региона DeleteObject, количество объектов GDI не измениться. Однако, если вызвать функцию CreateRoundRectRgn, а затем DeleteObject, то в таком случае, количество GDI объектов все же уменьшиться на 1.

 

Получается, что это правило, правило кеширования и не уменьшения количества, относиться к кистям и регионам, созданным лишь определенными WinAPI функциями. Какие именно это функции, для кистей и регионов, нужно выяснять своими тестами.

 

GdiFlush никак не изменяет кеш таких объектов.

Скорее всего, Microsoft реализовала такую особенность не просто так. Но, это конечно не айс, с точки зрения определения утечки. Впрочем, реальная утечка объектов, проявляет себя как постоянное увеличения количества, когда как при кешировании, увеличение происходит всего один раз, в момент первого создания. По этому признаку, можно смело определить, что утечки, как таковой, нет.

 

Сколько еще таких особенностей скрывает Micosoft...

Ссылка на комментарий
Поделиться на другие сайты

  В 22.10.2022 в 08:43, Antonshka сказал:

Сколько еще таких особенностей скрывает Micosoft...

Показать  

ImageList, также имеет подобный "остаточный" эффект. После одного такого ImageList'a, остается 2 битмапа и две кисти. И это нормально.

В общем, при поиске утечек GDI объектов, нужно смотреть на постоянное увеличение их количества, а не на единоразовое.

Изменено пользователем Antonshka
Ссылка на комментарий
Поделиться на другие сайты

  В 23.10.2022 в 07:52, Xipho сказал:

А если после вызова DeleteObject обнулить переменную, в которой этот объект лежал, счетчик уменьшится?

Показать  

Нет, не уменьшится.

Мысль у тебя хорошая, я помню где-то в интернете мне попадалась она уже. Но я не помню, для какого она была контекста.

В каких случаях такие обнуления имеют эффект?

 

По поводу счетчика и кеша, вот ответ от Raymond Chen

  Показать контент

 

Ссылка на комментарий
Поделиться на другие сайты

Насчет кистей со сплошной заливкой я в курсе. Есть даже набор кистей по умолчанию типа BLACK_BRUSH, WHITE_BRUSH и иже с ними.

Обнуление переменной, по идее, должно уничтожить дескриптор GDI объекта и пометить память как свободную. 

Ссылка на комментарий
Поделиться на другие сайты

Вот выписка с MSDN Resource leak

  Показать контент

Мы можем обнулить созданный нами дескриптор кисти, но не можем обнулить тот дескриптор кисти, который помешен в dedicated cache.

Обнуление также никак не влияет на удаление самого объекта кисти в кеше. Он там будет сидеть до следующего вызова CreateSolidBrush, с таким же цветом как и у нее.

Это все что я понял на данный момент, из собственных тестов, и из интернета.

 

Я нигде не нашел функцию очистки такого специального кеша. Впрочем, я долго не искал. Если это норма для WIndows, то пусть так и будет.

Просто для обнаружения утечки GDI объектов, приходится в обязательном порядке несколько раз создавать и удалять какой-либо контрол.

Изменено пользователем Antonshka
Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.