OberonCore https://forum.oberoncore.ru/ |
|
Графический отчет https://forum.oberoncore.ru/viewtopic.php?f=24&t=241 |
Страница 1 из 1 |
Автор: | zar [ Понедельник, 12 Июнь, 2006 00:02 ] |
Заголовок сообщения: | Графический отчет |
Здравствуйте. Набрался-таки наглости и решил немножко вас напрячь. Верю, что за спрос и у вас не бьют. Хотелось бы узнать у компетентных людей, насколько просто/сложно решается следующая задача в BlackBox. Есть подозрение, что решается она сильно проще, чем, например, в Дельфи, в которой я и делаю работу(выполнено процентов 97). А задача такая. Нужно создать макет графического отчета, который представляет из себя несколько(скажем, количеством до 100, т.е. макет БОЛЬШОЙ, в смысле длинный) страниц, либо цельный рулон соответствующих размеров. В дальнейшем, для удобства, буду говорить только о рулоне. В самом верху рулона пишется некая системная информация, размещаются несколько таблиц, несколько рисунков - назовем это шапкой отчета. Под шапкой размещаются несколько Графических Боксов, каждый со своим набором графиков. Должна быть возможность диалоговой настройки Графических Боксов. Размеры Графических Боксов = (длина рулона - высота шапки отчета)(т.о. ориентация графиков - вертикальная). Т.е. Графические Боксы получаются очень большие. (В Дельфи я использовал для отображения графиков и шапки отчета метафайлы.) Требуется: создавать и размещать на рулоне в произвольном месте, в том числе на поверхности Графических Боксов(например, по клику кнопки мыши) Текстовые Боксы(ТБ). Текстовый Бокс - это, грубо говоря, перетаскиваемая мышью(драг&дроп) прямоугольная рамка с расположенным внутри текстом. Текст может распологаться как в строчку, так и заполнять весь прямоугольник, в зависимости от размеров текста и ограничивающей его рамки. Нужно, чтобы ТБ показывал - при двойном клике по нему, например - диалоговое окно настройки своих параметров(поле ввода/редактирования текста, настройка шрифта). Также необходимо, чтобы можно было менять размеры ТБ(с автоматической перегруппировкой текста внутри бокса) при помощи мыши путем перетаскивания его границ. Насколько я понимаю, в BlackBox есть инструмент для решения этой проблемы - "вьюшки", но вот как им воспользоваться... Надо бы разобраться, но не хватает времени... Кроме того, необходимо предусмотреть возможность масштабирования макета. Что скажете, господа? |
Автор: | Cardinal [ Понедельник, 12 Июнь, 2006 05:07 ] |
Заголовок сообщения: | Re: Графический отчет |
zar писал(а): Здравствуйте.
Набрался-таки наглости и решил немножко вас напрячь. Верю, что за спрос и у вас не бьют. Хотелось бы узнать у компетентных людей, насколько просто/сложно решается следующая задача в BlackBox. Есть подозрение, что решается она сильно проще, чем, например, в Дельфи, в которой я и делаю работу(выполнено процентов 97). Вы правы. Легко Будет примерно так: Код: (***************************************)
PROCEDURE LoadFromFile*(name: Files.Name; OUT view: Views.View); VAR loc: Files.Locator; conv: Converters.Converter; BEGIN loc := Files.dir.This( name ); view := Views.Old( Views.dontAsk, loc, name, conv); END LoadFromFile; (***************************************) PROCEDURE CreateReport; VAR textModel: TextModels.Model; textView: TextViews.View; formatter: TextMappers.Formatter; view: Views.View; BEGIN textModel := TextModels.dir.New(); (* создаю модель *) textView := TextViews.dir.New(textModel); (* создаю вид *) formatter.ConnectTo(textModel); (* присоединяю форматтер *) LoadFromFile('List/Rsrc/Pictures.bmp', view); (* загружаю документ из файла *) formatter.WriteString('это рисунок'); formatter.WriteLn; formatter.rider.WriteView(view, 10 * Ports.mm, 20 * Ports.mm); (* вывожу рисунок в текстовую модель размерами 10мм х 20 мм *) formatter.WriteLn; ... formatter.WriteString('это документ'); formatter.WriteLn; LoadFromFile('List/Rsrc/Report.odc', view); formatter.WriteView(view); (* Размер документа - по умолчанию *) formatter.WriteLn; ... Views.OpenView(textView); END; Возможно, что нужно ещё будет создать контексты ... Код этот не тестировал. Делал подобное . А Вы в Delphi работали с TCanvas? |
Автор: | zar [ Понедельник, 12 Июнь, 2006 09:39 ] |
Заголовок сообщения: | Re: Графический отчет |
Cardinal писал(а): Возможно, что нужно ещё будет создать контексты ... Код этот не тестировал. Делал подобное . А Вы в Delphi работали с TCanvas?
В Delphi работал с TMetaFileCanvas и, соответственно, с TMetaFile. С TCanvas, насколько помню, были серьезные проблемы. Битмапы не годятся из-за их неподъемных размеров(получаются файлы объемом до нескольких сот МБ). Делаю так: рисую графики в метафайле, часть метафайла отображаю на экране. Прокрутка происходит при помощи ScrollBar - просто метафайл перерисовывается с новой позиции, в зависимости от ScrollBar.Position. Таким образом создается эффект прокручивания отчета. Но проблема в том, что мало создать и отобразить графики в отчете. Требуется еще и прокомментировать графики, для чего и требуются Текстовые Боксы. ТБ нужно создавать и размещать/форматировать при помощи мыши произвольно по всему отчету, с привязкой к ключевому параметру графиков. Делать все это требуется визуально, после загрузки данных в графики. Вот в чем загвоздка. Предельно краткое описание работы с программой: -- сконструировали при помощи мыши шаблон отчета - накидали компоненты на страницу - создали шапку отчета; сохранили шаблон в файл; -- загрузили шаблон из файла; загрузили данные в отчет - получили длинный(на несколько десятков страниц) отчет, в котором подавляюще бОльшую часть занимают графики, очень длинные графики. Теперь эти графики нужно прокомментировать по всей их длине. -- Создаем Текстовые Боксы и при помощи мыши произвольно(в любом месте) размещаем/форматируем их по всему рулона отчета. ТБ привязываются к ключевому параметру графиков(на случай изменения масштаба графиков). |
Автор: | Cardinal [ Понедельник, 12 Июнь, 2006 10:28 ] |
Заголовок сообщения: | |
Да, в BlackBox-е определенно проще решать задачи, для которых нужны составные документы . Я поэтому и решил писать irc-клиента на ББ - изучить новый язык, среду, понять что есть компоненты, раздельная компиляция. Попробуйте код, который я написал выше. Вам надо начать . |
Автор: | Илья Ермаков [ Понедельник, 12 Июнь, 2006 21:02 ] |
Заголовок сообщения: | |
Ну, примерно вот так это может выглядеть - в текстовый документ кладем несколько отображений-форм (FormViews), на них накидываем графики (я кинул из Excel, но можно реализовать свои отображения-"вьюшки"), потом открываем этот документ, а юзерь будеть кидать туда блоки текста, двигать как угодно и править в них текст: |
Автор: | Илья Ермаков [ Понедельник, 12 Июнь, 2006 21:06 ] |
Заголовок сообщения: | |
А код будет выглядеть (схематично) так: Код: PROCEDURE Do* ;
VAR fm: FormModels.Model; fv: FormViews.View; tm: TextModels.Model; tv: TextViews.View; wr: TextModels.Writer; BEGIN fm := FormModels.dir.New(); fv := FormViews.dir.New(fm); fv.SetBackground(0FFFFFFH); tm := TextModels.dir.New(); wr := tm.NewWriter(NIL); (* пишем через wr шапку *) wr.WriteView(fv, 10*36000, 200*36000); (* засовываем форму, накидываем на форму через ее fm.NewWriter() графики и т.п. *) tv := TextViews.dir.New(tm); Views.OpenAux(tv, "Отчет") (* открываем документ *) END Do; |
Автор: | zar [ Понедельник, 12 Июнь, 2006 22:31 ] |
Заголовок сообщения: | |
Илья Ермаков писал(а): А код будет выглядеть (схематично) так:
Действительно, схематично. Даже не вспомню, когда в последний раз чувствовал себя полным идиотом. Теперь чувствую. Спасибо за свежие ощущения. А если серьезно, то возникает много идиотских вопросов. Озвучу, для начала, некоторые из них. Хрен с ним, побуду идиотом. 1. Насколько я понимаю, ключевое требование, а именно - отобразить БОЛЬШОЙ отчет, который может растянуться на несколько десятков страниц формата А4 - не выполняется. Размеры отображений-форм (FormViews) существенно ограничены, и туда не впихнешь длинный график(?). Если не ошибаюсь, допустимые размеры графиков в Excell также невелики. 2. Прекрасно представляю, как можно "накидать" на отчет ТекстБоксы в Дельфи(например так: нажали кнопку выбора типа объекта-->кликнули мышью на поверхности отчета-->создали объект в точке клика-->теперь можем совершенно произвольно, независимо от всего остального, перетаскивать/изменять размеры при помощи мыши, двойным кликом по объекту вызываем диалоговое окно настройки его параметров и т.п.). Совершенно не представляю, как это можно сделать в Блэкбоксе. Работать через системное меню Блэкбокса? Как? |
Автор: | Илья Ермаков [ Вторник, 13 Июнь, 2006 01:58 ] |
Заголовок сообщения: | |
Да, у Вас задачка не очень тривиальная. Размер отображений (вьюшек, как Вы их называете), помещаемых внутрь текста/формы, ограничен. Однако никто не мешает написать свое отображение, которое будет само реализовывать прокрутку на любое расстояние. Тогда получается следующая конструкция: наше специализированное отображение, которое умеет рисовать график и реализует прокрутку по нему, оно открывается как корневое (т.е. как главный документ, в корне окна), а в него помещаются необходимые текстовые блоки - как шапка, так и надписи. Можно, конечно, налеплять не только текстовые, но и любые другие отображения. В общем, я тут накидал примерчик - рисуется длиннющая вертикальная диаграмма из 10 тыс. полосок (можно и больше), открывается как отдельный документ. На нее мышкой можно добавлять текстовые блоки, нажав клавишу и очертив желаемый прямоугольник для блока. Затем добавленные блоки можно выбирать и в каждом из них работать как в обычном текстовом документе, естественно, форматируя, вкладывая еще отображения и т.п. Сюда выкладываю окончательный вариант кода. Запускать команду TempGraphic.Open. Также выкладываю сам исходник модуля - там последовательно (снизу вверх) лежат 4 версии кода, начиная от простейшей и до окончательной. Поэтапно разбираться будет лучше... Исходник: Вложение:
|
Автор: | Илья Ермаков [ Вторник, 13 Июнь, 2006 02:00 ] |
Заголовок сообщения: | |
Код: (O) TempGraphic.Open
MODULE TempGraphic; IMPORT Views, Ports, Models, Stores, Controllers, ObxRandom, TextViews, TextModels; CONST bandH = 10 * Ports.mm; TYPE Plot = POINTER TO RECORD (Views.View) data: POINTER TO ARRAY OF INTEGER; (* % *) topBand: INTEGER; (* Верхний отображаемый столбец *) blocks, focus: Context END; Context = POINTER TO RECORD (Models.Context) (* Описатель контекста для внедряемых отображений *) next: Context; base: Plot; (* контейнер - наш график *) view: Views.View; (* внедряемое отображение. Mожет быть не только TextView, но и любой другой *) l, t, r, b: INTEGER (* cached bounding box of contained view *) END; PROCEDURE CalcRange (t, b: INTEGER; OUT beg, end: INTEGER); BEGIN beg := t DIV bandH; end := b DIV bandH + 1 END CalcRange; PROCEDURE DrawBand(f: Views.Frame; fW, num, val: INTEGER); BEGIN f.DrawRect(0, num * bandH, SHORT(ENTIER(fW / 100 * val)), (num + 1) * bandH, 0, Ports.blue) END DrawBand; PROCEDURE (v: Plot) Restore (f: Views.Frame; l, t, r, b: INTEGER); VAR beg, end, len, i: INTEGER; w, h: INTEGER; c: Context; BEGIN v.context.GetSize(w, h); len := LEN(v.data); beg := v.topBand; end := beg + h DIV bandH + 1; FOR i := MIN(beg, len-1) TO MIN(end, len-1) DO DrawBand(f, w, i-beg, v.data[i]) END; (*Создаем подкадры для всех внедренных отображений. Дальше их отрисовку обеспечит среда*) c := v.blocks; i := 0; WHILE c # NIL DO (* Рисуем рамочку *) f.DrawRect(c.l, c.t - v.topBand*bandH, c.r, c.b - v.topBand*bandH, 0, Ports.red); Views.InstallFrame(f, c.view, c.l, c.t - v.topBand*bandH, i, c = v.focus); INC(i); c := c.next END END Restore; PROCEDURE ^ NewBlock (v: Plot; l, t, r, b: INTEGER); PROCEDURE ^ CheckBlock (v: Plot; x, y: INTEGER): Context; PROCEDURE (v: Plot) HandleCtrlMsg (f: Views.Frame; VAR msg: Controllers.Message; VAR focus: Views.View); VAR w, h, len, page: INTEGER; l, t, r, b: INTEGER; c: Context; PROCEDURE InputRect; (* Считываем прямоугольник для нового блока *) VAR x, y: INTEGER; mod: SET; isDown: BOOLEAN; BEGIN f.Input(x, y, mod, isDown); l := x; t := y; REPEAT f.Input(x, y, mod, isDown) UNTIL ~isDown; IF x < l THEN r := l; l := x ELSE r := x END; IF y < t THEN b := t; t := y ELSE b := y END END InputRect; BEGIN v.context.GetSize(w, h); page := h DIV bandH; len := LEN(v.data); WITH msg: Controllers.PollSectionMsg DO (* Опрос состояния прокрутки, можно возвращать в любых единицах, главное - отношение трех величин *) IF msg.vertical THEN (* Отрабатываем только вертикальную прокрутку *) msg.wholeSize := len; msg.partPos := v.topBand; msg.partSize := page; msg.valid := TRUE; msg.done := TRUE END | msg: Controllers.ScrollMsg DO IF msg.vertical THEN CASE msg.op OF | Controllers.decLine: v.topBand := MAX(0, v.topBand-1) | Controllers.incLine: v.topBand := MIN(v.topBand+1, len-1) | Controllers.decPage: v.topBand := MAX(0, v.topBand-page) | Controllers.incPage: v.topBand := MIN(v.topBand+page, len-1) | Controllers.gotoPos: v.topBand := MAX(0, MIN(msg.pos, len-1)) END; msg.done := TRUE; Views.Update(v, Views.rebuildFrames) END | msg: Controllers.TrackMsg DO c := CheckBlock(v, msg.x, msg.y); (* Проверяем, нет ли уже в точке блока. *) IF c = NIL THEN (* Если нет, то создаем новый *) InputRect; IF r - l < 30 * Ports.mm THEN r := l + 30 * Ports.mm END; IF b - t < 20 * Ports.mm THEN b := t + 20 * Ports.mm END; INC(t, v.topBand*bandH); INC(b, v.topBand*bandH); NewBlock(v, l, t, r, b) ELSE IF c = v.focus THEN (* Если в этой точке уже фокусированный блок, то говорим среде, что обработку сообщения надо передать ему *) focus := c.view ELSE v.focus := c (* Иначе устанавливаем новый фокус *) END END; Views.Update(v, Views.rebuildFrames) | msg: Controllers.PollCursorMsg DO (* Устанавливаем форму курсора *) c := CheckBlock(v, msg.x, msg.y); IF c = NIL THEN (* Если блоков нет, то крестовый курсор *) msg.cursor := Ports.graphicsCursor ELSIF c = v.focus THEN (* Если фокусированный блок, то спросим у него самого *) focus := v.focus.view ELSE (* Если нефокусированный блок, то стрелка *) msg.cursor := Ports.arrowCursor END ELSE (* Если есть фокус, то передаем все остальные сообщения ему *) IF v.focus # NIL THEN focus := v.focus.view END END END HandleCtrlMsg; PROCEDURE CheckBlock (v: Plot; x, y: INTEGER): Context; VAR c: Context; BEGIN INC(y, v.topBand*bandH); c := v.blocks; WHILE c # NIL DO IF (c.l <= x) & (x < c.r) & (c.t <= y) & (y < c.b) THEN RETURN c END; c := c.next END; RETURN NIL END CheckBlock; PROCEDURE NewBlock (v: Plot; l, t, r, b: INTEGER); VAR block: Context; BEGIN NEW(block); block.view := TextViews.dir.New(TextModels.dir.NewFromString("Текстовый блок")); block.l := l; block.t := t; block.r := r; block.b := b; block.next := v.blocks; v.blocks := block; Stores.Join(v, block.view); block.view.InitContext(block); v.focus := block END NewBlock; (* Context *) PROCEDURE (c: Context) ThisModel (): Models.Model; BEGIN RETURN NIL END ThisModel; PROCEDURE (c: Context) GetSize (OUT w, h: INTEGER); BEGIN w := c.r - c.l; h := c.b - c.t END GetSize; PROCEDURE (c: Context) Normalize (): BOOLEAN; BEGIN RETURN TRUE END Normalize; PROCEDURE Init (v: Plot); VAR i: INTEGER; BEGIN NEW(v.data, 10000); FOR i := 0 TO LEN(v.data)-1 DO v.data[i] := SHORT(ENTIER(ObxRandom.Uniform()* 100)) END END Init; PROCEDURE Open* ; VAR v: Plot; BEGIN NEW(v); Init(v); Views.OpenAux(v, "Отчет") END Open; END TempGraphic. |
Автор: | zar [ Вторник, 13 Июнь, 2006 09:05 ] |
Заголовок сообщения: | |
Илья Ермаков писал(а): Сюда выкладываю окончательный вариант кода. Запускать команду TempGraphic.Open.
Также выкладываю сам исходник модуля - там последовательно (снизу вверх) лежат 4 версии кода, начиная от простейшей и до окончательной. Поэтапно разбираться будет лучше... Исходник: http://blackbox.metasystems.ru/download ... raphic.odc Ну что тут скажешь. Круто. Спасибо за код. Буду разбираться, наверняка появятся вопросы, не обессудьте. |
Автор: | Targitay [ Среда, 14 Июнь, 2006 11:38 ] |
Заголовок сообщения: | |
Цитата: Сюда выкладываю окончательный вариант кода. Запускать команду TempGraphic.Open.
Также выкладываю сам исходник модуля - там последовательно (снизу вверх) лежат 4 версии кода, начиная от простейшей и до окончательной. Поэтапно разбираться будет лучше... Исходник: http://blackbox.metasystems.ru/download ... raphic.odc Код работает, но при попытке распечатать появляется TRAP в PROCEDURE (v: Plot) HandleCtrlMsg (f: Views.Frame; VAR msg: Controllers.Message; VAR focus: Views.View); в точке: len := LEN(v.data); - v.data = NIL Как же вывести на принтер? |
Автор: | zar [ Среда, 14 Июнь, 2006 11:39 ] |
Заголовок сообщения: | |
Думал, сам разберусь, но не так быстро... Вопросы, снова глупые, возникли такие: 1. Как попроще сделать перетаскивание мышью(в смысле драг&дроп, пускай и при какой-нибудь нажатой клавише) полученные ТекстБоксы? 2. Как менять при помощи мыши размеры полученных Боксов(те самые квадратики по углам и сторонам, за которые можно перетаскивать границы Боксов)? 3. При наличии в отчете ТекстБоксов И при быстром прокручивании отчета иногда "вываливается" Trap. Как с этим бороться? По поводу первых двух вопросов: подозреваю, что есть какие-то "штатные" средства? |
Автор: | Илья Ермаков [ Суббота, 24 Июнь, 2006 22:59 ] |
Заголовок сообщения: | |
Прошу прощения, что долго не отвечал... Форум почему-то не пометил эту ветку как активную... 1) По поводу трепа. Повторить смог только один раз, больше у меня почему-то не появляется. Причина вроде бы в том, что в этом куске кода f.DrawRect(c.l, c.t - v.topBand*bandH, c.r, c.b - v.topBand*bandH, 0, Ports.red) идет работа со слишком большими координатами (ведь в ББ все измеряется в универсальных единицах, 1 мм = 36000 уе), идет переполнение, в результате - прямоугольник с неверными вершинами, срабатывает предусловие в DrawRect. Во-первых, надо оптимизировать - делать DrawRect и InstallFrame только для тех блоков, которые реально в текущем кадре, во-вторых, можно ввести для вертикальной позиции дополнительную переменную - номер "страницы", а top пусть меряется от "страницы", чтоб избежать переполнения в длинных графиках. 2) По поводу печати - перед печатью отображение копируется, а у нас оно копироваться не умеет - я не стал реализовывать, чтоб не отвлекать на это внимание. Надо описать процедуру (v: Plot) CopyFromSimpleView (см. документацию Views), которая будет копировать нужные поля отображения (создавая полные копии блоков в том числе, а не просто присваивая указатели). Чтоб сохранять, надо реализовать Internalize/Externalize (см. Stores). 3) Для изменения размеров - расширьте обработку TrackMsg в HandleCtrlMsg, чтоб при щелчке на границе блока происходило "протягивание" границы - готовый код же уже перед глазами - "протягивание" прямоугольника для нового блока. CursorMsg - для изменения формы курсора на границе. Для перетаскивания - обработать в HandleCtrlMsg сообщение Controllers.DropMessage - среда при дропе сообщит и бросаемое отображение, и позицию. Для бросаемого отображения создаем блок и т.д. Вообще говоря, можно пойти иным путем и писать отображение - расширение Containers.View, как это сделано для FormViews. Там для сложных контейнеров уже кое-что реализовано в готовом виде. Однако для вашего случая это будет даже сложнее. |
Автор: | adva [ Суббота, 30 Сентябрь, 2017 10:06 ] |
Заголовок сообщения: | Re: |
Илья Ермаков писал(а): Код: (O) TempGraphic.Open MODULE TempGraphic; ... END TempGraphic. А можно бы еще пример для случая когда view и model разделены по модулям? Не могу понять, как в свою графическую модель вставить TextView. Все таки была бы пошаговая отладка, проще было бы понять устройство блекбокса, а так точно, черный ящик ) |
Автор: | adva [ Воскресенье, 01 Октябрь, 2017 15:43 ] |
Заголовок сообщения: | Re: Re: |
adva писал(а): А можно бы еще пример для случая когда view и model разделены по модулям? Пока примера не надо, кажется понял, почему у меня не выводится встроенное отображение, сначала проверю догадку. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |