#database #delphi #dbgrid
#База данных #delphi #dbgrid
Вопрос:
Мне нужна помощь в устранении проблемы с моей базой данных. У меня есть файл .mdb, который содержит записи автомобилей. Это связано с моей ADOTable, а затем с DBGrid в Delphi. Когда я удаляю записи с помощью кнопки в моей форме, кажется, что она не удаляет ее должным образом, потому что, когда я прокручиваю dbgrid, предполагается, что активная запись изменяется / обновляется (зависит от того, прокручиваю ли я вниз или вверх) и отображает значение каждого поля активной записи в edits нижеDBGrid.
После того, как мой код удалил запись, она не отображается ни в DBGrid, ни в mdb-файле, когда я просматриваю ее в MS Access, поэтому я предположил, что она была удалена правильно. Но, как я объяснил выше, когда событие OnMouseWheel завершается, оно отображает, как я полагаю, либо удаленную запись, либо данные предыдущей записи, когда указатель на активную запись DBGrid четко показывает, что она должна отображать данные следующей или предыдущей записей.
Интересно отметить, что кнопки OnCellClick и DBGridNavigator не оказывают такого влияния на DBGrid и отображаемую информацию о записи.
Изображения:
Каждое изображение после 1 исключения:
Изображение фактического MDB-файла:
Код для используемых процедур и функций:
OnMouseWheel:
procedure TCars.DBGrid1MouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer;
MousePos: TPoint; var Handled: Boolean);
begin
Show_Car_Details;
end;
OnCellClick:
procedure TCars.DBGrid1CellClick(Column: TColumn);
begin
Show_Car_Details;
end;
Show_Car_Details:
procedure TCars.Show_Car_Details;
begin
with CarOwners.tbl_Cars do
begin
edt_Car_ID.text := inttostr(fieldbyname('ID').value);
edt_Car_Type.text := fieldbyname('Make').value;
edt_Car_Price.text := FloatToStr(fieldbyname('Price').value);
edt_Car_Distance.text := inttostr(fieldbyname('Distance').value);
edt_Owner_ID.text := inttostr(fieldbyname('OwnerID').value);
if fieldbyname('Insurance').value = true then
begin
cbx_Insurance.ItemIndex := 0;
end
else
begin
cbx_Insurance.ItemIndex := 1;
end;
end;
end;
Процедура удаления:
procedure TCars.bit_DeleteClick(Sender: TObject);
begin
if messagedlg
('Are you sure you want to delete this record? It will permanently be removed.',
mtConfirmation, [mbyes, mbno], 0) <> mryes then
exit;
CarOwners.tbl_Cars.Delete;
DBGrid1.DataSource.DataSet.Refresh;
end;
Просто добавьте код для процедур добавления и обновления:
Add:
procedure TCars.bit_AddClick(Sender: TObject);
var
Make: string;
OwnerID, Distance: Integer;
Price: real;
Insurance: Boolean;
begin
Make := edt_Car_Type.text;
OwnerID := strtoint(edt_Owner_ID.text);
Distance := strtoint(edt_Car_Distance.text);
Price := strtofloat(edt_Car_Price.text);
if cbx_Insurance.ItemIndex = 0 then
begin
Insurance := true;
end
else
begin
Insurance := false;
end;
Add_Record(Make, OwnerID, Price, Distance, Insurance);
end;
//---------------------------------------------------------
procedure TCars.Add_Record(Make: string; OwnerID: Integer; Price: real;
Distance: Integer; Insurance: Boolean);
begin
// ----validation----
//validation done here(removed for space, just basic if with exit.)
// add new information
with CarOwners do
begin
tbl_Cars.DisableControls;
tbl_Cars.last;
tbl_Cars.Insert;
tbl_Cars['Make'] := Make;
tbl_Cars['OwnerID'] := OwnerID;
tbl_Cars['Price'] := Price;
tbl_Cars['distance'] := Distance;
tbl_Cars['Insurance'] := Insurance;
tbl_Cars.post;
tbl_Cars.EnableControls;
end;
end;
Процедура обновления:
procedure TCars.bit_UpdateClick(Sender: TObject);
var
Brand: string;
Price: real;
Insurance: Boolean;
OwnerID, Distance: Integer;
begin
Brand := edt_Car_Type.text;
Price := strtofloat(edt_Car_Price.text);
OwnerID := strtoint(edt_Owner_ID.text);
Distance := strtoint(edt_Car_Distance.text);
if cbx_Insurance.ItemIndex = 0 then
begin
Insurance := true;
end
else
begin
Insurance := false;
end;
Update_Record(Brand, OwnerID, Price, Distance, Insurance);
end;
//------------------------------------------------------------
procedure TCars.Update_Record(Make: string; OwnerID: Integer; Price: real;
Distance: Integer; Insurance: Boolean);
begin
//validation done here(removed for space, just basic if with exit.)
// ----Update Information ----
with CarOwners do
begin
tbl_Cars.DisableControls;
tbl_Cars.edit;
tbl_Cars['Make'] := Make;
tbl_Cars['OwnerID'] := OwnerID;
tbl_Cars['Price'] := Price;
tbl_Cars['Distance'] := Distance;
if Insurance then
begin
tbl_Cars['Insurance'] := true;
end
else
begin
tbl_Cars['Insurance'] := false;
end;
// ShowMessage('Posting...');
tbl_Cars.post;
// ShowMessage('Done');
tbl_Cars.EnableControls;
end;
end;
Любые советы или помощь приветствуются!!!
С уважением
Комментарии:
1. Вы должны связать свои поля непосредственно с источником данных.
2. Вы также можете использовать событие onDataChange для обновления полей.
3. «Извините, я подумал, что это бесполезная информация относительно моего вопроса и проблемы». Совсем нет. Фактически это объясняет, почему ваш код кажется написанным без какого-либо учета того, как правильно писать приложения с поддержкой Delphi db. Скажите своему преподавателю, что вам не нужно использовать TEdits вместо TDBEdits только для проверки. Вы можете использовать событие OnValidate TField для проверки отдельных полей и событие TDataSet Before Post для проверки между полями…
4. «вы не могли бы объяснить, как это решит мою проблему»
MouseWheel
Событие не является подходящим местом для обновления элементов управления полями. Если метод вызывается до того, как событие обрабатывается сеткой, то в конечном итоге отображается предыдущая запись.5. @Olivier: Отличное объяснение! Я думаю, что OP должен больше времени слушать вас и меньше своего инструктора.
Ответ №1:
Спасибо @MartynA и @Olivier за ответ. Проблема заключалась в использовании неправильного обработчика событий для обновления и отображения значений полей записи.
НЕ ИСПОЛЬЗУЙТЕ: OnMouseWheel
ИСПОЛЬЗОВАНИЕ:
procedure TCarOwners.ds_CarsDataChange(Sender: TObject; Field: TField);
begin
if Field = nil then
begin
Cars.show_car_details;
end;
end;
Это правильно обновляет элементы управления, не связанные с данными. Обязательно добавьте Form1
или в моем случае Cars_frm
в uses
список непосредственно под implementation
.
Комментарии:
1. В более общем случае, когда требуемое поведение связано с данными в наборе данных, используйте события TDataSet и его потомков, таких как TADODataSet и TField, а не события в графическом интерфейсе, чтобы получить желаемое поведение.