1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
unit Unit5; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DB, ADODB, Grids, DBGrids, StdCtrls, ComObj; type TForm1 = class(TForm) Button1: TButton; Button3: TButton; Label1: TLabel; OpenDialog1: TOpenDialog; Edit1: TEdit; Label2: TLabel; StringGrid1: TStringGrid; Label3: TLabel; Edit2: TEdit; Button2: TButton; procedure OpenDialog1CanClose(Sender: TObject; var CanClose: Boolean); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure Button1Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); private { Private declarations } public { Public declarations } end; var Form1: TForm1; Excel: Variant; implementation procedure Xls_Open(XLSFile:string; Grid:TStringGrid); const xlCellTypeLastCell = $0000000B; var ExlApp, Sheet: OLEVariant; i, j, r, c:integer; begin //создаем объект Excel ExlApp := CreateOleObject('Excel.Application'); //делаем окно Excel невидимым ExlApp.Visible := false; //открываем файл XLSFile ExlApp.Workbooks.Open(XLSFile); //создаем объект Sheet(страница) и указываем номер листа (1) //в книге, с которого будем осуществлять чтение Sheet := ExlApp.Workbooks[ExtractFileName(XLSFile)].WorkSheets[1]; //активируем последнюю ячейку на листе Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate; // Возвращает номер последней строки r := ExlApp.ActiveCell.Row; // Возвращает номер последнего столбца c := ExlApp.ActiveCell.Column; //устанавливаем кол-во столбцов и строк в StringGrid Grid.RowCount:=2; //по умолчанию 2 строки Grid.ColCount:=c; //заполняем шапку таблицы (наименование полей) for i:= 1 to c do Grid.Cells[i-1,0]:= sheet.cells[1,i]; //считываем значение из каждой ячейки и проверяем на совпадение по 5 столбцу (должность) for j:= 1 to r do //собственно сравниваем наш критерий со значением в Excel //функция trim убирает все лишние пробелы в строке т.е. пробелы перед и после текста //функция lowercase возвращает строку в нижнем регистре. uppercase - в верхнем регистре begin //если значения совпали то заносим его в таблицу grid. Не забываем что в объекте Excel нумерация строк и столбцов с 1, в Grid c 0 for i:= 1 to c do Grid.Cells[i-1,grid.RowCount-1]:= sheet.cells[j,i]; grid.RowCount:=grid.RowCount+1; //добавляем пустую строку в grid. end; //закрываем приложение Excel ExlApp.Quit; //очищаем выделенную память ExlApp := Unassigned; Sheet := Unassigned; end; {$R *.dfm} procedure TForm1.OpenDialog1CanClose(Sender: TObject; var CanClose: Boolean); begin with OpenDialog1 do if Execute then Excel.Application.WorkBooks.Add(FileName); end; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin try Excel.Quit; except end; CanClose:=True; end; procedure TForm1.Button1Click(Sender: TObject); begin If OpenDialog1.Execute then Xls_Open (OpenDialog1.FileName, StringGrid1); end; procedure Xls_Open_filter(XLSFile:string; Grid:TStringGrid; criterion1,criterion2:string); const xlCellTypeLastCell = $0000000B; var ExlApp, Sheet: OLEVariant; i, j, r, c:integer; begin //создаем объект Excel ExlApp := CreateOleObject('Excel.Application'); //делаем окно Excel невидимым ExlApp.Visible := false; //открываем файл XLSFile ExlApp.Workbooks.Open(XLSFile); //создаем объект Sheet(страница) и указываем номер листа (1) //в книге, с которого будем осуществлять чтение Sheet := ExlApp.Workbooks[ExtractFileName(XLSFile)].WorkSheets[1]; //активируем последнюю ячейку на листе Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate; // Возвращает номер последней строки r := ExlApp.ActiveCell.Row; // Возвращает номер последнего столбца c := ExlApp.ActiveCell.Column; //устанавливаем кол-во столбцов и строк в StringGrid Grid.RowCount:=2; //по умолчанию 2 строки Grid.ColCount:=c; //заполняем шапку таблицы (наименование полей) for i:= 1 to c do Grid.Cells[i-1,0]:= sheet.cells[1,i]; //считываем значение из каждой ячейки и проверяем на совпадение по 3 столбцу (Номер документа) for j:= 1 to r do //собственно сравниваем наш критерий со значением в Excel //функция trim убирает все лишние пробелы в строке т.е. пробелы перед и после текста //функция lowercase возвращает строку в нижнем регистре. uppercase - в верхнем регистре if (trim (lowercase(sheet.cells[j,4]))=trim(lowercase(criterion1))) or (trim (lowercase(sheet.cells[j,8]))=trim(lowercase(criterion2))) then begin //если значения совпали то заносим его в таблицу grid. Не забываем что в объекте Excel нумерация строк и столбцов в Excel 1, в Grid c 0 for i:= 1 to c do Grid.Cells[i-1,grid.RowCount-1]:= sheet.cells[j,i]; sl:TstringList; .. sl:=TstrtingList.Create; if sl.IndexOf(sheet.cells[j,i])>-1 then // увеличить на 1 else sl.add(sheet.cells[j,i]) // добавили строку grid.RowCount:=grid.RowCount+1; //добавляем пустую строку в grid. end; //закрываем приложение Excel ExlApp.Quit; //очищаем выделенную память ExlApp := Unassigned; Sheet := Unassigned; end; procedure TForm1.Button3Click(Sender: TObject); begin If OpenDialog1.Execute then Xls_Open_filter (OpenDialog1.FileName, StringGrid1, Edit1.Text, Edit2.Text); end; procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); const //здесь определяем ваш цвет. Так же можно использовать цвета по умолчанию. clPaleGreen = TColor($CCFFCC); clPaleRed = TColor($CCCCFF); begin //Если ячейка получает фокус,то нам надо закрасить её другими цветами if (gdFocused in State) then begin StringGrid1.Canvas.Brush.Color := clBlack; StringGrid1.Canvas.Font.Color := clWhite; end else //Если же ячейка теряет фокус,то закрашиваем её коасным и зелёным. if (ACol=7) or(ACol=3) then //Восьмая ячейка будет зелёной,другие - ячейки красные StringGrid1.Canvas.Brush.color := clPaleGreen else StringGrid1.canvas.brush.Color := clPaleRed; //Теперь закрвсим ячйки,но только,если ячейка не Title- Row/Column //Естественно это зависит от того,есть у вас title-Row/Columns ??? ???. if (ACol > 0) and (ARow > 0) then begin //Закрашиваем бэкграунд StringGrid1.Canvas.FillRect(Rect); //Закрашиваем текст (Text). Так же здесь можно добавить выравнивание и т.д.. StringGrid1.Canvas.TextOut(Rect.Left, Rect.Top, StringGrid1.Cells[ACol, ARow]); end; end; end. end. end. |
DBGrid — кнопка фильтра как в Excel
Модератор: Модераторы
DBGrid — кнопка фильтра как в Excel
Здравствуйте.
Начал разбираться с Lazarus, так как Excel уже не подходит для задач, но хотелось бы перенести плюшки.
Как бы добавить к каждому столбцу кнопку фильтр, чтобы при нажатии появлялось окошко, в которое можно ввести часть текста и в отфильтрованном списке можно было бы выбрать варианты (или при нажатии Enter сразу бы фильтровалось по тому, что уже нашлось)? При этом нужно учитывать фильтры других столбцов
- alegzz
- незнакомец
- Сообщения: 4
- Зарегистрирован: 15.03.2017 19:57:59
Re: DBGrid — кнопка фильтра как в Excel
Deimos » 15.03.2017 22:26:51
Буду удивлен, если буду не прав, но эта хотелка из разряда МНОГО своего кода. Для БД смотреть LIKE и локальный (самодельный) поиск по гридам. Я копал-бы в эту сторону…
- Deimos
- постоялец
- Сообщения: 166
- Зарегистрирован: 17.01.2010 00:31:30
-
- Профиль
- ICQ
Re: DBGrid — кнопка фильтра как в Excel
olegy123 » 16.03.2017 10:23:36
Вам никто не может предоставить «кнопки как в Excel-е», кроме как в самом Excel-е.. Майкрософт придумала данный компонент, включила функционал для удобства своих клиентов, и то не сразу.
Это их фишичка.. на который вы подсели..
Хотя не все так печально. Есть компоненты которые предоставляют похожий функционал:
http://www.ehlib.com
https://www.devexpress.com/
http://www.tmssoftware.com/
и др..
можно тут, крупная база компонентов, поискать
http://torry.net/
вообще если вы умеете делать визуальные компоненты — то за один вечер вы сможете нарисовать кнопку.. Ну нужен опыт.
- olegy123
- долгожитель
- Сообщения: 1643
- Зарегистрирован: 25.02.2016 12:10:20
Re: DBGrid — кнопка фильтра как в Excel
Nick74 » 16.03.2017 11:51:36
И ждут вас на этом пути многие овраги и ямы… ))
У меня в программе (Правда на Дельфи, но смысл один) используется похожее.
Использую компоненты EhLib. Там есть очень похожий на Excel-ный фильтр, но с ограниченным функционалом, в основном хорошо работающий локально в памяти. Никакие визуальные компоненты править/писать не придется.
Но для таблицы в 30 строк все это лишнее, зато когда в таблице 50000 строк (Хотя бы), или, не дай бог, пара миллионов строк, все это начинает ощутимо подтормаживать (Дико тормозить), приходится переносить фильтры в SQL запрос, а это требует парсинга SQL-запроса, чтобы вставить в него нужные where/having и т.д. и т.п.
Впрочем у меня это все писалось в крайне общем случае для сферической лошади, возможно у вас все это будет сильно проще.
P.S. У меня был EhLib 5.6/6.0, сейчас смотрю есть уже 9-й, правда дико дорогой. А вдруг там уже все это сделали и ничего делать не надо вообще (Помечтал немножко…)
- Nick74
- новенький
- Сообщения: 25
- Зарегистрирован: 15.03.2017 13:55:06
- Откуда: Москва
Re: DBGrid — кнопка фильтра как в Excel
java73 » 16.03.2017 11:56:22
А в RXDGGrid случаем нет подобного? Итоговые всякие строки как в «умных» таблицах там есть, я использую. А фильтр скорее всего придется писать самому, т.к. это же разные компоненты — таблица только за внешнее отображение отвечает, а фильтруется уже сама таблица БД через SQL запросы…
- java73
- постоялец
- Сообщения: 257
- Зарегистрирован: 21.11.2013 09:08:10
Re: DBGrid — кнопка фильтра как в Excel
alegzz » 16.03.2017 13:45:10
мне бы понять, как рюшечки делать: запихнуть значок фильтр к столбцам и нарисовать окошко. обработку по-любому писать, так как там связанные таблицы. а то я сейчас даже смотрю на DBGrid и в печали: края не прилипают к краям формы…
- alegzz
- незнакомец
- Сообщения: 4
- Зарегистрирован: 15.03.2017 19:57:59
Re: DBGrid — кнопка фильтра как в Excel
java73 » 16.03.2017 13:57:14
Края к форме — привязку надо в редакторе anchors поставить и все будет прилипать, или align свойство
- java73
- постоялец
- Сообщения: 257
- Зарегистрирован: 21.11.2013 09:08:10
Re: DBGrid — кнопка фильтра как в Excel
serbod » 16.03.2017 14:02:44
Быстрый фильтр/сортировка в памяти делается очень просто — для отображения используется вторичная (виртуальная) таблица, которая не содержит данных, только ссылки на элементы первичной (реальной) таблицы. При изменении условия фильтра/сортировки нужно перезаполнить вторичную таблицу, это может занять ощутимое время (около секунды для миллиона строк), но зато скроллинг и прочие манипуляции пользователя тормозить не будут.
-
serbod - постоялец
- Сообщения: 449
- Зарегистрирован: 16.09.2016 11:03:02
- Откуда: Минск
-
- Профиль
- Сайт
Re: DBGrid — кнопка фильтра как в Excel
alegzz » 16.03.2017 17:06:12
serbod сделать еще один dbgrid? а в колонках как можно добавить иконку фильтра? стандартный компонент работы с MySQL какой-то убогий — при любой проблеме все падает, есть смысл с zeos заморочиться или есть что лучше?
- alegzz
- незнакомец
- Сообщения: 4
- Зарегистрирован: 15.03.2017 19:57:59
Re: DBGrid — кнопка фильтра как в Excel
serbod » 16.03.2017 17:48:11
alegzz писал(а):сделать еще один dbgrid?
Боюсь, вы неправильно меня поняли. Поправочка — все просто, если вы умеете работать с реальными и виртуальными датасетами. А если хочется готовое, то выше накидали ссылок с компонентами. Они наверняка платные, но тут либо долго учиться и делать все самому, либо платить и получать результат сразу.
-
serbod - постоялец
- Сообщения: 449
- Зарегистрирован: 16.09.2016 11:03:02
- Откуда: Минск
-
- Профиль
- Сайт
Re: DBGrid — кнопка фильтра как в Excel
alegzz » 16.03.2017 18:34:05
serbod, вроде понял — смутило то, что речь про таблицы шла. осталось попробовать. а по рюшечкам где посмотреть?
- alegzz
- незнакомец
- Сообщения: 4
- Зарегистрирован: 15.03.2017 19:57:59
Re: DBGrid — кнопка фильтра как в Excel
svk12 » 16.03.2017 21:36:29
java73 писал(а):А в RXDGGrid случаем нет подобного?
Есть!
- svk12
- постоялец
- Сообщения: 389
- Зарегистрирован: 09.06.2008 18:42:47
Re: DBGrid — кнопка фильтра как в Excel
java73 » 17.03.2017 09:26:48
Вон сколько экстра-свойств есть у RxDBGrid, там это можно прикрутить я так думаю!
- java73
- постоялец
- Сообщения: 257
- Зарегистрирован: 21.11.2013 09:08:10
Вернуться в Lazarus
Кто сейчас на конференции
Сейчас этот форум просматривают: Google [Bot] и гости: 21
Here is my little test application that produces an Excel 2007 XLSX file:
uses
Excel2007;
function CreateExportExcelWorkbook(AApp: ExcelApplication; ALCID: Integer): ExcelWorkbook;
var
OldDefaultSaveFormat: XlFileFormat;
begin
OldDefaultSaveFormat := AApp.DefaultSaveFormat;
AApp.DefaultSaveFormat := xlOpenXMLWorkbook;
try
Result := AApp.Workbooks.Add(xlWBATWorksheet, ALCID);
finally
AApp.DefaultSaveFormat := OldDefaultSaveFormat;
end;
end;
procedure FixTopRows(AApp: ExcelApplication; ARowCount: Integer);
var
ActiveWindow: Window;
begin
ActiveWindow := AApp.ActiveWindow;
ActiveWindow.SplitColumn := 0;
ActiveWindow.SplitRow := ARowCount;
ActiveWindow.FreezePanes := True;
end;
procedure TForm1.Button1Click(Sender: TObject);
const
cRowCount = 200;
cColCount = 10;
var
LCID: Integer;
ExcelApp: ExcelApplication;
Workbook: ExcelWorkbook;
Worksheet: ExcelWorksheet;
i, j: Integer;
FVarArray: Variant;
Cell1, Range: ExcelRange;
begin
LCID := GetUserDefaultLCID;
ExcelApp := CoExcelApplication.Create;
try
ExcelApp.Visible[LCID] := False;
ExcelApp.UserControl := False;
ExcelApp.DisplayAlerts[LCID] := False;
Workbook := CreateExportExcelWorkbook(ExcelApp, LCID);
Worksheet := Workbook.Worksheets.Item[1] as ExcelWorksheet;
FVarArray := VarArrayCreate([0, cRowCount - 1, 0, cColCount - 1], varVariant);
for j := 0 to cColCount - 1 do
FVarArray[0, j] := Format('Column %d', [j]);
for i := 1 to cRowCount - 1 do
for j := 0 to cColCount - 1 do
FVarArray[i, j] := 100 * i + j;
Cell1 := Worksheet.Cells.Range['A1', 'A1'];
Range := Worksheet.Range[Cell1, Cell1.Offset[cRowCount - 1, cColCount - 1]];
Range.Value[EmptyParam] := FVarArray;
VarClear(FVarArray);
Range.EntireColumn.AutoFit;
FixTopRows(ExcelApp, 1);
Range := Worksheet.Range[Cell1, Cell1.Offset[0, cColCount - 1]];
//Range := Cell1.EntireRow;
//Range.AutoFilter(1, 'All', EmptyParam, EmptyParam, True);
Workbook.SaveAs(ExpandFileName('test.xlsx'), EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
xlNoChange, EmptyParam, False, EmptyParam, EmptyParam, EmptyParam, LCID);
finally
ExcelApp.Quit;
end;
end;
Unit Excel2007
is the imported Excel 2007 type library. This works fine so far. However I would like to make the header row auto-filtered like in this screenshot:
Unfortunately all my attempts to do this via OLE automation resulted in OLE or Variant exceptions. Any idea how I should proceed?
NB: The data shouldn’t be filtered — I just want the drop-down buttons.
Продолжаем работу с базами данных. На этот раз, хотел бы рассмотреть фильтрацию данных в БД. Вообще, хотелось бы поговорить, для чего она предназначена, а также способы фильтрации данных, другими словами поиска данных в БД, с использованием технологии ADO.
Как, я уже говорил, на мой взгляд, фильтрация данных – это, грубо говоря, поиск данных. Но фильтрация данных проходит гораздо быстрее, чем обычный поиск по всей БД, с перебором каждой записи.
Давайте в этой статье и рассмотрим, как быстро можно осуществлять поиск данных, даже если БД имеет большой объем.
Ну, как я уже говорил, это фильтрация данных, кроме этого можно поиск организовать с помощью sql-запросов и с помощью функции Locate. Не забываем, что сейчас мы разговариваем про технологию ADO.
Давайте вернемся к нашему проекту, на форме у меня следующие компоненты:
- TADOConnection
- TADOQuery
- TDBGrid
- TButton
- TDataSource
Создадим в MS Access произвольную базу данных и таблицу в ней. У меня она получилась, следующей структуры:
Теперь необходимо сделать подключение к нашей БД, как это делать, мы рассматривали в данной статье, а также необходимо связать между собой компоненты. Для этого, выделяем компонент TADOQuery и в свойстве Connection, выбираем компонент TADOConenction. Далее, выделяем компонент TDataSource и в свойстве выбираем компонент TADOQuery. Затем, выделяем компонент TDBGrid и в свойстве DataSet выбираем компонент TDataSource. Все подключение к нашей БД настроено, теперь приступаем к поиску данных.
Первый способ
Фильтрация данных
Ну, тут много говорить не буду, уже итак все сказал, что фильтрация данных — это тот же поиск по определенному условию, который указывается в свойстве Filter, например
procedure TForm1.Button1Click(Sender: TObject); begin ADOQuery1.Filtered:=True; ADOQuery1.Filter:='names='+'''Andrey'''; end;
В данном свойстве, указывается поле, которое необходимо фильтровать и условия отбора. Работает достаточно быстро, при большом количестве записей. Не забываем, что его необходимо еще и активировать Filtered:=True
Второй способ
С помощью SQL-запросов
Ну, тут, я много ничего не буду говорить, так как мы много рассматривали подобных примеров, просто выбираем записи, по определенному условию, например:
procedure TForm1.Button2Click(Sender: TObject); begin ADOQuery1.SQL.Clear; ADOQuery1.SQL.Add('SELECT * FROM Test WHERE names=''Andrey'''); ADOQuery1.Active:=True; end;
Тут будут найдены записи, которые полностью удовлетворяют условию, а чтобы были найдены записи, по начальному совпадению, то необходимо использовать LIKE, например:
procedure TForm1.Button2Click(Sender: TObject); begin ADOQuery1.SQL.Clear; ADOQuery1.SQL.Add('SELECT * FROM Test WHERE names LIKE ''%Andr%'''); ADOQuery1.Active:=True; end;
Данным способом, будут выбраны все записи, которые начинаются на Andr.
Третий способ
С помощью функции Locate
Есть также, замечательная функция, которая позволяет также находить записи по неполному совпадению, например:
procedure TForm1.Button3Click(Sender: TObject); begin if ADOQuery1.Locate('names','Andr',[loCaseInsensitive,loPartialKey])=True then begin ShowMessage('True'); end; end;
Ну вот такая небольшая заметка, по поиску данных в БД, с использованием ADO. Исходники выкладывать не буду, так как тут итак, думаю, все понятно.
кто-нибудь пробовал реализовать?
—
Бoрис
Posted via RSDN NNTP Server 1.9
Здравствуйте, rathome, Вы писали:
R>кто-нибудь пробовал реализовать?
DevExpress QuantinumGrid 4.XX, 5.XX точно присутствует, и писать ничего не надо. Найти можно у китайцев.
… << RSDN@Home 1.1.4 stable SR1 rev. 568>>
> R>кто-нибудь пробовал реализовать?
>
> DevExpress QuantinumGrid 4.XX, 5.XX точно присутствует, и писать ничего не надо.
проблема не в этом.
хочу сделать, чтобы автофильтр cxGrid работал точно также как в excel.
в cxGrid реализован простой вариант: возможные значения для фильтрации отображаются все.
столбец1 столбец2
A 3
A 3
A 2
B 5
B 4
B 1
например. фильтруем по столбец1 (столбец1=A). хочу, чтобы при фильтрации столбца2 видны были значения
3
2
в cxGrid виды все значения столбца2
3
2
5
4
1
это я уже сделал.
единственная проблема втом, что если отфильтровали столбец1 по значению А и пытаемся еще отфильтровать, видим только значение А, а не все значения в столбце1.
кусок из cxCustomData.pas
<code>
procedure TcxDataFilterValueList.Load(AItemIndex: Integer);
var
ANullExist: Boolean;
AField: TcxCustomDataField;
procedure LoadRecords;
var
I: Integer;
V: Variant;
FI:Integer ;
begin
ANullExist := False;
AField := DataController.Fields[AItemIndex];
for I := 0 to DataController.GetFilteredRecordCount — 1 do {boris}
begin
// TODO: ignore editing record
FI:=DataController.GetFilteredRecordIndex(I) ;
V := DataController.GetFilterDataValue(FI, AField);
if Criteria.ValueIsNull(V) then
ANullExist := True
else
Add(fviValue, V, DataController.GetFilterDisplayText(FI, AItemIndex), False);
end;
end;
begin
Clear;
// SortByDisplayText := DataController.GetItemValueSource(AItemIndex) <> evsText; // TODO: Text for Lookup Field!!!
SortByDisplayText := DataController.IsFilterItemSortByDisplayText(AItemIndex);
Add(fviAll, Null,
</code>
просто понаблюдайте как работает фильтр в excel с несколькими столбцами и поймете меня.
Posted via RSDN NNTP Server 1.9