PropertyPage Apply

Декабрь 14, 2009 от alexpir

При нажатии кнопки Apply изменения, внесенные на пропертипейдж должны «глубоко» сохраняться незамедлительно.

Объяснение. Логика пользователя такова – изменения, сделанные до нажатия на эту кнопку, должны обязательно запоминаться. Даже если потом будет нажато cancel, или диалог закрыт «крестиком»  ЭТИ изменения должны быть сохранены. А те изменения, которые были сделаны после нажатия на Apply, разумеется, при нажатии на Cancel НЕ должны применяться. Это не позволяет повесить применение всех изменений на OnClose.

Надо сказать, в очередной раз раздражает то, что DoDataExchange (SaveAndValidate) всегда вызывается при покидании данной Propertypage. Это не зависит от того, посылалось ли в PropertySheet PSM_CHANGED Более того, я не нашел способ внутри Propertypage понять, установлен ли этот флаг. Таким образом, сохранение данных ВСЕГДА происходит при покидании PropertyPage

Проблемы с CValueDlg

Октябрь 30, 2009 от alexpir

Проблема заключается в том, что рекурсия изменений (изменение присылается в сам источник изменений, например значение параметра фильтра – в методику, которая и апдейтила CValueDlg ) заблокирована в самом CValueDlg  (т.е. он не будет обрабатывать изменение, если он источник изменений), но не заблокирована в обратном направлении со стороны хранителя значения. Она происходит постольку, поскольку соотв. сообщение WM_VALUEDLG рассылается из DoDataExchange, если bSaveAndValidate = false, либо если источник UpdateData (true) – edit, т.е. реально во всех случаях, когда что-то делается в DoDataExchange.

Непонятно, почему из DoDataExchange(FALSE), т.е. в ситуации, когда ValueDlg отображает изменения внсенные снаружи, он присылает это сообщение. Это вроде бы неправильно.

Неправильный подход заключается в том, что изменения вносимые изнутри (нажатия на плюс-минус, и т.д.) применяются посредством вызова UpdateData (FALSE). Таким образом, поскольку SetValue тоже (и это как раз правильно) вызывает UpdateData (FALSE), объединяются совершенно различные ситуации: изменение снаружи и изменение изнутри диалога.

Исправление:

DoDataExchange(FALSE) в не должен рассылать сообщение WM_VALUEDLG. Он вызывается, когда требуется обновление контролов диалога в соотв. с измененным значением; это ситуация, обратная той о которой должно сигнализировать сообщение WM_VALUEDLG (и соотв. оно должно рассылаться при DoDataExchange(TRUE)).

Со своей стороны , кнопки плюс минус и т.д. должны в конечном счете приводить а) к DoDataExchange(FALSE) б) к рассылке сообщения.

Можно сделать функцию ChangeValueFromInside()

{UpdateData(FALSE); SendMessage(WM_VALUEDLG)}

SetValue должен применять DoDataExchange(FALSE)? но  не должен высылать сообщение WM_VALUEDLG. Оно должно высылаться только если произошла внутренняя (в диалоге) редакция значения. Рассылка нового значения по разным окнам (если такая требуется –надо проанализировать все вызовы SetValue) должна делаться как-то по-другому.

vector _bool_

Октябрь 15, 2009 от alexpir

Драфт нового стандарта C0x вызывает у меня последнее время все больше вопросов. Такое впечатление,  что господа Страуструп, Саттер и компания даже не подчистили проблемы, известные со времен обсуждения предыдущего C98. Вот яркий пример.

Еще в 98-99 годах активно высказывались мнения (упомянутого Саттера), что описание vector<bool> в стандарте С98 содержит внутреннее противоречие – данный контейнер не является стандартным, а также является underspecified.

Еще ДО принятия C98 делались попытки разрешить эту ситуацию, но к сожалению безрезультатно. Как с некой суммой информации об этом (а также, если кто-то подзабыл – в чем собсна проблема) можно ознакомиться вот с этой статьей.

Поскольку в большинстве статей по проблеме, которые я видел, люди пишут что-то вроде

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

vector<bool> vb;
...//init vb
bool *b = &vb[0];

и на этом «мысль заканчивается», пойдем немного дальше и попытаемся понять, почему же это так плохо.

Для начала – чем хорош нынешний vector<bool>? Он оптимизирует место, занимаемое контейнером. Когда это полезно? Когда массив очень большой. А какие еще проблемы у нас возникнут при работе с большим массивом, помимо места? Скорость, разумеется. Проблема не в том, что как пишут здесь , «1 Кб никого не парит», а в том что эта оптимизация места оборачивается пессимизацией скорости – не «потенциально», а 100% кинетически, если вы работаете с большими массивами bool, т.е. сохраняете их, копируете, передаете каким-то другим модулям. Благодаря невозможности получить указатели на кусок памяти, занимаемый нужным фрагментом контейнера, для нас закрыта возможность работать через быстрые «старорежимные» rtl-фунции типа memcpy ( или скажем fwrite, который сработает в несколько раз быстрее, чем всякие там ostream_iterator(ofstream_object) ). Т.е. примененная «оптимизация для больших объемов» при работе с оными создаст вам гораздо более грозные проблемы, чем те что она решает. Это известно с 90-х годов, но в Dinkumware STL, которую использует VS 2005, у vector<bool> по-прежнему нет методов получения вожделенного указателя, хотя от рождения есть всякие нестандартные flip, и можно было бы добавить еще. Это означает, что vector<bool> – «политический труп», на который давно махнули рукой, и все рекомендуют его просто игнорировать.

Что же мы видим в драфте нового стандарта (вот его позднейший кусочек про сабж) ? А ничего.  Все та же мутная херня, что и была в предыдущем стандарте. Те же пожелания реализовывать vector<bool> с упаковкой в биты. Даже не потрудились переименовать vector<bool> в bit_vector, чтобы люди могли легко получить нормальную, не проксированную реализацию vector<bool>.

RIP Concepts

Октябрь 9, 2009 от alexpir

In July 2009 the C++ standards committee decided to remove concepts from the C++0x by an unprecedented move
Аллилуйя!!!

Вот выкинули бы нахер еще всякие shared_ptr и было бы ваще счастье.

PS «Slowpoke detected» – yeah I know.

GdiPlus::MeasureString

Октябрь 7, 2009 от alexpir

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


GetClientRect(rectBnd);

graphics.MeasureString(L"", -1, font, pointOrigin/*origin*/, stringFormat, rectBnd/*in:rectBound, out:rectResult*/);

rectBnd == Rect(ClientRect.UpperLeft(),  ClientRect.UpperLeft()), т.е. 0,0,0,0

а не rectBnd == Rect(pointOrigin, pointOrigin)

Поэтому если попытаться потом сделать

rect(pointOrigin, rectResult.bottomright()),

то получишь прямоугольник у которого левый бок правее правого бока.

сукасука

Акселераторы

Июль 22, 2009 от alexpir

Задавать в качестве акселераторов не VK, а просто символы можно только для тех клавиш, которые являются латинскими буквами. Для остальных надо использовать VK_OEM_*

Например если нужен акселератор «правая квадратная скобка» следует ставить VK_OEM_6. Если поставить «]» – не будет работать.

О приоритете операторов

Июнь 2, 2009 от alexpir

LPDWORD pdwCountsReceived = …;

*pdwCountsReceived=0; //все верно

*pdwCountsReceived++; //++ выполнится прежде *, инкрементируется указатель а не содержимое

NK6 Presentation 24_04_09

Май 5, 2009 от alexpir

NK 6.0.0.2

Май 3, 2009 от alexpir

Второй релиз вылетел из гнезда.

NK 6.0.0.2

Исправления и улучшения см в readme

Из существенных для любопытствующих – есть демосигнал, работает без усилителя.

Для этого, сразу после логина, нажать на кнопку с шестеренками, на вкладке «Общие» выбрать «MBN-20 демо» и закрыть – открыть заново НК6

Пора бы и поставить за деньги, только вот некому – 2009 год продажами НК пока не ознаменовался.

Об изначальном убожестве MFC сплиттеров

Апрель 20, 2009 от alexpir

Узелок на память.

Система статических сплиттеров, когда все панэльки создаются заранее,а потом при необходимости Виды начинают занимать одну панэльку за другой (соотв. выдвигая их), имеет неустранимый недостаток – если вы открыли 4 вида, а потом 2 средних из них закрыли (т.е. схлопнули панэльки), оставшиеся Виды будут разделены 3мя сплиттерами (и соотв, передвигать их будет просто невозможно)

Сделать сплиттеры динамическими, как известно, можно только если все Виды одинаковые, одного класса.  Это следует из того, что фунция CSplitterWnd::Create, которой создается dynamic splitter принимает CCreateContext, котрый будет использовать при созданиии новых view (и он, естесвенно, содержит только один runtime-class view).

Разумеется, толковые парни сплясали с бубном, и теперь в описанной ситуации, при передвижении крайних из этих 3 сплиттеров, соотв. виды изменяют свои размеры (что достигается SetColumnInfo с последующим RecalcLayout – тяжелый случай).