Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.116.8.110] |
|
Сообщ.
#1
,
|
|
|
Здравствуйте!
Заранее оговорюсь - я не программист, я только учусь. Стояла задача визуализировать некоторую матрицу данных (или поток). Для определения матрицы данных использовалась консоль (в рамках получения цифр этого было достаточно). А вот для визуализации консоли оказалось недостаточно. 16 цветов (симпатично, но не информативно) Прикреплённый файлCON_1.png (14,18 Кбайт, скачиваний: 409) Может кто подскажет как получить чёрное поле с данными матрицы 100 х 2000, в которой значения изменяются от 0 до 100, каждое значение это ячейка на 2 символа, а цвет ячейки это интенсивность белого цвета, которое соответствует значению матрицы. |
Сообщ.
#2
,
|
|
|
Создайте битмап, в нужных местах рисуйте прямоугольники соответствующего цвета
l := value * 255 div 100; bmp.Canvas.Brush.Color := RGB(l,l,l); bmp.Canvas.FillRect(...) |
Сообщ.
#3
,
|
|
|
Цитата MBo @ Создайте битмап Спасибо за направление, буду изучать поскольку совершенно не знаком с формами, т.к. по специальности я физик |
Сообщ.
#4
,
|
|
|
Цитата ivan1234 @ Создайте битмап Упёрся в следующую проблему - как из консоли, получив промежуточное значения расчёта, открыть форму, вывести на форме значение этого промежуточного результата в виде градации цвета и опять вернуться к расчёту т.д. |
Сообщ.
#5
,
|
|
|
Нашёл такой пример для начинающих, немного переделал под свои нужды, то что вижу на экране для начала вполне устраивает зрительно:
unit unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormPaint(Sender: TObject); private { Private declarations } public { Public declarations } end; type TFigure = class private {Private declarations } FX,FY:integer; // поля координаты FColor:integer; // поле цвет Fn:integer; // поле длина ребра public { Public declarations } procedure Paint; virtual; abstract; procedure SetColor(c:integer); procedure Coordinates(X,Y:integer); property Color : integer read FColor write SetColor; // Свойство цвет property n : integer read Fn write Fn; // Свойство ребро property X : integer read FX write FX; // Свойство координата X property Y : integer read FY write FY; // Свойство координата Y end; type TSquare = class(TFigure) private { Private declarations } public { Public declarations } procedure Paint();override; {переопределяем базовый метод} end; type TMyObjects = class private { Private declarations } ArrObj: Array of TFigure; {массив, элементами которого являются объекты нашего типа TSquare} public { Public declarations } procedure AddFigure(X,Y,Color,n:integer); procedure RePaint(); procedure RePaint2(); end; var Form1: TForm1; MyObjects:TMyObjects; v, g: Byte; implementation {$R *.dfm} { TFigure } procedure TFigure.Coordinates(X, Y: integer); begin FX:=X; FY:=Y; end; procedure TFigure.SetColor(c: integer); begin FColor:=c; end; { TSquare } procedure TSquare.Paint; begin Form1.Canvas.Brush.Color := FColor; Form1.Canvas.Rectangle(X,Y,X+n,Y+n); //рисуем квадрат end; { TMyObjects } procedure TMyObjects.AddFigure(X, Y, Color,n: integer); var i:integer; b:byte; begin b := 0; for i:=0 to Length(ArrObj)-1 do if ArrObj[i] = nil then begin b := 1; Break; end; if b = 0 then //нет свободных, увеличим массив begin SetLength(ArrObj, Length(ArrObj)+1); i := Length(ArrObj)-1; end; ArrObj[i]:=TSquare.Create; ArrObj[i].Coordinates(x,y); ArrObj[i].SetColor(Color); ArrObj[i].n:=n; end; procedure TMyObjects.RePaint; var i:integer; begin for i:=0 to Length(ArrObj)-1 do if ArrObj[i] <> nil then ArrObj[i].Paint; end; procedure TMyObjects.RePaint2; var i:integer; Color:integer; begin i:= 10; Color:= RGB(Random(255),Random(255),Random(255)); MyObjects.AddFigure(g*10,v*10,Color,i); MyObjects.RePaint; end; procedure TForm1.FormPaint(Sender: TObject); begin for v:=0 to 63 do for g:=0 to 63 do MyObjects.RePaint2; end; procedure TForm1.FormCreate(Sender: TObject); begin MyObjects := TMyObjects.Create; end; end. ... Но почему так медленно??? С такой скоростью просто в мусорку. Может есть какой нибудь способ побороть этот недостаток? |
Сообщ.
#6
,
|
|
|
Процедура AddFigure реализована плохо. Расширение массива на единицу - неправильный подход, медленный и
может жрать память (в зависимости от версии Delphi и соотв. менеджера памяти) А вообще я не вижу смысла во введении всех этих объектов. Никакого полезного функционала, по крайней мере в текущей реализации, они в себе не содержат. Так что лучше использовать то, что я посоветовал: матрица данных у Вас уже есть, в ней содержится вся необходимая информация. По значению элемента считаете цвет, рисуете прямоугольник. Лишние прокладки - нафиг. |
Сообщ.
#7
,
|
|
|
Цитата MBo @ Процедура AddFigure реализована плохо )за что купил, за то продал попробовал ваш совет: procedure TForm1.FormPaint(Sender: TObject); begin for v:=0 to 12000 do for g:=0 to 63 do with Form1.Canvas do begin s:= Random(255); Pen.Color:=RGB(s,s,s); Brush.Color:=RGB(s,s,s); Rectangle(10*g, 10*v, 10*g+10, 10*v+10); end; end; работает значительно быстрее - просто замечательно Но по ходу изучения возникло ещё 2 вопроса: 1. как скролить такой большой массив как в примере? 2. как к скролу дополнительно добавить поток строк? |
Сообщ.
#8
,
|
|
|
Цитата ivan1234 @ 1. как скролить такой большой массив как в примере? 2. как к скролу дополнительно добавить поток строк? Я бы выбрал визуальный компонент типа Grid и заполнял ячейки цветом. Тогда и скролить было бы можно. Осталось найти такой компонент |
Сообщ.
#9
,
|
|
|
>Осталось найти такой компонент
Так сам грид всё умеет. Пример >как скролить такой большой массив как в примере? Отрисовать матрицу в битмап, битмап на PaintBox, лежащем на ScrollBox. Если размеры слишком велики, то битмап вообще можно не создавать (размеры ограничены, памяти нужно много), а рассчитывать часть матрицы, помещающуюся в скроллируемое окно (ScrollBox), и только эту часть выводить. >как к скролу дополнительно добавить поток строк? Что это означает?? |
Сообщ.
#10
,
|
|
|
Цитата MBo @ Отрисовать матрицу в битмап, битмап на PaintBox, лежащем на ScrollBox. С битмапом пока не разобрался, если я правильно понял необходимо заранее создать 256 картинок с градацией серого, где то его хранить, если на диске, то боюсь опять возникнут проблемы со скоростью, если создавать в процессе запуска программы, то как это правильно реализовать пока не знаю, потому как ООП для меня пока как для чайника)) Цитата MBo @ >как к скролу дополнительно добавить поток строк? Что это означает?? всё очень просто: (в общем смысле) какой либо процесс имеет свой спектральный состав - это строка частот с различными амплитудами... но процессы очень редко бывают стабильными во времени, а на осциллограмме мы видим только мгновенное состояние спектра. Получив поток таких строк позволит более детально изучить изменение спектра во времени, тем более что время изменения спектра ничтожно мало. Т.е. при постоянном анализе на поле формы хотелось бы увидеть постоянно меняющуюся в реальном времени матрицу спектра. В console это прекрасно реализуется, но к сожалению только цифрами. |
Сообщ.
#11
,
|
|
|
>если я правильно понял необходимо заранее создать 256 картинок с градацией серого,
Видимо, неправильно. ООП тут ни при чём. >изменение спектра во времени Посмотрите, что такое сонограмма |
Сообщ.
#12
,
|
|
|
Цитата MBo @ Видимо, неправильно. может посоветуете литературу в которой хорошо разжёвано про Bitmap? Цитата MBo @ Посмотрите, что такое сонограмма здесь я совсем не понял, как это относится к моему вопросу, ну существует такой термин в медицине, возможно что то отдалённо похожее я хочу увидеть у себя на экране... и что? меня интересует как это реализовать, а не как это назвать |
Сообщ.
#13
,
|
|
|
https://ru.wikipedia.org/wiki/Спектрограмма
Вопрос про скролл я сначала понял как скроллирование окна, поскольку размер 12000 указан. Вам же, похоже, нужно, чтобы просто бежали вверх или вниз строки с информацией. Достаточно иметь массив с таким количеством строк, чтобы помещалось на экране, расширять его не надо (если не требуется сохранять всё). После приёма новой строки можно сдвигать данные в массиве на одну строку вверх, новую дописывать в конец, потом выводить содержимое массива. |
Сообщ.
#14
,
|
|
|
Цитата MBo @ Вопрос про скролл я сначала понял как скроллирование окна, поскольку размер 12000 указан. именно так и спрашивалось в 1 пункте, а 2 пункт это одновременная реализация скрола и бегущая строка, по крайней мере так реализовано в консоли. Возможно то что я хочу получить в конечном счёте не реализуемо на форме, тогда перед собой я поставлю скорее всего другую задачу и приду к решению типа: Цитата MBo @ Достаточно иметь массив с таким количеством строк, чтобы помещалось на экране, расширять его не надо (если не требуется сохранять всё). После приёма новой строки можно сдвигать данные в массиве на одну строку вверх, новую дописывать в конец, потом выводить содержимое массива. Что касаемо Bitmap, то в инете про него от 2 предложений до 2 страниц (для профессионалов), я же не профессионал и мне этих 2 страниц мало, тем более что всё описание Bitmap отирается на классы, методы и свойства, а ООП я только начал изучать) Добавлено я работаю в области металловедения (структуры, состояния, характеристики, свойства и тд), а привёл простейший пример известный даже школьнику чтобы было понятно что мне нужно получить на выходе, а СПЕКТРОГРАММА в определении википедии лишь частный случай возможного применения такого метода |
Сообщ.
#15
,
|
|
|
Цитата ^D^ima @ Я бы выбрал визуальный компонент типа Grid Цитата MBo @ Так сам грид всё умеет Попробовал этот вариант. Всё заполняет, есть скрол, но: 1. На вскидку обращение к ячейкам таблицы работает в 2 раза медленнее чем обращение к координатам точки 2. Встроенная сетка несколько мешает восприятие зрительной информации (как её убрать сетку не знаю, потому как чайник) 3. Скол работает как скрол строки, а не всей таблицы и в месте фокуса затирает значение 4. Когда доходит до последней строчки окна начинает скролить таблицу, но изменяет размер ячеек по высоте и затирает информацию в невидимых строках В общем исходя их выше сказанного, наилучшим способом оказалось обращение к координатам пикселя, хотелось только добавить туда работоспособный скрол. Был бы очень благодарен за кусок кода, который позволил бы это реализовать. |
Сообщ.
#16
,
|
|
|
Цитата ivan1234 @ Упёрся в следующую проблему - как из консоли, получив промежуточное значения расчёта, открыть форму, вывести на форме значение этого промежуточного результата в виде градации цвета и опять вернуться к расчёту т.д. 1) Отдельным GUI приложением, связь держать через любой способ - STDIN, сокеты, сообщения, маппинг памяти (имхо для озвученных целей - самое простое) 2) Изначально сделать GUI приложение, добавить консоль через AttachConsole С отображением: помимо грида, можно попробовать с listview, хотя я бы, наверно, сделал paintbox + собственная отрисовка |
Сообщ.
#17
,
|
|
|
Цитата Fr0sT @ С отображением: помимо грида, можно попробовать с listview, хотя я бы, наверно, сделал paintbox + собственная отрисовка Начал пробовать этот вариант, и при создании первой таблицы выяснилось что для большого количества строк (8000-12000)это очень трудоёмкий процесс, поскольку каждую строку необходимо вносить вручную, можно конечно и программно, но тогда скорость заполнения онлайн значительно снижается. Попробовал вернуться к StringGrid1DrawCell, оказалось, что при правильной настройке параметров таблицы многие проблемы описанные ранее вообще отпали, но пока осталась самая существенная - если матрица значений (цветов) больше окна на форме то при скроле таблицы в моём варианте обновляются цвета ячеек. Есть ли возможность это как то побороть. Допускаю что просто код у меня совершенно кривой, или просто событие OnDrawCell невозможно остановить после первого заполнения таблицы? Кусок моего кода, которым заполняется таблица: procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); begin with StringGrid1 do begin s:= Random(255); Canvas.Brush.Color:=RGB(s,s,s); Canvas.FillRect(CellRect(ACol, ARow)); end; end; procedure TForm1.FormPaint(Sender: TObject); begin for ARow:=0 to 63 do for ACol:=0 to 63 do StringGrid1DrawCell(Sender,ACol,ARow,Rect,State); end; |
Сообщ.
#18
,
|
|
|
>при скроле таблицы в моём варианте обновляются цвета ячеек
Естественно, ведь они при перерисовке заполняются случайным серым цветом s:= Random(255); Canvas.Brush.Color:=RGB(s,s,s); А вот вызывать StringGrid1DrawCell (из Paint) не нужно вообще - событие само возникнет при необходимости перерисовки видимых ячеек, тогда и обработчик вызовется. |
Сообщ.
#19
,
|
|
|
Цитата MBo @ Естественно, ведь они при перерисовке заполняются случайным серым цветом получается так? запускаю программу, программа выполняет главный и вложенный цикл, заполняет таблицу случайным образом и останавливается в конце главного цикла, но... когда я хочу просмотреть ту часть таблицы которая не влезла в окно, эта часть таблицы не статична, а перезаполняется опять новыми случайными числами.... те я уже буду видеть не те начальные данные, а уже изменённые - пока я не пойму как это происходит, и самое главное для чего нужно продолжать закончившийся цикл?? Цитата MBo @ событие само возникнет при необходимости перерисовки видимых ячеек В том то и дело что мне не нужно перерисовывать первоначально заполненную таблицу, мне нужно её просмотреть, выбрать значимые участки, сделать допустим PS и тд. те в конце главного цикла остановить работу обработчика. ЗЫ: понятно что в реальной ситуации вместо генератора в таблицу заносятся реальные значения реальных датчиков, хочу сказать что реализация такого визуального представления даже в кусочном виде позволяет сделать значительный скачок в анализе результатов. Очень жаль что в настоящий момент не получается увидеть сразу всю картину процесса целиком) |
Сообщ.
#20
,
|
|
|
Цитата MBo @ А вот вызывать StringGrid1DrawCell (из Paint) не нужно вообще Проверил - если я правильно понял, циклы в моём коде вообще не работают просто по циклам автоматически таблица заполняется полностью вся, размеры которой указаны в параметрах StringGrid. Но остаётся вопрос - как например заполнить таблицу наполовину, и как её зафиксировать? |
Сообщ.
#21
,
|
|
|
Ваша задача - вместо Random обеспечить значение, соответствующее индексам ACol, ARow.
|
Сообщ.
#22
,
|
|
|
Цитата MBo @ Ваша задача - вместо Random обеспечить значение, соответствующее индексам ACol, ARow вроде всё работает, но тогда получается что при каждом скроле вся таблица и соответственно весь код по заполнению полностью повторяется и окно полностью перерисовывается начиная с величины сдвига (те таблица не хранится в памяти и не сдвигается окно по таблице). Я конечно проверю, но скорее всего большая матрица будет двигаться по окну как шторка. И второе - поток в этом случае исключается полностью, потому как между вводом данных и выводом результатов на экран есть ещё целая куча математики, которая и так существенно тормозит код. |
Сообщ.
#23
,
|
|
|
Цитата Fr0sT @ можно попробовать с listview Как и всегда оказалось, что если у кого то не получается что то сделать (кто то это конечно же я) - это совершенно не означает что это невозможно осуществить в принципе, просто на тот период у этого "кто то" недостаточно знаний. Перекопав огромное количество примеров оказалось, что listview прекрасно справляется с поставленной задачей, заполняет поле мгновенно, да и скол присутствует в различных видах, правда несколько тормозит при прокрутке всего окна, но на этом этапе для меня этого достаточно. Всем кто принял участие огромное спасибо! Проект который у меня получился выложен здесь: unit Unit_1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls; type TForm1 = class(TForm) ListView1: TListView; procedure FormCreate(Sender: TObject); procedure ListView1Data(Sender: TObject; Item: TListItem); procedure ListView1CustomDrawItem(Sender: TCustomListView; Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean); procedure ListView1CustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} uses Unit_2; type TColorData=record end; var arr: TSimpleArr; s: Word; procedure TForm1.FormCreate(Sender: TObject); var lc: TListColumn; j: integer; begin MatrData(arr); Listview1.OwnerData:=True; ListView1.ViewStyle:=vsReport; for j:=0 to 10 do begin lc:=ListView1.Columns.Add; lc.Caption:=inttostr(j-1); lc.Width:=42; end; ListView1.RowSelect:=true; ListView1.Items.Count:=Length(arr); Caption:=IntToStr(Length(arr)); end; procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView; Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean); begin Sender.Canvas.Brush.Color:=RGB(255,255,255); end; procedure TForm1.ListView1CustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean); begin Sender.Canvas.Brush.Color:=RGB(s,s,s);; end; procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem); var n, j: integer; begin n:=10; item.Caption:=arr[item.Index,0].caption; for j:= 0 to n-1 do begin item.SubItems.Add(IntToStr(arr[item.Index,j].data)); s:= arr[item.Index,j].data; end; end; end. и unit Unit_2; interface uses SysUtils; type TColor =record caption:string; data:integer; end; TSimpleArr = array of array of TColor; procedure MatrData(var arr:TSimpleArr); implementation procedure MatrData(var arr:TSimpleArr); var k, n, i, j: integer; begin k:=12000; n:=10; SetLength(arr,k,n); for i := 0 to k-1 do for j:= 0 to n-1 do begin arr[i,j].caption:=inttostr(i); arr[i,j].data:=i*j; end; end; end. |