OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 16 Апрель, 2024 12:04

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 40 ]  На страницу 1, 2  След.
Автор Сообщение
 Заголовок сообщения: Создание своего контрола
СообщениеДобавлено: Вторник, 31 Январь, 2006 16:07 
Аватара пользователя

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 13:17
Сообщения: 84
Откуда: Россия, Мурманск
Создал свой контрол. Не могу понять как сделать чтобы он линковался к данным...
Открываю StdTables. Там есть тип Control и есть ещё 2 типа: Table - сами данные и TableValue - загадочный тип, который не экспортируется и экземпляры которого не создаются (?!).
Из Control'a доступ к Table идёт через Control.item.GetVal, причём возвращаемое значение типа TableValue. Вопрос: откуда оно берётся? Ну и главное: как мне сделать чтобы в моём контроле линк работал?

P.S. Сильно жалко, что стандартный грид недоступен для расширения. Приходится делать свой. Как вы думаете это правильно? Надёжность за счёт расширяемости?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Вторник, 31 Январь, 2006 23:33 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
TableValue - это просто оболочка для того значения, которое мы хотим получить через метапрограммирование.
item: Meta.Item - это описатель, соответствующий какому-либо объекту (типу, переменной, процедуре и т.п.). Такой описатель можно получить, зная символьное имя объекта через Meta.LookupPath - а дальше делать с этим объектом все, что угодно (см. Meta). В данном случае - получить его значение с помощью GetValue. GetValue принимает параметр по ссылке, который должен быть записью- потомком от Meta.Value и иметь единственное поле подходящего типа - в которое Meta поместит значение.

Что касается расширения - в компонентных системах рекомендуется избегать межмодульного наследования реализации, т.к. это ведет к тесным зависимостям от внутренних особенностей работы конкретной версии модуля - так называемая Fragile Base Class Problem (проблема хрупкости базового класса). Рекомендуется между модулями, особенно от различных поставщиков, наследоваться только от абстрактных классов. Если нужно, можно унаследоваться от базового абстрактного класса, агрегировать поле того типа, от которого хотелось бы наследоваться, и дальше вызовы части процедур делегировать ему.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Среда, 01 Февраль, 2006 00:15 
Аватара пользователя

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 13:17
Сообщения: 84
Откуда: Россия, Мурманск
Илья Ермаков писал(а):
GetValue принимает параметр по ссылке, который должен быть записью- потомком от Meta.Value и иметь единственное поле подходящего типа - в которое Meta поместит значение.

Вот чисто теоретически интересно, а откуда Мета узнаёт про тип, который не экспортирован (имею ввиду запись-потомок от Meta.Value), там ведь вроде в документации сказано, что Мета безопасен и работает только с экспортируемыми сущностями? Ну и вообще интересно как он работает.

Ещё вопросик: Хочу сделать данные для линка - расширяемой записью. Как поставить условие в PROCEDURE (c: Control) CheckLink- (VAR ok: BOOLEAN); для проверки того, что тип - это потомок исходного типа или сам он? (Ну как проверить, что сам он - понятно)

Илья Ермаков писал(а):
Что касается расширения -
...
Fragile Base Class Problem (проблема хрупкости базового класса).
Ну в общем - понятно, хотя, по идее эта проблема должна затрагивать только экземпляры классов-потомков. Разве нет? Экземпляры базового класса ведь останутся нехрупкими?
Жаль только, что из подходящих абстрактных классов имеется только Controls.Control. Был бы какой-нить абстрактный класс табличного поля, с базовой функциональностью (ну, частично абстрактный).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Среда, 01 Февраль, 2006 02:52 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Цитата:
Вот чисто теоретически интересно, а откуда Мета узнаёт про тип, который не экспортирован (имею ввиду запись-потомок от Meta.Value), там ведь вроде в документации сказано, что Мета безопасен и работает только с экспортируемыми сущностями? Ну и вообще интересно как он работает.


Чисто теоретически отвечаю :-)
Через сканирование или LookupPath достать неэкспортированные объекты нельзя, после компиляции они не присутствуют в символьном файле и потому по имени недоступны. Но они точно также имеют тэг типа, а значит, можно получить полную информацию об их структуре.

Например, в нашу процедуру приходит ptr: ANYPTR. Мы вызываем Meta.GetItem(ptr) - получаем Item, по которому и работаем. (В Meta, однако, нет процедуры, которая давала бы Item по ANYREC (GetThisItem - это служебная внутренняя процедура - и она делает совсем не то), но это просто мелкая недоработка - такую процедуру легко написать самому, но придется обращаться к Kernel...)

А вообще Meta не делает ничего, кроме как представляет информацию в удобном виде, в Item, позволяет сканировать и т.п.
А всю основную работу делают несколько процедур Kernel - Meta сделан для изоляции от него и для удобства. Поизучайте Kernel - любопытная вещь. Управление динамической типизацией, менеджер памяти и сборщик мусора в 1800 строках :-)

Цитата:
по идее эта проблема должна затрагивать только экземпляры классов-потомков. Разве нет?

Так и есть. Хрупкость в том смысле, что потомки опираются на нечто ненадежное, что может меняться.
Но, между прочим, это касается и разработчика базового класса. Единожды позволив наследовать реализацию, он очень себя стесняет в развитии, т.к. если много пользователей полагались на какую-нибудь недокументированную особенность, он уже не сможет свободно уйти от этой особенности.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Среда, 01 Февраль, 2006 02:54 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
sacred писал(а):
Ещё вопросик: Хочу сделать данные для линка - расширяемой записью. Как поставить условие в PROCEDURE (c: Control) CheckLink- (VAR ok: BOOLEAN); для проверки того, что тип - это потомок исходного типа или


Проще всего - через модуль Services, там есть готовые подходящие процедуры:
PROCEDURE Extends (IN type, base: ARRAY OF CHAR): BOOLEAN;
PROCEDURE GetTypeName (IN rec: ANYREC; OUT type: ARRAY OF CHAR);
PROCEDURE Is (IN rec: ANYREC; IN type: ARRAY OF CHAR): BOOLEAN;
PROCEDURE IsExtensionOf (IN ra, rb: ANYREC): BOOLEAN;


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Четверг, 02 Февраль, 2006 17:49 

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 10:28
Сообщения: 1428
Илья Ермаков писал(а):
Проще всего - через модуль Services, там есть готовые подходящие процедуры:

Нет. Проще всего: "a IS A" ;)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Четверг, 02 Февраль, 2006 20:14 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Ну да. Я просто слишком усложнил вопрос :-)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Пятница, 03 Февраль, 2006 10:50 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
Trurl писал(а):
"a IS A"

Это когда тип A известен (экспортирован)...


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Суббота, 04 Февраль, 2006 16:55 
Аватара пользователя

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 13:17
Сообщения: 84
Откуда: Россия, Мурманск
Илья Ермаков писал(а):
sacred писал(а):
Ещё вопросик: Хочу сделать данные для линка - расширяемой записью. Как поставить условие в PROCEDURE (c: Control) CheckLink- (VAR ok: BOOLEAN); для проверки того, что тип - это потомок исходного типа или


Проще всего - через модуль Services, там есть готовые подходящие процедуры:
PROCEDURE Extends (IN type, base: ARRAY OF CHAR): BOOLEAN;
PROCEDURE GetTypeName (IN rec: ANYREC; OUT type: ARRAY OF CHAR);
PROCEDURE Is (IN rec: ANYREC; IN type: ARRAY OF CHAR): BOOLEAN;
PROCEDURE IsExtensionOf (IN ra, rb: ANYREC): BOOLEAN;


Расширяемая запись не прокатила. Meta.GetVal хочет только запись того типа, который передан в качестве параметра. Никаких потомков не признаёт. Пришлось перехитрить: создать нерасширяемую запись с одним полем, и передавать всегда переменные именно этого типа, и линковать только её. А уже в этом поле хранить свои типы, расширяемые и т.д.

Дальше, у меня почему-то не перерисовыется мой контрол, когда я перекрываю его каким-нибудь окном, а потом окно сдвигаю. Вместо контрола - мусор. Иногда он перерисовывается, но я не понял в каких именно случаях. Что нужно сделать чтобы он перерисовывался всегда, когда необходимо?

И ещё, полосы прокрутки не появляются при изменении данных, которые в линке. Вот если в режиме редактирования формы поизменять размер, то они появляются, а по-другому - нет.

Посоветуёте, что-нибудь.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 05 Февраль, 2006 00:48 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Цитата:
Дальше, у меня почему-то не перерисовыется мой контрол, когда я перекрываю его каким-нибудь окном, а потом окно сдвигаю. Вместо контрола - мусор. Иногда он перерисовывается, но я не понял в каких именно случаях. Что нужно сделать чтобы он перерисовывался всегда, когда необходимо?


Вообще говоря, для правильной перерисовки не надо делать НИЧЕГО, кроме как обеспечить Restore, который эту перерисовку делает. Остальное делает среда. Значит, что-то не то в Restore.


Цитата:
И ещё, полосы прокрутки не появляются при изменении данных, которые в линке. Вот если в режиме редактирования формы поизменять размер, то они появляются, а по-другому - нет.

Полосы прокрутки используете стандартные - StdScrolllers? Во-первых, что-то обрабатывается только после вызова Dialog.Update для линкованного интерактора. Во-вторых, надо, чтобы при Restore происходил в случае необходимости пересчет и изменение размера отображения. Остальное сделает автоматика.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 05 Февраль, 2006 00:58 
Аватара пользователя

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 13:17
Сообщения: 84
Откуда: Россия, Мурманск
Илья Ермаков писал(а):

Вообще говоря, для правильной перерисовки не надо делать НИЧЕГО, кроме как обеспечить Restore, который эту перерисовку делает. Остальное делает среда. Значит, что-то не то в Restore.

Полосы прокрутки используете стандартные - StdScrolllers? Во-первых, что-то обрабатывается только после вызова Dialog.Update для линкованного интерактора. Во-вторых, надо, чтобы при Restore происходил в случае необходимости пересчет и изменение размера отображения. Остальное сделает автоматика.

Код:
PROCEDURE (v: Control)  Restore* (f: Views.Frame; l, t, r, b: INTEGER);

Так с Restore разобрался. Я думал, что l, t, r, b - это границы отображения, а это оказывается границы прямоугольника внутри отображения, который надо перерисовать!

Однако, с прокруткой всё так же плохо. И не обновляется при изменении данных.
Как сделать, чтобы при Restore происходил пересчет и изменение размера отображения? Надо кому-то какое-то сообщение послать, так? Кому и какое?
Код:
PROCEDURE (v: Control) HandleCtrlMsg2- (f: Views.Frame;
                        VAR msg: Controllers.Message; VAR focus: Views.View);
VAR
   w, h : INTEGER;
   changed : BOOLEAN;
   Data : TableValue;
   ok : BOOLEAN;
BEGIN
   IF v.item.Valid() THEN
      v.item.GetVal(Data, ok);
   ELSE
      ok := FALSE;
   END;
   changed := TRUE;
   WITH msg: Controllers.ScrollMsg DO
      v.context.GetSize(w, h);
      IF msg.vertical THEN
         CASE msg.op OF
            Controllers.decLine: IF v.RowOrigin>0 THEN DEC(v.RowOrigin); END;
            |Controllers.incLine: IF v.OriginHeight()+h<v.Height() THEN INC(v.RowOrigin); END;
            |Controllers.decPage: IF v.RowOrigin>0 THEN DEC(v.RowOrigin); END;
            |Controllers.incPage: IF v.RowOrigin<Data.table.RealData.RowCount() THEN INC(v.RowOrigin); END;
            |Controllers.gotoPos: v.RowOrigin := RoundedDIV(msg.pos, v.RowHeight(-1) (*DIV 1000*));
         END;
      ELSE
         CASE msg.op OF
            Controllers.decLine: IF v.ColOrigin>0 THEN DEC(v.ColOrigin); END;
            |Controllers.incLine: IF v.OriginWidth()+w<v.Width() THEN INC(v.ColOrigin); END;
            |Controllers.decPage: IF v.ColOrigin>0 THEN DEC(v.ColOrigin); END;
            |Controllers.incPage: IF v.ColOrigin<Data.table.RealData.ColCount() THEN INC(v.ColOrigin); END;
            |Controllers.gotoPos: v.ColOrigin := RoundedDIV(msg.pos, v.ColWidth(-1) (*DIV 1000*));
         END;
      END;
      msg.done := TRUE;
      IF changed THEN Views.Update(v, Views.keepFrames) END
   | msg: Controllers.PollSectionMsg DO
      v.context.GetSize(w, h);
      IF msg.vertical THEN
         msg.wholeSize := v.Height() (*DIV 1000*);
         msg.partSize := h (*DIV 1000*);
         msg.partPos := v.OriginHeight() (*DIV 1000*);
      ELSE
         msg.wholeSize := v.Width() (*DIV 1000*);
         msg.partSize := w (*DIV 1000*);
         msg.partPos := v.OriginWidth() (*DIV 1000*);
      END;
      
      msg.valid := msg.partSize < msg.wholeSize;
      msg.done := TRUE
   ELSE
   END;
END HandleCtrlMsg2;

Полосы прокрутки - стандартные, когда надо вызывать Dialog.Update ?


P.S.

Посмотрел - моему контролу никогда не передаётся сообщение Controllers.PollSectionMsg. Как сделать чтобы оно передавалось?


Последний раз редактировалось sacred Воскресенье, 05 Февраль, 2006 02:22, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 05 Февраль, 2006 02:19 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Возможно, не зачищаете фон? При перерисовке надо считать, что в [l, t, r, b] лежит мусор - и затирать его. И еще, если отоборажение непрозрачное, то надоперегрузить метод (v: View) GetBackground (VAR color: Ports.Color), и вернуть цвет для фона - закраску выполнит контейнер.

Цитата:
когда надо вызывать Dialog.Update ?


После того, как поменяли значение переменной, на которую указывает link (вообще-то она называется "интерактор").


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 05 Февраль, 2006 02:25 
Аватара пользователя

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 13:17
Сообщения: 84
Откуда: Россия, Мурманск
На самом деле, я вызываю Dialog.Update(DialogData) сразу после изменения данных в DialogData.
Однако, не происходит ни перерисовки отображения, ни посылки других сообщений (типа определения необходимости и параметров прокрутки).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 05 Февраль, 2006 10:42 

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 18:08
Сообщения: 76
Views.Update(v, Views.keepFrames)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 05 Февраль, 2006 12:44 
Аватара пользователя

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 13:17
Сообщения: 84
Откуда: Россия, Мурманск
Views.Update и Dialog.Update надо вызывать по-очереди? В каком порядке? Для чего нужен каждый из них?

Ещё. В каких случаях надо определять методы Update и UpdateList?
Что в них нужно прописывать?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 05 Февраль, 2006 15:30 

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 18:08
Сообщения: 76
Они для разных целей. Views.Update обновляет View. Dialog.Update обновляет поля интерактора формы.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 05 Февраль, 2006 16:01 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Dialog.Update - это стандартная процедура, которая используется для обновления всех отображений, связанных с какой-либо записью-интерактором.
Смотрите, что она делает: посылает по всей иерархии отображений сообщение Views.NotifyMsg:
NotifyMsg = EXTENSIBLE RECORD (Views.Message)
view-: Views.View; (* = NIL *)
id0, (* = ADR(интерактора) *) id1: INTEGER;
opts: SET (* = update, GuardChack *)
END
Каждое отображение в своей HandleViewMsg смотрит на адрес интерактора и решает, относится к нему это сообщение или нет. В Controls.Control такой HandleViewMsg уже реализован. Так как при вызове Dialog.Update в opts присутствует update и GuardCheck, то Controls.HandleViewMsg будет проверять охрану и вызывать Views.Update.

Что делает Views.Update? Она ставит прямоугольник отображения в очередь отложенного обновления, которой владеет корневой кадр соответствующего окна. Через некоторое время будет очередное обновление экрана, и будет вызвана Restore вашего отображения.

А вот уже в Restore нужно реагировать на все изменения интерактора: перерисовывать данные, менять свой размер и т.п. В наиболее распостраненном случае достаточно вызвать view.context.SetSize - а скроллинг обеспечит сама среда, в механизме кадров, ну и соотв. полосы прокрутки у обертки StdScrollers тоже появятся автоматически.
Но, как я понимаю, вы переделываете SqlControls, и там размер отображения (по вертикали) не меняется в целях скорости, а сообщения ScrollMsg и PollSectionMsg отрабатываются самостоятельно. Тогда в Restore вам нужно поменять какую-то внутреннюю переменную отображения, которая указывает на число строк или что там... Все остальное касательно прокрутки, как я уже говорил, сделает среда.

Что касается Dialog.Update и Views.Update, то при программировании на уровне "кидания контролов на форму" используется Dialog.Update (обычно ведь view неизвестен, известен только интерактор). Views.Update нужен для перерисовки конкретного известного нам отображения.

Да, по нашим наблюдениям, перерисовка и вызов Restore иногда происходит асинхронно (ядро ББ многопоточное, там от 5 до 8 потоков иногда крутятся параллельно). Поэтому надо руководствоваться следующим правилом: как можно меньше побочных эффектов. Можно менять только состояние своего отображения и вызывать ТОЛЬКО функции с повторной входимостью. Проблема выплыла, когда мы в Restore вызывали функции из внешней DLL без повторной входимости. Долго не могли понять, почему DLL работала неправильно, пока не перенесли все вызовы из Restore в другое место. Только тогда поняли весь смысл фразы из документации: "Разработчик не должен делать никаких предположений относительно момента вызова Restore"...


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Воскресенье, 05 Февраль, 2006 17:14 
Аватара пользователя

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 13:17
Сообщения: 84
Откуда: Россия, Мурманск
Илья Ермаков писал(а):
А вот уже в Restore нужно реагировать на все изменения интерактора: перерисовывать данные, менять свой размер и т.п. В наиболее распостраненном случае достаточно вызвать view.context.SetSize - а скроллинг обеспечит сама среда, в механизме кадров, ну и соотв. полосы прокрутки у обертки StdScrollers тоже появятся автоматически.
Но, как я понимаю, вы переделываете SqlControls, и там размер отображения (по вертикали) не меняется в целях скорости, а сообщения ScrollMsg и PollSectionMsg отрабатываются самостоятельно. Тогда в Restore вам нужно поменять какую-то внутреннюю переменную отображения, которая указывает на число строк или что там... Все остальное касательно прокрутки, как я уже говорил, сделает среда.

Нет, я вообще делаю таблицу с нуля. напрямую от Controls.Control без использования других исходников. (Кстати, вот опять же всплыла тема, про которую я уже говорил. Закрывая доступ к методам, и таким образом, защитившись от "хрупкости" базового класса мы сводим повторное использование кода к очень малым величинам, и переходим к китайскому методу Copy/Paste).
Но это я отвлёкся. Фактически, при изменении данных, Restore не вызывается ВООБЩЕ никогда, до тех пор, пока я не перекрою чем-нибудь окно с контролом, т.е. не испорчу изображение. Хотя Dialog.Update я вызываю сразу после изменения данных. В чём может быть проблема - не понимаю.
PollSectionMsg - также не вызывается! Поэтому там можно писать всё, что угодно - результат не изменится. Вернее это сообщение передаётся 1 раз: при первом отображении контрола, а потом при изменении данных оно больше не вызывается никогда! Где у меня может быть ошибка?

Заодно просветите тёмного, что такое view.context.SetSize
зачем и когда его нужно вызывать. А также что такое view.context?
Высоту и ширину и способ прокрутки я определяю самостоятельно.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Понедельник, 06 Февраль, 2006 00:47 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
1) Почему после Dialog.Update не вызывается Restore. Скажите, а где вы храните link на интерактор? В view.prop.link или в каком-нибудь самопальном поле? Controls.Control в обработчике HandleViewMsg сранивает параметр id NotifyMsg со своим prop.link, и если они совпадают, делает guard check и Views.Update. Другое поле он, естественно, не может проверить, и потому пропустит NotifyMsg "мимо ушей". Можно, конечно, написать свой HandleViewMsg2 для NotifyMsg, но лучше просто хранить ссылку в предназначенном поле.

2) PollSectionMsg не вызывется, надо думать, по той же причине.

3) Касательно view.context.GetSize - эта процедура возвращает размер отображения. Не размер содержимого отображения, за который отвечаете вы сами, а именно размер, который отображение занимает в контейнере или окне. Последнее слово касательно этого размера принадлежит контейнеру, а не вашему отображению. Ваше отображение может лишь высказать свои пожелания, вызвав context.SetSize. Соответственно, если ваше отображение обернуто в скроллер (StdScrollers), то скроллер при изменении размера автоматически даст сролбары. Удобно то, что для простых отображений вообще не надо обрабатывать ScrollMsg и PollSectionMsg - достаточно просто устанавливать размер отображения равным размеру содержимого. Restore будет перерисовывать отображение целиком, но кадр сам выполнит нужный сдвиг и отсечение. Только для больших отображений, например, текстов или таблиц, делается своя обработка скроллинга. При этом размер отображения по вертикали всегда остается постоянным, мы сами по внутреннему состоянию отображения определяем, какой кусок рисовать в Restore и через PollSectionMsg говорим "крыше", на какой позиции мы находимся. А вот горизонтальный скроллинг для текстов и таблиц обычно вручную не обрабатывается, там просто меняется размер отображения, так проще, т.к. ширина текстов обычно невелика.
Еще нужно написать обработку в HandlePropMsg сообщения SizePref, которое среда посылает отображению при его загрузке или открытии, чтобы запросить желаемый размер - читайте 6 раздел хелпа "Конструирование отображений".

Цитата:
Закрывая доступ к методам, и таким образом, защитившись от "хрупкости" базового класса мы сводим повторное использование кода к очень малым величинам, и переходим к китайскому методу Copy/Paste).

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

А вот Copy-Paste действительно помогает. Если время не терпит, иногда беру исходный код из стандартного модуля и изменяю в нем только то, что нужно. Вообще, открытые коды ББ здорово помогают, без них разобраться и быстро начать работать было бы гораздо сложнее.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Понедельник, 06 Февраль, 2006 10:50 
Аватара пользователя

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 13:17
Сообщения: 84
Откуда: Россия, Мурманск
Илья Ермаков писал(а):
1) Почему после Dialog.Update не вызывается Restore. Скажите, а где вы храните link на интерактор? В view.prop.link или в каком-нибудь самопальном поле? Controls.Control в обработчике HandleViewMsg сранивает параметр id NotifyMsg со своим prop.link, и если они совпадают, делает guard check и Views.Update. Другое поле он, естественно, не может проверить, и потому пропустит NotifyMsg "мимо ушей". Можно, конечно, написать свой HandleViewMsg2 для NotifyMsg, но лучше просто хранить ссылку в предназначенном поле.

Никаких специальных полей в моём контроле нет. Доступ к данным я получаю через self.item.GetVal. Связь с данными устанавливаю статически через дизайнер форм. Полагаю, что она хранится там, где положено.

Илья Ермаков писал(а):
А вот горизонтальный скроллинг для текстов и таблиц обычно вручную не обрабатывается, там просто меняется размер отображения, так проще, т.к. ширина текстов обычно невелика.

И горизонтальная и вертикальная прокрутка у меня реализована "вручную", и работает правильно. Но сами полосы скроллинга появляются только если в окне редактирования формы подвигать размеры отображения слегка. После этого прокрутка работает как надо.

Илья Ермаков писал(а):
Цитата:
Закрывая доступ к методам, и таким образом, защитившись от "хрупкости" базового класса мы сводим повторное использование кода к очень малым величинам, и переходим к китайскому методу Copy/Paste).

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

Нет, не подошло бы. Мне надо заменить логику работы таблицы с её данными. В стандартной таблице данные берутся из фиксированной структуры, состоящей из массивов строк. Это черезчур расточительно по ресурсам, кроме того, надо долго ждать, пока эти данные заполнятся из исходных данных. Надо ведь всё преобразовать в строки, выделить память т.д.
Я делаю динамическую таблицу, которая получает только данные, отображаемые на экране в данный момент. Т. к. типичное число строк в моей задаче 1.5 -5 миллионов. И колонок 5-10.

Илья Ермаков писал(а):
А вот Copy-Paste действительно помогает. Если время не терпит, иногда беру исходный код из стандартного модуля и изменяю в нем только то, что нужно. Вообще, открытые коды ББ здорово помогают, без них разобраться и быстро начать работать было бы гораздо сложнее.

Вот где-то я читал, что Copy-Paste - это любимейший китайский способ сохранения и размножения ошибок :)


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 40 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
cron
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB