Мне нужно сделать тест. Базу вопросов хочу хранить как file of record. Проблема заключается в том, что в тесте должны быть картинки. Хотел сделать как поле записи. Но вот проблема: в файл не записывается ни поле :TImage ни :TPicture ни даже :TBitmap. Как это можно осуществить?
По разному можно. Например, выбросить из головы желание заниматься глупостями и изобретать базу самостоятельно. Берешь любую настоящую базу данных (тот же MSAccess) и делаешь с ней все, что хочешь...
Можно забросить содержимое картинки в TMemoryStream, и из него уже записать в файл. Но тут возникает вопрос: а сколько ты места отвел для хранения картинки в том поле, где она будет храниться? А если не поместится - что делать будешь?
Чего это? У тебя ж файл, который типизированный, не будет прямо в твоем EXE-шнике храниться, правда? Так какая разница, сделаешь ты хранение в MDB, а интерфейс в Дельфи или хранение в своем file of record, и интерфейс в том же Дельфи?
Цитата
type tq=record p:tbitmap; end;
не пойдет. TBitmap - это класс, сохранение которого тебе ничего не даст (ну, сохранил ты в файле адрес того участка, где хранилось изображение, или его палитра, и что? Перезапусти программу, изображения там уже нет, при попытке чтения оттуда в лучшем случае получишь AV)
Так какая разница, сделаешь ты хранение в MDB, а интерфейс в Дельфи или хранение в своем file of record, и интерфейс в том же Дельфи?
Я с базами данных вообще никогда не работал. Слышал, что так это можно осуществить, просмотрел книжки мельком, но то что я там заметил - меня особо не обрадовало: составление таблиц, сортировки по параметрам итд.. "На готовенькое" не попал. Думал, через файлы легче будет.
Цитата
не пойдет. TBitmap - это класс, сохранение которого тебе ничего не даст (ну, сохранил ты в файле адрес того участка, где хранилось изображение, или его палитра, и что? Перезапусти программу, изображения там уже нет, при попытке чтения оттуда в лучшем случае получишь AV)
Теперь я понял, почему вот эта программа:
var q,w:TBitmap; f:file of TBitmap; begin assignfile(f,'in'); { rewrite(f); q:=TBitmap.Create; q.LoadFromFile('1.bmp'); write(f,q); closefile(f);} reset(f); read(f,w); closefile(f); form1.Image1.Picture.Bitmap:=w; end;
При втором запуске (и закомментированом коде) выдает ошибку, а если раскомментировать, то все нормально Что такое АV?
Как надоест - скажешь, я помогу тебе организовать хранение в БД.
Допустим уже надоело. Прочитать - прочитаю, но времени катастрофически нет... в идеале програмку надо было еще месяц назад сдать... а так где-то неделька осталась...
Добавлено через 2 мин. Помогите) С чего надо начинать?
Как бы отмазаться я смогу - тест из текстового файла есть, но ведь это же не то.
то что я там заметил - меня особо не обрадовало: составление таблиц, сортировки по параметрам итд.. "На готовенькое" не попал.
А на что ты рассчитывал попасть? На готовую программу?
Чего там делать? Открываешь MS Access, создаешь одну таблицу, содержащую как минимум одно поле типа OLEObject - я назвал его image - (в нем будет храниться изображение. Если тебе надо еще что-то - создавай сразу и все остальное).
Все поля, которые нужны - создал? Сохраняешь БД, и выходишь из Access-а, вся дальнейшая работа - из Дельфи. Сначала надо связать базу с твоей программой. Для этого на форму положим компонент TADOConnection (из раздела DbGo, у меня Д2009, поэтому, извини, все дальнейшие места расположения компонентов я буду приводить именно из этой версии), компонент TADOTable (тоже DbGo), и TDataSource (из Data Access)...
Вот тут лежит Видео, около 2.5 Мб, показывающее, как и в какой последовательности надо подключать базу к проекту на Дельфи (это было давно сделано, почти 2 года назад, просто сейчас оно оказалось нужно )
Подключил все, DBGrid показывает пустые ячейки? Прекрасно... Теперь можно их заполнять. Чтоб занести текст - можно прямо использовать DBGrid (т.е., прямо в нем и печатать). Картинки - да пожалуйста:
// 1. Из TImage в текущую запись БД: procedure TForm1.Button1Click(Sender: TObject); var memStr: TMemoryStream; begin memStr := TMemoryStream.Create; try Image1.Picture.Graphic.SaveToStream(memStr); memStr.Seek(0, soFromBeginning); DBGrid1.DataSource.DataSet.Edit; TBlobField(DBGrid1.DataSource.DataSet.FieldByName('image')).LoadFromStream(memStr); DBGrid1.DataSource.DataSet.Post; finally memStr.Free; end; end;
// 2. Из текущей записи БД назад в TImage - легко: procedure TForm1.Button2Click(Sender: TObject); var bStream: TADOBlobStream; bm: TBitmap; begin if not DBGrid1.DataSource.DataSet.FieldByName('image').IsNull then begin bStream := TADOBlobStream.Create(TBlobField(DBGrid1.DataSource.DataSet.FieldByName('image')), bmRead); try bm := TBitmap.Create; bm.LoadFromStream(bStream); Image2.Picture.Bitmap.Assign(bm); // Это я для теста гружу в ДРУГОЙ Image bm.Free; finally bStream.Free; end; end; end;
sheka, база данных - это правильное решение, с ним разберись обязательно. Но если программа нужна срочно, то не вижу смысла вообще хранить изображения в каких-то своих форматах. Создай директорию и храни изображения там. Можешь изменить расширения файлов, чтобы никто не догадался =). А в записи отведи место только под имя файла.
а можно вопрос? как организовать фильтрацию данных? как можно тут использовать запросы? например, хочу найти записи, значение поля 'fio' равно 'Иванов'. записей может быть несколько
Что она делает? тыкнул ctrl+mouse и нашел описание функции
function QuotedStr(const S: string): string; var I: Integer; begin Result := S; for I := Length(Result) downto 1 do if Result[I] = '''' then Insert('''', Result, I); Result := '''' + Result + ''''; end;
сделал эксперимент
procedure TForm2.Button2Click(Sender: TObject); begin Button2.Caption:=''''; end;
В итоге есть только одн апостроф. Получается, что <''''> это и есть апостроф в строке?
Ничего особенного. Просто преобразует входную строку так, что она на выходе "обернута" апострофами. Кстати, в основном - именно для работ с БД, где требуется строковые параметры запросов заключать в апострофы...
Цитата
Получается, что <''''> это и есть апостроф в строке?
Да, внешние апострофы - это признак строки, а внутренние два - это один апостроф, который строка и содержит... Дублирование необходимо для того, чтобы не завершать строку:
Button2.Caption := 'test of 's: error'; // Первый же одиночный апостроф строку "сломал"
Нет такой функции, и не рекомендую я тебе ее писать... Ибо DBGrid может находиться в режиме фильтрации, ты найдешь индекс выделенной строки, потом тебе захочется что-то с ним сделать, а фильтр отменится или изменится, вся индексация летит к чертям, что дальше?
Обходной путь, конечно, есть. В классе TDBGrid есть свойство Row, но оно скрыто от посторонних глаз. Можно его открыть. Добавляешь
type TDBGrid = class(DBGrids.TDBGrid) public // Теперь Row считается общим членом класса property Row; end;
перед описанием класса формы, и потом обращаешься к свойству Row там, где нужно получить номер текущей записи ДБГрида. Но учти, разработчики VCL совсем не просто так ее скрыли от посторонних "шаловливых ручек". Некоторые причины я тебе уже привел.
Также интересует еще вопрос с картинкой: я нашел как ее можно показывать в самом DBGridе, по моему там было с помощью отрисовки Bitmapа на canvasе клетки, но в таком случае возникает вопрос с подгонкой размера картинки под размер клетки. Поэтому думал сделать так: если выделена запись, то вывести ее значение поля OLE в Image, который где-то бы на форме находился.
А для этого ни разу не надо знать номер строки... Любая операция в Гриде производится с текущей строкой. Для ее удаления можно применить:
DBGrid1.DataSource.DataSet.Delete;
Цитата
Поэтому думал сделать так: если выделена запись, то вывести ее значение поля OLE в Image, который где-то бы на форме находился.
Правильно думал... Я приводил код отображения картинки из БД в TImage... Если его повесить на событие DBGrid->DataSource->OnDataChange, это будет выполнять поставленную задачу:
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField); var bStream: TADOBlobStream; bm: TBitmap; begin if not DBGrid1.DataSource.DataSet.FieldByName('image').IsNull then begin bStream := TADOBlobStream.Create(TBlobField(DBGrid1.DataSource.DataSet.FieldByName('image')), bmRead); try bm := TBitmap.Create; bm.LoadFromStream(bStream); Image2.Picture.Bitmap.Assign(bm); bm.Free; finally bStream.Free; end; end else Image2.Picture := nil; // поле image пустое... Очищаем end;
Это тебе не самописная база, где все пришлось бы делать вручную, и отслеживать текущую запись, и ловить момент перехода по списку записей... В ADO уже все есть...
У меня должен в базе храниться достаточно длинный текст (где-то 1-3 предложения), а он целиком не помещается в одну строку(MSAccess на длину ругается, но это ничего страшного, можна обойтись и этой длиной. проблема в неудобности обозрения информации) . Вычитал, что стандартно многострочным поле ДБГрида быть не может. Мои варианты решений проблемы: 1) т.к. времени очень мало - забить на создание редактора базы и пользоваться MSAccess в этих целях. Но как тогда загрузить картинку через него? Если ее загружаешь( или просто из папки перетаскиваешь в поле ОЛЕ, или рисуешь встроеным редактором), то делфи выдает ошибку при считывании этого поля. 2) использовать поле МЕМО, вывод которого ДБГрид тоже не поддерживает. Т.е. его надо привязать к объекту мемо(тому который на форму кинуть можно).
из 2) появляется еще один вопрос: как считывать информацию из полей ДБГрида? (тоже как-то через поток?): а) просто текстового поля б) поля МЕМО - для реализации 2-го пункта.
а он целиком не помещается в одну строку(MSAccess на длину ругается
Поле типа Memo (описанное как Memo в Access-е) способно хранить до 64К текста... Ничего себе у тебя предложения...
Цитата
использовать поле МЕМО, вывод которого ДБГрид тоже не поддерживает. Т.е. его надо привязать к объекту мемо(тому который на форму кинуть можно).
Это твои фантазии... Точно так же, как и в любой другой контрол, в ячейку DBGrid-а можно вставить TMemo. Подробнее - здесь: НеОбычный TDBGrid
Итого, у тебя есть варианты: 1. Положить на форму TMemo и точно так же, как ты из базы вытягиваешь картинку в лежащий на форме TImage, в этот самый Memo сбрасывать текст из соотв. поля текущей записи. Это обычный текст, кстати... Просто
2. (предпочтительно) Воспользоваться TDBMemo, связать его с нужным полем в таблице, и за тебя это будет делать сам компонент (кстати, я прошляпил, надо было тебе и про TDBImage сразу сказать, точно так же - связал с полем и при перемещении по DBGrid-у изображение изменяется автоматически...) 3. Вставить Memo внутрь DBGrid-а.
Выбирай...
Какая у тебя Дельфи, скажи заодно, чтоб я хоть примерно знал, что есть в арсенале, а чего нету...