500+ FAQ по Delphi

Перейти на: Главную | Индексную | Предыдущую | Следующую страницу


Как добиться верной работы фильтра на запросах и на неиндексированных таблицах?

(Т.е. при работе программы наблюдалась следующая картина:
в результате очередной фильтрации оставалось видно 4 записи из восьми.
Добавляем букву к фильтру, остается, допустим, две.
Убираем букву, которую только что добавили, в гриде все равно видно только две записи)

Эта проблема была в Delphi 3.0 только на TQuery, а в Delphi 3.01 появилась и в TTable.

Лечится так (простой пример):

procedure TMainForm.Edit1Change(Sender: TObject);
begin
if length( Edit1.Text ) > 0 then
begin
Table1.Filtered := TRUE;
UpdateFilter( Table1 );
end
else
Table1.Filtered := FALSE;
end;

procedure TMainForm.UpdateFilter( DataSet: TDataSet );
var
FR: TFilterRecordEvent;
begin
with DataSet do
begin
FR := OnFilterRecord;
if Assigned(FR) and Active then
begin
DisableControls;
try
OnFilterRecord := nil;
OnFilterRecord := FR;
finally
EnableControls;
end;
end;
end;
end;

Pavel Krasikov
(2:5005/7)

Как получить результирующим полем разницу между хранимой датой и текущей датой?

SELECT CAST((поле_с_датой -"NOW") AS INTEGER) FROM MyBase
Получишь результат в днях.

Подскажите, как на Oracle 7.3.2.3 (Solaris x86) поменять compatible на 7.3.2.3 (c 7.1.0.0)?

Ставить в initmybase.ora
compatible = "7.3.2.3"
и после старта с новым параметром сделать
ALTER DATABASE RESET COMPABILITY;
И рестартовать базу.

Alexander Medvedev
(2:5010/3.88)

Как создать БД в кодировке CP1251?

Вот такая конструкция проходит на DB2 2.1.2/NT и UDB5/NT...

CREATE DATABASE Efes2
USING CODESET 1251 TERRITORY RU
COLLATE USING IDENTITY;

Можно ли использовать результаты выполнения одного TQuery для другого TQuery?

Если Вы работаете с локальными БД, то Вам поможет -
DbiMakePermanent( SourceQuery.Handle, RName, false );

В Delphi 3 и выше ползунок TDBGrid иногда может находится не только в трех фиксированных позициях. Что для этого нужно?

Здесь отрывки из исходников VCL -

unit DBGrids;

procedure TCustomDBGrid.UpdateScrollBar;
var
SIOld, SINew: TScrollInfo;
begin

[skipped]

if IsSequenced then

begin
SINew.nMin := 1;
SINew.nPage := Self.VisibleRowCount;
SINew.nMax := RecordCount + SINew.nPage -1;
if State in [dsInactive, dsBrowse, dsEdit] then
SINew.nPos := RecNo; // else keep old pos
end
else
begin
SINew.nMin := 0;
SINew.nPage := 0;
SINew.nMax := 4;
if BOF then SINew.nPos := 0
else if EOF then SINew.nPos := 4
else SINew.nPos := 2;
end;

[skipped]

unit dbtables;

function TBDEDataSet.IsSequenced: Boolean;
begin
Result := (FRecNoStatus = rnParadox) and (not Filtered);
end;

Ilya Andreev
(2:5030/55.28)

-----------

То есть, к примеру, все будет работать "красиво" на таблицах BDE, если они:

таблицы Paradox;
на них не установлен фильтр.
TClientDataSet в режиме single-tier (briefcase) также работает "красиво".

Как заставить произвольный компонент реагировать на изменения в TDataSource?

TFieldDataLink. За D2 не скажу, а в D1 в Help'е его нет, pеализован в \DELPHI\SOURCE\VCL\DBTABLES.PAS.

type
TMyForm = class(TForm)
{...}
Table1: TTable;
DataSource1: TDataSource;
private
FDL : TFieldDataLink;
procedure RecChange(Sender: TObject);
public
{...}
end;

procedure TMyForm.FormCreate(Sender: TObject);
begin
FDL:=TFieldDataLink.Create;
FDL.OnDataChange := RecChange;
FDL.DataSource := DataSource1;
FDL.FieldName := 'MyFieldName';
end;

procedure TTabEditDlg.FormDestroy(Sender: TObject);
begin
FDL.Free;
end;

procedure TTabEditDlg.MasterChange(Sender: TObject);
begin
{... тут pеагиpуй на изменения ...}
end;

Eugene Polkin
(2:5001/12.3)

-----------

За отслеживание различных событий, происходящих с TDataSource, в иерархии VCL отвечает класс TDataLink. TFieldDataLink - наследник, который выполняет маскирование событий, не относящихся к конкретному столбцу набора данных.
Если надо отслеживать изменения в любом столбце набора, используйте TDataLink. Если необходимо отслеживать события для некоторого подмножества строк набора данных, посмотрите на реализацию TGridDataLink.

Как поймать свой RAISEERROR в Delphi?

Отлавливать нужно NativeCode, напpимеp так:

procedure TFDMUtils.GeneralError( DataSet: TDataSet; E: EDatabaseError; var Action: TDataAction);
var
i: Word;
ExtInfo : String;
begin
ExtInfo := '';

if (E is EDBEngineError) then
begin
if ( EDBEngineError( E ).Errors[0].NativeError = 0 ) then
begin // Local Error
if EDBEngineError( E ).Errors[0].Errorcode = 9732 then
ExtInfo := DataSet.FieldByName( trim( copy( E.Message, 29, 20 ) ) ).DisplayLabel;
.............
end
else
begin // Remote SQL Server error
ExtInfo := ExtractFieldLabels( DataSet, E.Message );
case EDBEngineError( E ).Errors[0].NativeError of
233, 515 :
Alert( 'Ошибка', 'Hе все поля заполнены ! ' + ExtInfo );
547 :
if ( StrPos( PChar( E.Message ), PChar('DELETE' ) ) <> nil ) then
Alert('Ошибка пpи удалении', 'Имеются подчиненные записи, удаление (изменение) невозможно! ' + ExtInfo )
else
if ( StrPos( PChar( E.Message ), PChar( 'INSERT' ) ) <> nil ) then
Alert( 'Ошибка пpи вставке', 'Отсутствует запись в МАСТЕР-таблице! ' + ExtInfo )
else
if ( StrPos( PChar( E.Message ), PChar( 'UPDATE' )) <> nil ) then
Alert( 'Ошибка пpи обновлении', 'Отсутствует запись в МАСТЕР-таблице! ' + ExtInfo );
2601 :
Alert( 'Ошибка', 'Такая запись уже есть!' );
else
Alert( 'Ошибка', 'Hеизвестная ошибка, код - ' + inttostr( EDBEngineError( E ).Errors[0].NativeError ) + ExtInfo);
end;
end;
end;
end;

Этот код был заточен под MSSQL, но не нужно пытаться его использовать, а лучше по этому пpимеpу написать свою процедуру.

Sergey Gristchuk
gristchuk@usa.net
(2:463/209.31)

Как в TDBGrid pазpешить только опеpации UPDATE записей и запpетить INSERT/DELETE?

А я делаю так.

На DataSource, к которому прицеплен Grid, вешаю обработчик на событие OnStateChange.

Ниже текст типичного обратчика -

if DBGrid1.DataSource.DataSet.State in [dsEdit, dsInsert] then
DBGrid1.Options := DBGrid1.Options + goRowSelect
else
DBGrid1.Options := DBGrid1.Options - goRowSelect;

Дело в том, что если у Grid'а стоит опция goRowSelect, то из Grid'а невозможно добавить запись. Ну а когда програмно вызываешь редактирование или вставку, то курсор принимает обычный вид и все Ok.

Denis Kim
(2:5020/799.2)

------------

Лучше использовать конструкцию "State in dsEditModes"

Max Belugin
belugin@bsd.lanit.ru
(2:5020/484.28)

Как заставить работать DB2 через протокол IPX?

Связь Win-клиента c DB2 в сети Netware

Hастройка доступа к DB2

-------------

1. Связь с использованием протокола IPX/SPX.
Возможны два варианта доступа:

через сервер NETWARE;
прямая адресация.

-------------

1.1. Конфигурация для доступа через сервер.
Замечание: Проверялся доступ через сервера NW 3.11 и 3.12. Для 4.х нужно еще разобраться.

1.1.1. DB2 Сервер
- должна быть установлена OS/2 Warp или OS/2 Warp Connect;

- включена поддержка NETWARE;

- в CONFIG.SYS в переменную среды DB2COMM добавить (через запятую) IPXSPX и перезагрузить систему;

- создать командный файл DBIPXSET.CMD следующего вида:

|--------------------------------------
|db2 update dbm cfg using fileserver <NWSERVER> objectname dbserver
|--------------------------------------

где - <NWSERVER> - имя сервера;

- выполнить командный файл DBIPXSET.CMD;

- перестартовать сервер базы данных;

- создать командный файл DBIPXREG.CMD следующего вида:

|--------------------------------------
|db2 register nwbindery user <USERNAME>
|--------------------------------------

где - <USERNAME> - имя пользователя, обладающего правами администратора на сервере <NWSERVER> ;

- выполнить командный файл DBIPXREG.CMD;

- ответить на запрос пароля.

1.1.2. WINDOWS - клиент
- установить WINDOWS 3.1 или WfWG 3.11;

- установить клиента NETWARE от версии 4.х;

- при установке влючить поддержку WINDOWS;

- установить клиента DB2 для WINDOWS;

- используя программу Client Setup описать новый узел - сервер базы данных :

Name - <любое имя>
Protocol - IPX/SPX
File server - <NWSERVER>
Object name - dbserver

- описать базу данных и разрешить доступ к ней через ODBC.

------------

1.2. Конфигурация для доступа через прямую адресацию
1.2.1. DB2 Сервер
- см. п 1.1.1;

- найти в директории x:\sqllib\misc программу DB2IPXAD.EXE и выполнить ее;

- записать полученный адрес;

1.2.2. WINDOWS - клиент
- см. п. 1.1.2. (первые три шага);

- используя программу Client Setup описать новый узел - сервер базы данных :

Name - <любое имя>
Protocol - IPX/SPX
File server - *
Object name - <адрес полученный от DB2IPXAD.EXE>

- описать базу данных и разрешить доступ к ней через ODBC.

Sergei Babain
(2:5058/88.23)

Что нужно знать о принципе и порядке работы с TUpdateSQL для работы с неживыми запросами?

Кидаешь UpdateSQL на форму, после чего в том SQL, который ты собираешься редактировать, устанавливаешь в UpdateObject имя этого UpdateSQL. После этих дел по дабл-клику на UpdateSQL выдаётся редактор, в котором ты должен для каждой из таблиц,входящих в твой запрос, указать набор полей, являющихся уникальным ключём таблицы, и набор полей, которые требуется редактировать. В общем случае возможны глюки с редактированием, если в числе изменяемых полей будут элементы ключа. Указав все поля, давишь кнопку Generate SQL и в результате у тебя генерятся запросы на редактирование, добавление и удаление, которые прописываются в том же UpdateSQL. Обычно эти запросы никакого дополнительного редактирования не требуют. После всех этих дел ты можешь нормально редактировать запрос, как обычную таблицу.

Hекоторые моменты.

Для того, чтобы всё это нормально работало, нужно, чтобы в TQuery были включены RequestLive и CashedUpdates. Соответственно, для подтверждения изменений нужно вызывать TQuery.ApplyUpdates и TQuery.CommitUpdates, либо TDatabase.ApplyUpdates, а для отмены - CancelUpdates.

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

-- Отрезано --

Hасчёт CachedUpdates.

Сия хреновина придумана для того, чтобы обеспечить сохранение/отмену редактирования/добавления/удаления сразу нескольких записей. Принцип совершенно элементарен: если CachedUpdates включен, то все производимые изменения в датасете по команде Post фиксируются не в базе, а во временном файле на винте клиента. Для того, чтобы прописать изменения в таблице (физически), необходимо вызвать для соответствующего запроса последовательно методы ApplyUpdates и CommitUpdates, а для отмены ВСЕХ изменений (начиная от последнего выполненного CommitUpdates), вызвать CancelUpdates. Кроме того, метод ApplyUpdates у TDataBase. Этому методу нужен список датасетов, и он производит их обновление в одной транзакции.

Практическое применение, например, такое: на форме редактирования с гридом и набором кнопок Добавить, Удалить, Редактировать, ОК, Отмена, вешаешь на первые три кнопки обработчики с Insert, Delete и Edit соответственно,
на ОК - такой примерно обработчик:

with DataSet do begin
if State in [dsEdit,dsInsert] then Post;
ApplyUpdates;
CommitUpdates;
end;

а на Отмену такой:

with DataSet do begin
if State in [dsEdit,dsInsert] then Cancel;
CancelUpdates;
end;

В результате юзер может редактировать хоть всю таблицу, но если успеет спохватиться, то может отменить все свои художества. Только желательно на выходе из формы проверить, сохранены ли изменения,и если нет, то напомнить/переспросить.


Ivan Kudryashov

jony@chat.ru

--------------

Лучше использовать конструкцию "State in dsEditModes"

Max Belugin
belugin@bsd.lanit.ru
(2:5020/484.28)

При выполнении некоторых живых запросов, возвращающих единственную запись, BDE ругается "multiple records found, but only one was expected". Как лечить?

Запросы вида

SELECT c, b, a, q FROM T WHERE b = :b,

где ключ c, но BDE посчитала ключом a. Интересный запрос, да? Такое впечатление, что, поскольку ключом в исходной таблице являлась третья колонка, то Дельфы посчитали ключом третью колонку.

Перестановкой SELECT a, b, c, q... все исправилось. Я решил теперь использовать в таких (live) запросах только SELECT *.

Victor V. Metelitsa
(2:5077/13)

При попытке регистрации UDF возникает ошибка (udf not defined). Что не так?

1) Располагайте DLL в каталоге Interbase/Bin, или в одном из каталогов, в которых ОС обязательно будет произведен поиск этой библиотеки (для Windows это %SystemRoot% и %Path%);

2) При декларировании функции не следует указывать расширение модуля (в Windows по умолчанию DLL):

declare external function f_SubStr
cstring(254), integer, integer
returns
cstring(254)
entry_point "Substr" module_name "UDF1"

Где UDF1 - UDF1.DLL.

Alexey Malinin
(2:5057/19.18)


Материалы находятся на сайте http://cracklab.narod.ru/faq/


Создатель этого HTML файла не претендует на авторство вопросов/ответов представленных в нём, не отвечает за их содержание и достоверность, а также за последствия использования программных кодов , полученных из этого HTML файла. Также не принимаются претензии относительно не размещённой информации об авторе каждого конкретного FAQ'а. Любые другие вопросы присылайте на bad_guy@cracklab.ru (обращаться к Bad_guy'ю).
Hosted by uCoz