Добрый день уважаемые читатели!
Задача.
Имеется файл .xls, в котором несколько столбцов с названиями: дата, наименование рецепта, название компонента, с названием компонентов столбцов несколько. В столбце с наименованием рецепта беспорядочно записаны строки, в которых непосредственно содержатся наименования рецептов. Рецептов около десяти штук. Некоторые строки пустые. В соседних столбцах с названием компонентов, в ячейках, содержатся значения их массы. Один рецепт делается в несколько подходов, поэтому имеется столбец с названием "Цикл". Циклов-подходов на изготовление одного рецепта всегда бывает разное количество, иногда один цикл, иногда 6, иногда 57, поэтому и строк бывает разное количество. Требуется посчитать сумму массы компонентов по каждому рецепту. Записать макрос в данном случае не решит задачу, потому что каждый день количество циклов разное, соответственно и количество строк меняется, макрос же будет суммировать конкретные адреса ячеек. К тому же, создать макрос не даст тот факт, что название рецепта будет записано каждый раз в новую строку, потому что количество циклов неизвестно заранее...
Решение.
Для начала откроем файл:
uses
ComObj // это чтобы Excel открылся
procedure ButtonClick(Sender: TObject);
var
Excel: Variant;
j, k: integer;
s, s1, s2, s3, z: string;
const xlCellTypeLast=$000000B;
begin
Excel :=CreateoleObject('Excel.Application');
Excel.DisplayAlerts := false;
OpenDialog1.Filter:=' File MS Excel|*.xls;*.xlsx|';
if not OpenDialog.Execute then Exit;
Excel.Workbooks.Open(OpenDialog.FileName, False);
Прочитаем все строки в переменные:
j :=excel.ActiveCell.SpecialCells(xlCellTypeLast).Row;
k :=1;
while k<>j+1 do
begin
Запишем по столбцам:
s :=excel.cells[k, 1].value; // в первом столбце содержится дата
s1 :=excel.cells[k, 4].value;//в этом столбце наименование рецепта
s2 :=excel.cells[k, 6].value;//здесь масса первого компонента
s3 :=excel.cells[k, 7].value;//здесь масса второго компонента (остальные компоненты здесь не пишу, т.к. там просто меняется номер столбца)
z :=excel.cells[k, 3].value;//в третьем столбце строки с типами масс, нас интересует строка "Вес фактический"
inc(k);
if (z = 'Вес фактический') and (Pos(Combobox.Text, s1)<>0) //собираем только строки с фактическим весом, а в комбо-боксе запишем наименования наших рецептов (около 10 штук) и соберём их также
Поместим все, что собрали в StringGrid:
then begin
StringGrid.RowCount:=StringGrid.RowCount+1;
Stringgrid.cells[1,StringGrid.RowCount-1]:=s;
Stringgrid.cells[2,StringGrid.RowCount-1]:=s1;
Stringgrid.cells[3,StringGrid.RowCount-1]:=s2;
Stringgrid.cells[4,StringGrid.RowCount-1]:=s3;
и т.д.
Если в ячейке с массой пусто, проставим в неё ноль (это для выполнения суммирования в дальнейшем):
if Trim(StringGrid.Cells[3, StringGrid.RowCount-1])= '' then StringGrid.Cells[3, StringGrid.RowCount-1] := '0';
end;
Завершаем:
Excel.Workbooks.Close;
Excel.Quit;
Excel :=unassigned;
Это для пользователя программы полоса загрузки, чтобы не принял процесс зависшим:
ProgressBar.Position:=ProgressBar.Max;
В конце уведомление:
ShowMessage('Загрузка завершена!');
ProgressBar1.Position:= 0;
end;
Это если пожелаете кнопку очистки всех ячеек StringGrid: StringGrid.RowCount := 1;
Итак, мы получили все строки с искомым рецептом по фактическому весу, но теперь нам требуется суммировать значения масс всех циклов приготовления.
Для этого суммируем ячейки по каждому компоненту, удаляя повторяющиеся строки из столбца с названием рецепта:
procedure TForm.ButtonClick(Sender: TObject);
var
SumA, SumB, SumC, Sum1, Sum2, Sum3 : Real;
x, y : Integer;
begin
Пройдем двумя циклами:
for x:=1 to StringGrid.RowCount - 1 do
begin
for y:=x+1 to StringGrid.RowCount - 1 do
begin
if (StringGrid.Cells[2,x]) = (StringGrid.Cells[2,y]) then
begin //Если строки имеют одинаковое название, то :
Сохраним значение ячейки из столбца с компонентом в переменной:
Sum := 0;
Sum:= Sum+StrToFloat(StringGrid.Cells[3,x]);
//Проделаем для всех столбцов с компонентами.
Удаляем одинаковые строки в столбце с наименованием рецептов:
for z:= x to StringGrid.RowCount-2 do
StringGrid.Rows[z]:= StringGrid.Rows[z+1];
StringGrid.RowCount:= StringGrid.RowCount-1;
Прибавим сохраненное значение в оставшуюся после удаления строку:
Sum1 := 0;
Sum1:= Sum1+StrToFloat(StringGrid.Cells[3,x]);
StringGrid.Cells[3,x]:= FloatToStr(Sum+Sum1);
//Проделаем для всех столбцов с компонентами.
end;
Теперь нам надо сохранить посчитанное обратно в Excel :
procedure ButtonClick(Sender: TObject);
var
Excel, WorkBook, Sheet:variant;
i, j: integer;
FName: string;
begin
if SaveDialog.Execute then
FName := SaveDialog.FileName
else
Exit;
Excel:=CreateOleObject('Excel.Application');
Excel.DisplayAlerts:=False;
Excel.Visible:= False;
Workbook:=Excel.
Workbooks.Add;
Workbook.SaveAs(FName);
Sheet:= Workbook.ActiveSheet;
for i:= 0 to StringGrid.RowCount - 1 do
begin
for j:= 0 to StringGrid.ColCount - 1 do
Sheet.Cells[i+1, j+1]:= StringGrid1.Cells[j, i];
end;
Workbook.Save;
Workbook.Close;
Excel.Quit;
Excel:= UnAssigned;
MessageBox(Handle,'Экспорт данных завершен','Внимание!',0);
end;
Спасибо за прочтение, жду комментарии, вопросы и предложения. Подписывайтесь на мой канал, если пожелаете!