Delphi 3. Библиотека программиста

Сброс груза


Я перешел к шагу 3. Задача заключалась в том, чтобы определить номера столбца и строки для первого дня месяца и для положения курсора. С помощью несложных вычислений я получаю разность между двумя датами (в днях), которую затем можно прибавить к дате начала месяца для получения абсолютной даты.

Разумеется, первый день месяца всегда выводится в первой строке, каким бы днем недели он ни был. Со строкой все ясно. Поскольку я не изменял стандартного порядка дней недели (с воскресенья до субботы), день недели для первого числа месяца дает мне базовый номер столбца. Дальше остается лишь переместиться в календаре на нужное количество дней. К счастью, пакет Orpheus включает мощные процедуры для арифметических вычислений и преобразования дат, заметно облегчающие мою задачу. Функция вычисления даты приведена в листинге 14.3.

Листинг 14.3. Вычисление даты по положению курсора

function DatePointedTo : TOvcDate; var Idx : Longint; DOW : Integer; Day1 : TOvcDate; begin { Вычисляем первый день как Row = 1, Col = день недели, затем вычисляем смещение для даты под курсором и складываем. } Day1 := DMYToDate(1, Calendar.Month, Calendar.Year); DOW := Ord(DayOfWeek(Day1)) + 1; Idx := (RNum - 1) * 7; if CNum < DOW then Idx := Idx - (DOW - CNum) else if CNum > DOW then Idx := Idx + (CNum - DOW);1 Result := IncDate(Day1, Idx, 0, 0); end; { DatePointedTo }

Осталось выполнить тривиальную работу — преобразовать дату и содержимое текстового поля в строку и занести ее в TStringGrid. Кроме того, мне показалось, что текстовое поле после завершения перетаскивания стоит очистить. Поддержка перетаскивания несколько снизила возможности редактирования в текстовом поле, поэтому очищать его вручную было бы утомительно.

Примечание для себя: в данном случае текстовое поле следует очищать в обработчике события перетаскивания, поскольку эта операция должна выполняться лишь в случае успешного завершения. Если бы я захотел очищать текстовое поле независимо от того, состоялось перетаскивание или нет, это следовало бы делать в обработчике OnEndDrag текстового поля.

Заметки на память: 1) проследить за тем, чтобы свойство Initialize компонента OvcCalendar было равно True. В противном случае календарь окажется в неопределенном состоянии! 2) свойство DrawHeader должно иметь значение False, чтобы в календаре не выводилось ничего, кроме дат.

В листинге 14.4 приведен исходный текст всего модуля.



Листинг 14.4. Демонстрационная программа для перетаскивания

{——————————} {Перетаскивание (демонстрационная программа)} {DRAGMAIN.PAS : Главный модуль } {Автор: Эйс Брейкпойнт, N.T.P. } {При содействии Дона Тейлора } { } { Приложение, демонстрирующее } основные принципы } { внутреннего перетаскивания. } { } { Написано для *High Performance Delphi 3 Programming* } { Copyright (c) 1997 The Coriolis Group, Inc.} { Дата последней редакции 3/5/97 } {————————} unit DragMain; interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, Grids, StdCtrls, OvcBase, OvcCal, OvcData, OvcDT, ExtCtrls; type TDDDemoForm = class(TForm) Calendar: TOvcCalendar; OvcController1: TOvcController; EditBox: TEdit; StringGrid: TStringGrid; Label1: TLabel; Bevel1: TBevel; QuitBtn: TButton; Panel1: TPanel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Panel2: TPanel; procedure QuitBtnClick(Sender: TObject); procedure EditBoxMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure CalendarDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); procedure CalendarDragDrop(Sender, Source: TObject; X, Y: Integer); private { Private declarations } public { Public declarations } end; var DDDemoForm: TDDDemoForm; implementation {$R *.DFM} procedure TDDDemoForm.QuitBtnClick(Sender: TObject); begin Close; end; procedure TDDDemoForm.EditBoxMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if (Button = mbLeft) and (EditBox.Text <> "") and not (ssDouble in Shift) then TEdit(Sender).BeginDrag(False); end; procedure TDDDemoForm.CalendarDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin Accept := True; end; procedure TDDDemoForm.CalendarDragDrop(Sender, Source: TObject; X, Y: Integer); var RHeight : Integer; CWidth : Integer; RNum : Integer; CNum : Integer; s : String; function DatePointedTo : TOvcDate; var Idx : Longint; DOW : Integer; Day1 : TOvcDate; begin { Вычисляем первый день как Row = 1, Col = день недели, затем вычисляем смещение для даты под курсором и складываем. } Day1 := DMYToDate(1, Calendar.Month, Calendar.Year); DOW := Ord(DayOfWeek(Day1)) + 1; Idx := (RNum - 1) * 7; if CNum < DOW then Idx := Idx - (DOW - CNum) else if CNum > DOW then Idx := Idx + (CNum - DOW); Result := IncDate(Day1, Idx, 0, 0); end; { DatePointedTo } begin RHeight := Calendar.ClientHeight div 6; RNum := Y div RHeight + 1; CWidth := Calendar.ClientWidth div 7; CNum := X div CWidth + 1; { Заносим дату и описание задачи в список строк } s := DateTimeToStr(OvcDateToDateTime (DatePointedTo)) + " - " + EditBox.Text; StringGrid.Cells[0, StringGrid.RowCount - 1] := s; { Добавляем в список пустую строку } StringGrid.RowCount := StringGrid.RowCount + 1; EditBox.Text := ""; end; end.

Конец записи (19 марта).

Зловещая фигура наклонилась вперед, внимательно читая похищенный Дневник. Взгляд скользнул на следующую страницу.



Содержание раздела