Lazarus: DBGrid показывает "(MEMO)" в качестве значения строковых полей в SQLite 3

Я пытаюсь написать простое приложение на SQLite 3, используя Lazarus и компоненты SQLdb.

Мне удалось подключиться к базе данных и заполнить TDBGrid, Проблема заключается в том, что все столбцы, являющиеся текстовыми полями, отображают значение "(MEMO)", а не строку в БД.

13 ответов

Я нашел простое решение:

Недвижимость dgDisplayMemoText от DBGrid должен быть включен.

Я забыл источник этого, но это то, что я делаю с мемо-полями в tdbgrid. bluish прав насчет события gettext, вот как реализовать его в коде:

Создайте класс с именем MemoDifier:

MemoDifier = class
  public
    procedure DBGridOnGetText(Sender: TField; var aText: string;
      DisplayText: boolean);
  end;                  

В разделе реализации вашего кода, поместите это:

procedure MemoDifier.DBGridOnGetText(Sender: TField; var aText: string;
  DisplayText: boolean);
begin
  if (DisplayText) then
    aText := Sender.AsString;
end; 

Затем щелкните элемент управления tdbgrid в своей форме и в инспекторе объектов(Lazarus IDE) перейдите на вкладку "События" и прокрутите ниже, чтобы найти событие OnPrepareCanvas. Дважды щелкните по нему, чтобы сгенерировать код. Затем измените код в соответствии с вашими потребностями, такими как имя вашего элемента управления tdbgrid:

procedure Tmainui.TDBGrid1PrepareCanvas(sender: TObject;
  DataCol: Integer; Column: TColumn; AState: TGridDrawState);
var
  MemoFieldReveal: MemoDifier;
begin
   if (DataCol = 1) then
   begin
     try
       TDBGrid1.Columns.Items[0].Field.OnGetText := @MemoFieldReveal.DBGridOnGetText;
       TDBGrid1.Columns.Items[1].Field.OnGetText := @MemoFieldReveal.DBGridOnGetText;
       TDBGrid1.Columns.Items[2].Field.OnGetText := @MemoFieldReveal.DBGridOnGetText;
     except
       On E: Exception do
       begin
         ShowMessage('Exception caught : ' + E.Message);
       end;
     end;
   end;
end; 

Переменная MemoFieldReveal указывает на класс MemoDifier. Не забудьте изменить индекс (Items[x]), чтобы он указывал на ваш индексный номер элементов / полей tdbgrid, в котором отображается текст (MEMO).

Старый вопрос, но я столкнулся с ним, когда искал аналогичную проблему, но с данными, полученными с помощью кода, а не с помощью DBGrid; Когда я получил строковые поля с помощью методов или же , я получил "(memo)" вместо правильного значения.

Ответ на самом деле прост… Класс TSQLQuery владеет набором методов, называемых чтобы получить данные в соответствии с типом данных. Здесь используйте AsString, чтобы назначить встроенную переменную.

      SQLQuery1.Open;
//some check to make sure there are fields
name:=SQLQuery1.Fields[1].AsString;   //gives "English" for example
code:=SQLQuery1.Fields[2].DisplayText;   //gives "(Memo) instead of "en"

Более того, если во время разработки вы не знаете, к какому типу относится переменная (например, вы хотите разработать общую функцию для любого типа таблицы), вам может помочь ее свойство FieldDefs вашего объекта TSqlQuery. Он владеет свойством DataType, которое позволяет выбирать, какую функцию AsXxx использовать. Вот например.

      SQLQuery1.Open;
//some check to make sure there are fields
with SQLQuery1.FieldDefs[1].DataType of
  ftMemo: SQLQuery1.Fields[1].DisplayText;        //gives "(Memo)"
  ftString: name:=SQLQuery1.Fields[1].AsString;  //gives "English" for example
...
end;

И если вы посмотрите на тип данных во время отладки, вы заметите, что с SQLite любой текст рассматривается как ftMemo, а не ftString, поскольку там есть только один тип текста.

Мемо поля не могут быть показаны в TDBGrid, добавлять TDBMemo к форме и подключить его к тому же TDataSource, В этом случае вы увидите текст в своей записке.

Другой вариант

Если вы используете TZConection, добавьте эту строку в свой код при подключении к базе данных

TZConnection).Properties.Add('Undefined_Varchar_AsString_Length=100'); 

У меня то же самое в MySQL и Tgrid, поэтому я надеюсь, что ответ такой же, как он довольно прост:-)

Скажите, если s это поле, вызывающее проблему, то вместо записи

SELECT s

записывать

SELECT LEFT(s,200) AS s 

Вы также можете просто использовать TRIM в своем sql:

      SELECT TRIM(myfield) as NewField

Этот трюк также работает в Lazarus.

после некоторых тестов я мог видеть, что, хотя поля обрабатываются как «MEMO», для «строковых» полей просто сохраните параметр «VARCHAR» вместо «TEXT» при создании таблицы.

Как сказано в IRC, вам, вероятно, нужно добавить поля формы в форму запроса (чтобы для них были созданы "полевые" компоненты), а затем реализовать TMemoField.GetText событие.

Посмотрите, если при вводе поля "fields" в инспекторе объектов открывается редактор для генерации компонентов (это происходит в Zeos iirc).

Очевидно, простое решение - ограничить длину ТЕКСТА в поле, используя что-то вроде VARCHAR(n) в типе столбца, где n - максимальное количество разрешенных символов.

В довольно старой ветке форума я нашел подходящее мне решение (немецкий / английский):

SqLite, Zeos und keine Textanzeige, im DbGrid steht (MEMO) - Портал Zeoslib

Если вы измените типы полей в базе данных SQLite с text в varcharтекст отображается, как и ожидалось в TDBGrid,

изменение столбцов SQLite

Как вы, возможно, знаете, SQLite не позволяет вам изменять типы полей столбцов. Итак, если у вас уже есть ценные данные, хранящиеся в базе данных, используйте шаги, описанные в этом руководстве

SQLite ALTER TABLE и как преодолеть его ограничения

Вот еще один вариант

  • создать дамп (sqlite3 your.db .dump >your.sql)
  • изменить определения таблицы в результирующем sql (st как s/\<text\>/varchar/)
  • импортировать в новую базу данных (sqlite3 your2.db <your.sql)
  • поменять местами старые и новые базы данных

Если база данных Oracle, измените Tquery и добавьте строку выбора.... cast(field as varchar2(100) as field....

Эта статья предлагает решение: отображение и редактирование полей MEMO в TDBGrid от Delphi.

Здесь я суммирую, что вы должны сделать:

  • в.dfm добавить OnGetText = MyDataSetMyFieldGetText к TMemoField (здесь назван MyField) принадлежность к вашему набору данных (например, TTableздесь названный MyDataSet)
  • в.pas> interface > type > внутри определения формы добавьте

    procedure MyDataSetMyFieldGetText(Sender: TField; var Text: string; DisplayText: Boolean);
    
  • в.pas> implementation > добавить этот метод

    procedure TDM.WorkVisiteNoteGetText(Sender: TField; var Text: string; DisplayText: Boolean);
    begin
      Text := Copy(WorkVisiteNote.AsString, 1, 100);
    end;
    
Другие вопросы по тегам