Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Интернет: Образование, Работа и Бизнес" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Программирование на Delphi #21
Информационный Канал Subscribe.Ru |
Программирование на Delphi. Выпуск №21: 20.02.05. |
||||||||||||||||||||||||||||||||||||||||||||
Начну с того, что уже давно хотел сказать. Почему никто не посещает форум? Уже порядка двух недель ни одного нового сообщения и ни одной новой темы. Хотелось бы узнать, почему так? Жду ваших писем.
Не стесняйтесь и говорите, что вам конкретно не нравится... У меня одно подозрение, но хотелось бы услышать
именно вас. Предлагаю вам принять участие вот в таком конкурсе. Ниже вы видите 10 вопросов, на каждый из которых есть варианты ответов. Ответьте на все вопросы, просто указывая букву(ы) и пришлите их по ЭТОЙ ссылке. Внимание! Письмо должно соответствовать следующему образцу: -------------------------------------------------------- 1-A -------------------------------------------------------- Строки "--------------------------------------------------------" - просто разделители. Таким образом, письмо не должно иметь вступления (приветствия). Сразу должны идти ответы на вопросы: номер вопроса-ответ. Пробелов перед и после "-", а также после "," между двумя вариантами ответа (10-й вопрос) быть не должно. Строка "===" является разделителем между ответами и информацией о пользователе и является обязательной. Рекомендую вам просто скопировать текст из поля ниже и вставить его полностью в текст письма:
Не забудьте изменить варианты ответа на правильные :)) Хочу отдельно сказать, почему такой строгий шаблон писем: обрабатывать эти письма буду не я, а специально-написанная мною программа (на Delphi конечно :) ), поэтому соблюдайте все вышеописанные правила. А вот и сами вопросы: 1. Разработчиком Delphi является: A. Microsoft. 2. На Delphi можно писать... A. Всё, что угодно. 3. Среда Delphi разработана в Delphi: A. Да 4. Программу можно скомпилировать, даже если в коде есть ошибки, но тогда эти ошибки проявятся при выполнении программы... A. Да 5. На Delphi можно создавать приложения для Linux: A. Нет 6. Есть в Delphi поддержка RTL-библиотек (RunTime Libraries), как в Visual Basic? A. Есть 7. Выполнение кода:
приведёт к: A. Выводу всех строк List в Memo1. 8. Какой из перечисленных типов включает в себя наибольший диапазон значений? A. Single. 9. Можно ли запустить программу из Delphi с командными параметрами или только через Windows? A. Можно. 10. Укажите ДВЕ известные программы, написанные на Delphi: A. Microsoft Word. За каждый правильный ответ вы получите 2 балла. Таким образом, ответив правильно на все вопросы, вы можете получить 20 баллов. Имена лучших будут опубликованы. Также поступающие вопросы и ответы начиная с текущего времени и до обновления на сайте публиковаться НЕ БУДУТ по некоторым причинам. И вообще, сайт будет всё это время обновляться крайне мало. Учтите это. Но это вовсе не значит, что не работает и форум! Наоборот, он ждёт всех вас! Чуть не забыл... Когда вам начисляются баллы за ответы, то ваша "учётка" привязана к вашему e-mail. Поэтому, пожалуйста, все письма в ящик нашего проекта шлите с одного мыла, иначе счёт может обнулиться. Количество подписчиков: XXXX. Не забывайте посещать наш форум. Top-10 Readers:
Правила нашей рассылки: |
||||||||||||||||||||||||||||||||||||||||||||
74. У меня такой вопрос, бьюсь над ним уже две недели:
вывод суммарной температуры за день и за месяц.
Как в StringGrid сделать подсчет, чтобы было так:
В первый столбец вводится дата, во второй температура - в третьем столбце выводится суммарная температура за день, в четвертом суммарная температура за месяц: 75. Как убрать мою программу из диспетчера задач WINDOWS? [Ответить]. 76. Народ подскажите как получить список IP адресов компьютера без WinSock? [Ответить]. 77. У меня проблема.
Здесь все работает. Подскажите, пожалуйста, почему выдает ошибку следующее:
[Ответить]. |
||||||||||||||||||||||||||||||||||||||||||||
"Огромное спасибо за помощь Iron Monkу ! YaricZ (YaricZ@mail.ru)" - я так думаю, это за ответ на 60-ый вопрос. 71. (Отправка SMS). [Отвечает: Igor]: Отправить СМС можно, например, с помощью e-mail, если это поддерживает мобильный оператор. Нужно отправлять e-mail на спец. адрес, в который входит номер телефона, что-то типа 380670000000@2sms.kyivstar.net для абонентов Киевстар. Позвоните своему оператору и узнайте, как с простого e-mail послать СМС на телефон. [Отвечает: Садовников Владимир]: Есть хорошая программа для посылки смс - SMSSender. Но! Теперь крупные компании (типа МегаФона) стали использовать такие методы, как визуальное подтверждение кода (т.е. ты должен распознать число, нарисованное на картинке). Так что такой трюк уже не катит... Так как: программы делают следующим образом: соединяются с сервером посылки смс для данного оператора, после чего выполняют ту же работу, что и твой броузер - передают скриптам на странице определённые параметры (типа текста сообщения, номера получателя и т.д.). Когда возвращается удачный результат, соединение разрывается (чтобы понизить трафик). Вот и весь, вроде, принцип их работы - без оператора не покатит, универсальности здесь никакой, и надо подстраиваться под сети и сервисы тех операторов, которые тебе нужны. [Отвечает: Ершов Денис]: Отправка SMS через интернет в основном производится через e-mail или http. Для этого существуют специальные сервера сотовых операторов или специальные бесплатные службы, например, Infan.ru. С почтовыми сервисами все проще, необходим всего лишь почтовый клиент, отправляющий SMS в виде текста письма, но я о подобных сервисах только слышал. HTTP более популярная вещь, хотя и тоже крайне редкая. В этом случае нужно либо вежливо связаться с сапортом службы (может они дадут формат запроса), либо отправить для примера одну SMS с помощью браузера и с помощью анализаторов трафика самому его подсмотреть. Далее работа с http-клиентом. [Отвечает: Dron]: Все SMS отправляются обычным e-mail сообщением, только для каждого оператора они разные. Иногда ставят защиту вроде "введите код, который вы видите на картинке". Написать универсальную программу практически невозможно. 69. (Реализация шахмат). [Отвечает: Садовников Владимир]: Вот тебе пример модуля программы. Здесь есть только передвижение. Ни о каких поеданиях и речи быть пока не может (хотя исправить эту ситуацию несложно) - просто лениво было уже писать. Я думаю, ты и сам справишься. Думаю, что концепция ООП тебе понятна с наследующими классами. Кстати, в TQueen.Move я сжульничал - лень было код переписывать. Дерзай, может что-то вроде ChessMaster 9000 смастеришь или лучше :).
[Отвечает: Iron Monk]: Всем привет! Это шахматная доска:
А фигуры перемещать можно многими способами, от программного задания координат, до перетаскивания мышью, главное не забывать после каждой такой операции перерисовывать поле. Если в этом есть сложность, то проще использовать графическую доску TBitmap или TJPEGImage. [Отвечает: Сергей Загородних]: Используй класс TStringGrid, его методы и события, а также приёмы drag&drop. [Отвечает: alexlazer]: Здесь пример шахмат на Delphi. Как они устроены, не знаю, но можешь спросить у автора - Василенко И.П., i_vasilenco@yahoo.com. [Шахматы лежат здесь (238 Кб)]. [Отвечает: Dron]: Думаю, поле нарисовать совсем просто. Через Canvas, например. Затем нарисуй фигуры. Можешь их также рисовать на Canvas, но тогда придётся часто перерисовывать. Лично я бы использовал DelphiX. Каждая фигура - отдельный спрайт. Тогда вообще всё просто. А ещё круче - с помощью OpenGL сделать 3D-шахматы. В природе таких очень мало, но придётся самому писать AI для компьютера, а это непосильно одному человеку. Либо можно попробовать найти "готовую" логику. 35. (База данных в каталоге программы). [Отвечает: pirog]: Думаю эту проблему можно решить так: В инспекторе для Table1 ставим DatabaseName - ..\тут-Name\тут-baza. И делаем защищенный блок:
73. (Добавление компонентов на форму во время работы приложения). [Отвечает: Igor]: Да, можно. Вот пример добавления на форму кнопок во время работы приложения.
[Отвечает: Iron Monk]: Можно, можно даже создавать нестандартные решения.
[Отвечает: Сергей Загородних]: Если ты имешь в виду создание класса и обращение к нему в дальнейшем, то: 1. Нужно объявить переменную данного класса(который ты хочешь создать) в разделе объявления переменных(локально или глобально решать тебе в зависимости будешь ли ты с других процедур или функций обращаться к созданному тобой классу). 2. В теле метода(процедуры или ф-ции) создать класс через его конструктор(чаще всего имя метода констуктора называется Create). 3. Указать для класса его владельца(owner) или поставить nil и родителя(parernt)-[если класс визуальный] - о свойствах owner и parent для классов - можно прочитать в help по delphi. 4. Следить за разрушением класса(освобождением памяти, которую он занимает) - когда класс не используется и тебе не надо к нему обращаться. 5. Класс, который ты хочешь испоьзовать должен быть объявлен либо в твоём модуле, либо подключить в раздел uses модуль, в котором описан класс, который ты хочешь использовать [в дезайн-time'e При добавлении визуального компонента на форму delphi ide сам добавляет в uses модуль, в котором описан данный класс, добавляет переменную (объект) данного класса, к примеру caption1 : TCaption, а в .dfm-файле описывает св-ва для для добавленного объекта]. [Пример] - программно создать Label на button1.OnClick:
[Отвечает: VeroLom]: Вот пример добавления кнопки:
[Отвечает: Четвертных В.В.]: В принципе, это очень легко. компоненты, потомки TObject (А это - почти все стандартные компоненты Delphi) имеют конструктор Create. После создания компонента, если он визуальный, нужно указать его положение свойства: Top, Left, Width и Height (а можно использовать метод SetBounds(Top, Left, Width, Height:integer)), при необходимости делаем свойство Visible:=true. А вот теперь, можно делать с ним что хочешь... [Отвечает: alexlazer]: Если требуется, скажем, создать программно 5 кнопок. Очень просто. Помещаешь на форму тот объект, который надо программно создать (например, кнопку Button). В глобальном разделе var пишешь:
Щелкаешь по кнопке Button на форме, создаёшь, например, процедуру OnClick:
Компилируешь программу, удаляешь с формы первоначальную кнопку и запускаешь. Если требуется только одна кнопка, то:
Вариации по вкусу. [Отвечает: Андрей Лучников]: Можно, причем легко:
[Отвечает: Dron]: Конечно можно! Вот простой пример создания кнопки:
65. (События CM_MouseWheel). [Отвечает: Ершов Денис]: Не согласен с утверждением Ramon'а о бесполезности параметров MousePos: TPoint - координаты курсора, Handled: Boolean и Shift: TShiftState. С помощью ShiftState можно задать альтернативное действие. Например, в MS Visio удобно сделано: при зажатом Shift экран скроллируется по горизонтали, при Ctrl - масштабирование экрана. 70. (Работа с цветами изображения). [Отвечает: Dasha]: Чтобы получить цвет конкретного пикселя, можно использовать функцию GetPixel, или свойство TCanvas.Pixels[x,y]: TColor. Чтобы получить значения для цветового пр-ва CMYK, для полученного цвета можно вызвать: GetCValue, GetMValue и т.д. Так же можно получить значения каждого цвета в RGB. 50. (Слайд-шоу). [Отвечает: Dron]: Ну здесь проще всего создать в каталоге с программой каталог Pictures (ну можно и другое имя), в него положить все картинки, назвав их 1.jpg, 2.jpg, ..., n.jpg. Лучше преобразовать их все к одному графическому формату. Если это фотографии - JPEG как раз подойдёт. Затем завести массив и вписать в него текст к каждой картинке. Можно эти тексты также записать в файлы 1.txt, 2.txt, ..., n.txt. Ну а затем примерно так:
30. (Редактирование реестра с командной строки). [Отвечает: Dron]: Ну через bat действительно проще всего. Создай файл с именем, например, reg1.reg. Помести его куда-нибудь подальше, чтобы не нашли, например, в system32. Да и bat туда же. Затем как-нибудь вызови этот bat (это уже твоя забота :) ). Ну а сам bat пропиши примерно так: regedit.exe /s reg1.reg Ключ /s убирает запрос на добавление записей в реестр, т.е. всё будет тихо, как и хотим :) Данные добавятся, а reg-файл удалится - не будем оставлять следов :) Однако кто-то же будет запускать этот bat?.. Если твоя прога, то почему бы не использовать стандартные функции из модуля Registry.pas? 67. (Документация по работе с реестром). [Отвечает: Dron]: См. ответы на вопрос 44 в рассылке (16-ый выпуск). Там были приведены кучи ссылок. Наверняка на каждом сайте есть статьи на эту тему. Да и в самой рассылке довольно давно была статейка, на сайте посмотри. 62. (Рисование карандашом). [Отвечает: Dron]: Заводим переменную типа Boolean. Например, True - рисуем, False - не рисуем. Загружаем два курсора из файлов (через LoadCursor). Затем используем PaintBox для рисования (с палитры System). В OnMouseDown ставим Paint:=True и PaintBox.Cursor:=51;, в OnMouseUp: Paint:=False; Cursor:=52; А в OnMouseMove: If Paint Then PaintBox.Canvas.Pixels[X,Y]:=clBlue; Загружается курсор из файла следующим образом:
64. (Верхние индексы в исходнике). [Отвечает: Dron]: Нет, нельзя. В самом исходнике точно нельзя. А вот в строках (тип String и все его производные) - можно. Запускаем charmap.exe и ищем нужный символ. Запоминаем его код. Затем через функцию Chr (код) и получаем нужный символ, который и вставляем в строку. А вообще, я не знаю, зачем это всё нужно... 57. (Загрузка файлов в WebBrowser). [Отвечает: Dron]: У TWebBroswer есть функция Navigate, причём задавать её можно несколькими способами. В справке всё прекрасно описано. А если просто указать этой функции путь к странице (или картинке например), то эта страница (картинка) и загрузится. Также там есть дополнительные параметры, они все в хелпе есть. 51. (Изменение шрифта в отдельных ячейках StringGrid). [Отвечает: Dron]: У StringGrid есть событие OnDrawCell. Вот им и нужно воспользоваться. Читаем переменные ACol и ARow и, если в этой ячейке нужно изменить шрифт, то меняем его в StringGrid.Canvas.Font, а если не нужно - меняем шрифт на стандартный. Вот и всё. Вы также можете ответить на предыдущие вопросы. Поскольку на них уже ответили как минимум раз, они больше не публикуются в рассылке. Но если вы можете что-то добавить к ответам других, пожалуйста, отвечайте - ответы будут опубликованы. Найти предыдущие вопросы вы можете на нашем сайте: http://www.delphi-faq.fatal.ru/ или в спец-выпусках рассылки. |
||||||||||||||||||||||||||||||||||||||||||||
Delphi 4: Автоматизация приложений MS® Office® для эффективного анализа результатов
Глава 1. Работа с MS Excel.Часть 4. Работа с листами и ячейками.Евгений Старостин. Есть в VBA одна вещь, которая меня раздражает. Это ActiveSheet и ActiveWorkbook, а также возможность работы с Cells и Range без указания, к какому листу или книге они принадлежат. Одно время я боролся сам с собой, то применяя, то совсем отказываясь от подобных конструкций. Окончательно я отказался от этого лишь после обнаружения многочисленных ошибок в анализе "лога" моего Web-сервера, который я сделал на VBA. Благо, при работе в Delphi нет возможности написать Cells(x, y) = NewValue, подразумевая при этом какой-то неуловимый ActiveSheet. Поэтому прежде, чем работать с отдельными ячейками, я всегда получаю интерфейс на конкретный и вполне осязаемый лист книги. И делю это так:
var ISheet: Excel8TLB._Worksheet;
...
ISheet := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet;
Коллекция Worksheet подобна всем остальным коллекциям из Excel TLB. В ней вы можете удалять листы, вставлять новые, изменять их порядок. Но я практически никогда не делаю этого, поэтому всех нетерпеливых снова отсылаю к справке по Excel VBA. Главную же мысль свою повторю еще раз. Всегда и везде рекомендую работать с ячейками и областями в контексте их листа, получив предварительно интерфейс на этот лист вышеописанным способом. От использования свойств ActiveSheet и ActiveWorkbook можно совсем отказаться, разве что за исключением каких-то особых случаев. Чтение данных из ячейки.Написав этот заголовок, я подумал о том, как часто я "беру" данные из книги. Это случается весьма редко, ибо Excel я использую как средство построения отчетов. То есть, намного чаще эти данные я туда передаю. Поэтому хотелось бы описать не столько чтение данных, сколько способы обращения к ячейкам. Я использую разные способы обращения к ячейкам от привычного в Excel Cells(x,y) до коллекции Names. Вот некоторые примеры: procedure TForm1.btnReadDataClick(Sender: TObject); var Value: OLEVariant; ISheet: Excel8TLB._Worksheet; begin if Assigned(IWorkbook) then try ISheet := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; try case rgWhatRead.ItemIndex of 0: Value := ISheet.Cells.Item[2, 1].Value; 1: Value := ISheet.Range['A2', EmptyParam].Value; 2: Value := ISheet.Range['TestCell', EmptyParam].Value; 3: Value := IWorkbook.Names.Item('TestCell', EmptyParam, EmptyParam).RefersToRange.Value; end; ShowMessage(Value); finally ISheet := nil; end; except raise Exception.Create('Не могу прочитать данные!'); end; end; На главную форму проекта я добавил кнопку, по которой можно прочитать данные из ячейки "А2" открытой книги, и RadioGroup к ней, чтобы выбрать способ получения этих данных. Из приведенного кода видна одна из "гнуснейших" моих привычек - освобождать все полученные интерфейсы явно (ISheet := nil). Я не могу побороть ее уже долгое время, поэтому прошу прощения у мастеров программирования на Delphi за то, что эта строчка здесь абсолютно лишняя. Самый повторяющийся вопрос в моей почте, это вопрос о Cells. Почему-то многие уверены, что конструкция Cells[x, y].Value должна работать. В VBA это так. Но при раннем связывании это не соответствует истине. Свойство Cells объявлено у всех интерфейсов как property Cells: Range read Get_Cells; Отсюда видно, что это область (Range). И нет там никаких индексов, чтобы пробовать писать [x, y]. Один из корреспондентов мне написал, что он как-то обращался с этой проблемой к Наталье Елмановой, и она ему не помогла, написав, что "есть предположение, что кодогенератор Delphi их как-то не так "переваривает", генерируя XXX_TLB.pas, но полной уверенности нет". А дело в том, что "кодогенератор" правильно генерирует свойства _Defaul и Item (у многих интерфейсов в Excel Type Library есть такое свойство) у интерфейса Range. Вот только свойство _Default должно быть свойством по умолчанию. Поэтому стандартное объявление этих свойств property _Default[RowIndex: OleVariant; ColumnIndex: OleVariant]: OleVariant dispid 0; property Item[RowIndex: OleVariant; ColumnIndex: OleVariant]: OleVariant dispid 170; можно исправить на такой вариант property _Default[RowIndex: OleVariant; ColumnIndex: OleVariant]: OleVariant dispid 0; default; property Item[RowIndex: OleVariant; ColumnIndex: OleVariant]: OleVariant dispid 170; и смело писать Cells[x, y].Value. Понятное дело, что это нехорошо - редактировать код, полученный автоматически из умного "кодогенератора" Delphi. Но "Там", ведь, тоже люди работают и ошибаются они не реже наших. Кстати, в импортированной Excel Type Library (независимо от версии Delphi - 4 или 5) некоторые свойства, имеющие dispid 0, почему-то все-таки объявлены как default. Почему?! В приведенном выше примере кода я показал не только использование Cells. К ячейкам можно получить доступ и через свойство Range интерфейса Worksheet. Это свойство объявлено как property Range[Cell1: OleVariant; Cell2: OleVariant]: Range read Get_Range; В Cell1 / Cell2 можно передать ячейки (только в формате А1, RC вызовет исключение), описывающие границы области - левый верхний угол и правый нижний. Я же использовал только указание одной ячейки, мне необходимой. Где-то в Рунете я встретил предположение о том, что, если передать в оба параметра "A1", то в выбранный Range попадет вся колонка. Сначала я подумал, - "А почему не вся строка?!" Но, решил, все-таки проверить это предположение - в область попала одна ячейка. В Excel можно присваивать имена любым ячейкам и даже наборам ячеек. Это можно сделать, либо используя "комбо-бокс", который находится левее строки формул, либо пункт меню "Вставка\Имя\Присвоить". Ячейке "А2" я присвоил имя "TestCell" и, используя все то же свойство Range листа, получил значение ячейки по этому имени. И последний вариант, без которого я не смог бы обойтись при создании всех своих отчетов, это использование коллекции Names книги. Не смотря на некоторую неуклюжесть кода, этот способ я использую довольно часто. Почему? Потому, что очень часто использую именованные ячейки и области, разбросанные по разным листам и даже книгам. Но останавливаться на нем смысла не вижу, оставляя благодарному читателю возможность обратиться непосредственно к первоисточнику - справке по Excel VBA. Чтение данных из нескольких ячеек.Имея ввиду все вышеописанное, можно просто организовать чтение данных из поименованной области. Я часто нахожу такой код в Сети и в книгах, приведенный в качестве примера. Вот он: procedure TForm1.btnReadArrayClick(Sender: TObject); var Values: OLEVariant; ISheet: Excel8TLB._Worksheet; IRange: Excel8TLB.Range; i, j: integer; begin if Assigned(IWorkbook) then try ISheet := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; try IRange := ISheet.Range['TestRange2', EmptyParam]; Values := VarArrayCreate([1, IRange.Rows.Count, 1, IRange.Columns.Count], varVariant); for i := 1 to IRange.Rows.Count do for j := 1 to IRange.Columns.Count do begin Values[i, j] := IRange.Item[i, j]; ShowMessage( Values[i, j]); end; finally IRange := nil; ISheet := nil; end; except raise Exception.Create('Не могу прочитать данные в массив!'); end; end; Я создал на форме кнопку, по которой из заранее подготовленной области с именем "TestRange2" все значения ячеек будут получены в вариантный массив Values. Вызов ShowMessage добавлен сюда только для контроля над процессом. Как видно, получить значения ячеек области достаточно просто. Вы создаете вариантный массив с количеством строк и колонок, равными размерам области, а затем, проходя по очереди все ячейки области, запоминаете их значения в массиве. Но в этом коде есть одна проблема. Чтение из ячеек можно организовать еще проще. Вот так: procedure TForm1.btnReadArrayClick(Sender: TObject); var Values: OLEVariant; ISheet: Excel8TLB._Worksheet; IRange: Excel8TLB.Range; begin if Assigned(IWorkbook) then try ISheet := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; try IRange := ISheet.Range['TestRange2', EmptyParam]; Values := IRange.Value; // <<--- for i := 1 to IRange.Rows.Count do for j := 1 to IRange.Columns.Count do begin ShowMessage( Values[i, j]); end; finally IRange := nil; ISheet := nil; end; except raise Exception.Create('Не могу прочитать данные в массив!'); end; end; Дело в том, что строки Values := IRange.Value вполне достаточно. Свойство Value интерфейса Range в состоянии вернуть вариантный массив. Этот код, по моему мнению, более прост и производителен, особенно на больших объемах данных. Уберите отсюда циклы с ShowMessage и убедитесь в этом. А вот пример кода, который вернет в массиве значения всех ячеек из используемой области на листе. Проще сказать, вернет весь лист: var Values: OLEVariant; ISheet: Excel8TLB._Worksheet; IRange: Excel8TLB.Range; i, j: integer; begin if Assigned(IWorkbook) then try ISheet := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; try IRange := ISheet.UsedRange[0]; Values := IRange.Value; finally IRange := nil; ISheet := nil; end; except raise Exception.Create('Не могу прочитать данные в массив!'); end; end; Здесь я использую свойство UsedRange листа. Это прямоугольная область, заключенная между "левой верхней непустой" и "правой нижней непустой" ячейками. (Кто-нибудь понял? Впрочем, в два часа ночи разве напишешь понятней!). Конечно, если в этой прямоугольной области будет много пустых ячеек, то массив получится с избыточными данными. Что бы убедиться в этом, попробуйте создать циклы с ShowMessage из предыдущего примера. В комментариях проекта-примера вы найдете еще несколько интересных конструкций, которые мне приходится использовать для получения массивов со значениями ячеек. В качестве параметра в UsedRange я передаю 0. Это lcid, описанный в предыдущей статье. Кстати, об lcid. В прошлый раз меня подвела зрительная память. И в самом деле, "любимый классик" пишет, что туда можно смело передавать 0. Но другой, не менее любимый классик с этим не согласен и рекомендует передавать туда результат функции GetUserDefaultLCID. Думаю, последнее более правильно. Однако В некоторых случаях, чаще в гремучей смеси Windows 2000 и Excel 2000, оба решения не проходили. Причем, выдавалось сообщение о попытке "использовать библиотеку старого формата:" и что-то еще. Так вот, вместо GetUserDefaultLCID я применяю теперь константу LOCALE_USER_DEFAULT. Более ничего объяснить не могу, так как до сих пор, проштудировав основательно MSDN, не разобрался, что же в таком случае хочет получить Microsoft в методы и свойства интерфейсов Excel, где одним из параметров требует lcid. Кто бы объяснил?.. Есть еще несколько способов чтения данных из книги, которые, впрочем, я не в силах описать здесь. Один их таких способов, это использование DDE, самый быстрый и экономичный (по ресурсам) способ, который известен еще со времен Windows 3.1. Поиск данных на листе.Предлагаю поискать все ячейки, содержащие строку (или подстроку) "Text", и изменить цвет фона этих ячеек. Для этого я использовал методы Find и FindNext. На форму была добавлена кнопка, в обработчике которой появился следующий код: procedure TForm1.btnFindClick(Sender: TObject); var ISheet: Excel8TLB._Worksheet; IFirst, IRange: Excel8TLB.Range; FirstAddress, CurrentAddress: string; UsedRange: OLEVariant; begin if Assigned(IWorkbook) then try ISheet := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; try UsedRange := ISheet.UsedRange[0]; IDispatch(IFirst) := UsedRange.Find(What:='Text', LookIn := xlValues, SearchDirection := xlNext); if Assigned(IFirst) then begin IRange := IFirst; FirstAddress := IFirst.Address[EmptyParam, EmptyParam, xlA1, EmptyParam, EmptyParam]; repeat IRange.Interior.ColorIndex := 37; IDispatch(IRange) := UsedRange.FindNext(After := IRange); CurrentAddress := IRange.Address[EmptyParam, EmptyParam, xlA1, EmptyParam, EmptyParam]; until FirstAddress = CurrentAddress; end; finally IRange := nil; IFirst := nil; ShowExcel; end; except raise Exception.Create('Не могу чего-то сделать!'); end; end; Думаю, у каждого увидевшего этот код возникнет ощущение неудовлетворенности. Да, в выделенной красным строке никаким ранним связыванием и не пахнет. Более того, если вы попробуете вызвать метод Find с указанными параметрами, заменив остальные на EmptyParam, вы получите исключение. Есть места в Excel Type Library, работающие с ошибками. Я знаю достаточно этих мест. В таких случаях я использую приведенный здесь прием. Я проверяю работоспособность кода в редакторе VBA, а затем перехожу на позднее связывание. Так мне удалось обойти несколько серьезных, по моему мнению, ошибок в Excel TLB. Раннее связывание не должно быть догмой хотя бы из-за этого. Более того, перейдя полностью на ранее связывание, мы получим более компактный, а следовательно и читаемый код: procedure TForm1.btnFindClick(Sender: TObject); var ISheet: Excel8TLB._Worksheet; UsedRange, Range: OLEVariant; FirstAddress: string; begin if Assigned(IWorkbook) then try ISheet := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; UsedRange := ISheet.UsedRange[0]; Range := UsedRange.Find(What:='Text', LookIn := xlValues, SearchDirection := xlNext); if not VarIsEmpty(Range) then begin FirstAddress := Range.Address; repeat Range.Interior.ColorIndex := 37; Range := UsedRange.FindNext(After := Range); until FirstAddress = Range.Address; ShowExcel; end; except raise Exception.Create('Не могу чего-то сделать!'); end; end; Перемещение данных между листами.Несколько раз меня спросили о том, как перемещать данные между листами. Я бы сделал это вот так: procedure TForm1.btnMoveDataClick(Sender: TObject); var ISheetSrc, ISheetDst: Excel8TLB._Worksheet; IRangeSrc, IRangeDst: Excel8TLB.Range; begin if Assigned(IWorkbook) then try ISheetSrc := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; ISheetDst := IWorkbook.Worksheets.Add(EmptyParam, ISheetSrc, 1, EmptyParam, 0) as _Worksheet; IRangeSrc := ISheetSrc.Range['TestRange2', EmptyParam]; IRangeDst := ISheetDst.Range['D4', EmptyParam]; IRangeSrc.Copy(IRangeDst); finally IRangeDst := nil; IRangeSrc := nil; ISheetDst := nil; ISheetSrc := nil; end; end; Метод Copy интерфейса Range принимает в качестве параметра любой другой Range. Причем, совсем не важно, совпадают ли размеры источника и получателя, так как данные копируются начиная с левой верхней ячейки получателя в количестве, определенном размером источника. (О, завернул!) Для затравки хотелось бы показать код, который выполняет ту же задачу, но через буфер обмена (а вдруг в Word вставлять будем): procedure TForm1.btnMoveDataClick(Sender: TObject); var ISheetSrc, ISheetDst: Excel8TLB._Worksheet; IRangeSrc, IRangeDst: Excel8TLB.Range; begin if Assigned(IWorkbook) then try ISheetSrc := IWorkbook.Worksheets.Item['Лист1'] as Excel8TLB._Worksheet; ISheetDst := IWorkbook.Worksheets.Add(EmptyParam, ISheetSrc, 1, EmptyParam, 0) as _Worksheet; IRangeSrc := ISheetSrc.Range['TestRange2', EmptyParam]; IRangeDst := ISheetDst.Range[ 'D4', EmptyParam]; IRangeSrc.Copy(EmptyParam); // так кладем в Clipboard ISheetDst.Paste(IRangeDst, EmptyParam, 0); // а вот так достаем оттуда finally IRangeDst := nil; IRangeSrc := nil; ISheetDst := nil; ISheetSrc := nil; end; end; 1. Скриншот из 2-ой статьи: Открыть. 2. 1-ая часть цикла статей по Excel: Открыть. 3. 2-ая часть цикла статей по Excel: Открыть. 4. 3-ая часть цикла статей по Excel: Открыть. 5. 4-ая часть цикла статей по Excel: Открыть. 6. Демо-программа-1 к статье 4: Скачать. Присылайте свои статьи по адресу delphi-faq@list.ru с темой 'Clause' (без кавычек), и они будут опубликованы в ближайших выпусках рассылки. Большая просьба: статью оформляйте в -txt или -doc формате и используйте -zip или -rar сжатие (без самораспаковки). |
||||||||||||||||||||||||||||||||||||||||||||
В данном разделе публикуются различные ссылки, причём не только по Delphi но и по OpenGL, WinAPI, DirectX и т.д. (они могут быть на других языках, например, на Си). Присылайте свои ссылки на документацию по программированию. http://delphiworld.narod.ru/_all_articles_.html - 5000 статей и заметок по Delphi. |
||||||||||||||||||||||||||||||||||||||||||||
В связи с грядущим обновлением сайта пополнений нет.
|
||||||||||||||||||||||||||||||||||||||||||||
Здесь представлены ссылки на дружественные сайты нашего портала. Если вы тоже хотите стать нашим другом, разместите баннер на главной странице своего сайта. Подробнее о том, как стать другом, можно прочитать здесь: http://www.delphi-faq.fatal.ru/banner.htm, а узнать о всех наших друзьях - на странице http://www.delphi-faq.fatal.ru/friends.htm http://infomania2004.webhost.ru/ - Этот сайт создан для того, чтобы вы могли получить интересующую вас информацию с минимальными затратами сил и времени. Если вы не нашли здесь нужной информации, вы можете оставить заявку на ее поиск. Как только информация будет найдена, она появится на сайте, а вам сообщат об этом. |
||||||||||||||||||||||||||||||||||||||||||||
Только Билл Гейтс мог додуматься клеить обои на стол. *** - Чем хакер отличается от юзера? *** - Чем Бог отличается от Билла Гейтса? *** Хакер стирает коврик мышовый в ванной, заходит его друг: *** - Поставил девушке Windows 98, чтобы чаще с ней встречаться. Присылайте свои "компьютерные" анекдоты по этой ссылке: Delphi-FAQ@list.ru и они обязательно будут опубликованы! Нецензурные анекдоты не публикуются! |
||||||||||||||||||||||||||||||||||||||||||||
Товарищи программисты! Проявляйте свою активность. Давайте помогать друг другу! Если вы не нашли ответа на свой вопрос, не отчаивайтесь! Ведь количество подписчиков постоянно растёт и, наверняка, найдётся тот человек, который поможет вам! На сегодня всё. До встречи через неделю! |
||||||||||||||||||||||||||||||||||||||||||||
Ведущий рассылки и администратор сайта: Андрей (Delphi-FAQ@list.ru). |
||||||||||||||||||||||||||||||||||||||||||||
Сайт рассылки: http://www.delphi-faq.fatal.ru/ E-mail: Delphi-FAQ@list.ru Страница рассылки: http://subscribe.ru/catalog/comp.soft.prog.delphifaq |
http://subscribe.ru/
http://subscribe.ru/feedback/ |
Подписан адрес: Код этой рассылки: comp.soft.prog.delphifaq |
Отписаться |
В избранное | ||