Пензенская государственная технологическая академия Дисциплина «Методы и средства разработки прикладного программного обеспечения» Курсовой проект на тему «Разработка программы ведения БД по фирмам и операциям с акциями» Вариант 8 Выполнил студент группы 18ИЭ1бзи Романов В.В. Принял преподаватель Чигирева И.В. Оценка _____________ Дата _____________ Пенза 2021 Пензенский государственный технологический университет Кафедра : «Прикладаная информатика» Утверждаю» Зав. кафедрой__________ Дата: _________________ ЗАДАНИЕ на курсовое проектирование по дисциплине «Методы и средства разработки прикладного программного обеспечения» студенту Романову В.В. группы 18ИЭ1бзи Тема проектаРазработка программы ведения БД по фирмам и операциям с акциями Исходные данные (технические требования) на проектирование 1. Назначение программы: программа предназначена для сопровождения базы данных … . 2. Состав и структура исходных данных: предоставлена в разделе 2 3. Функции программы предоставлена в разделе 1 4. Требования к программепрограмма должна обеспечивать сопровождение БД согласно заданной структуре 5. Графическая часть: схема данных 1 лист формата А4, схемы программ 5 листов формата А4. 6. Экспериментальная часть: составление и отладка программы в среде Microsoft Visual Studio С#. График работ над проектом № п\п Работа Срок выполнения 1 Постановка задачи, разработка структуры данных 30.02.__ 2 Разработка алгоритмов решения задач 10.03.__ 3 Разработка структуры пользовательского интерфейса и 20.03.__ структуры программы 4 Программирование, отладка и тестирование 15.04.__ программы; подготовка текста программы 5 Подготовка графической части проекта 25.04.__ 6 Разработка руководства пользователя 05.05.__ 7 Оформление пояснительной записки 15.05.__ Дата выдачи задания 15.02.__ г. Дата защиты проекта 20.05.__ г. Студент Романов В.В._______________________ Руководитель Чигирева И.В.__________________ Содержание 1. Постановка задачи и исходные данные . . . . . .. 4 2. Состав и структура данных . . . . . . . . . . . . .. . . . 6 3. Методы решения задачи. ……. . . . . . . . . . . . . .. 8 4. Структура пользовательского интерфейса .. . . . 11 5. Структура программы .. . . . . . . . . . . . . . . . . . . . .13 6. Описание программы..……………………... . . . 19 7. Тестирование программы . . . . . . . . . . . . . . . .. . .21 8. Руководство пользователя . . . . . . . . . . . . . . . . . 22 9. Литература . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . 37 10. Приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Изм Лист Разработал Проверил Н. контр. Утв. № докум. Романов Чигирева Подп. Дата КП – 080801 – 32 – 15 81 01 Программа ведения БД по фирмам и операциям с акциями. Пояснительная записка Курсовой проект Литер Масса Лист 3 Листов 66 Масштаб ПензГТУ группа 18ИЭ1бзи 1. Постановка задачи и исходные данные Необходимо разработать прикладную программу для сопровождения БД, содержащей сведения согласно заданной ниже структуре: Структура данных 4. Фирма Номер Наименование Генеральный свидетельства фирмы директор Информация о доходах фирм от операций с акциями Дата Курс акций Количество Дохо акций д фирмы Покупка Продажа Купл Про ено дано Примечание: выполнить группировку по фирмам, по месяцам с вычислением итоговых сумм. Функции программы: - вывод меню функций, выполняемых программой (выбор пользовательских функций "Метками"), - ввод, просмотр, редактирование данных в базе данных (БД), содержащей не менее двух таблиц, - вычисление значений полей, - дополнение БД, удаление данных из БД, - отбор (фильтрация) данных по условию, задаваемому пользователем, - сортировка данных не менее чем по двум полям, - контроль вводимых данных с выводом сообщений о возможных ошибках (отсутствие данных, допустимые значения символов, диапазоны значений; соотношения между данными, например, между количеством товара на складе и количеством отпускаемого со склада товара), - обработка не менее трех исключительных ситуаций, - формирование не менее двух отчётов по данным из БД (с группировкой, вычисляемыми полями и вычислением итоговых данных), которые могут быть выведены на принтер, -4- - построение на основе информации из БД не менее двух графиков (гистограммы, полигона или круговой диаграммы), характеризующих заданную предметную область, - вывод формы со сведениями о программе (назначение, разработчик). -5- 2. Состав и структура данных База данных сделана в СУБД Access. Структура базы данных (схема данных): Поля таблиц: firms (фирмы) Тип Имя поля Назначение поля ID ID-номер записи Счетчик Name Название фирмы Текстовый 30 Certificate Номер свидетельства Текстовый 20 Director Генеральный директор Текстовый 50 -6- Длина (байт) Примечание Первичный ключ Без пустых строк, индекс (совпадения не допускаются) Без пустых строк, индекс (совпадения не допускаются) Имя поля Operations (операции с акциями) Назначение поля Тип ID ID-номер записи Счетчик FirmID ID записи фирмы Длинное целое PurchasePrice Цена акции при покупке Цена акции при продаже Сколько акций куплено Сколько акций продано Общий доход Дата/время покупки/продажи уникальный номер месяца Денежный Денежный Длинное целое Длинное целое Денежный Дата/время SalePrice PurchaseCount SaleCount Income Date MonthNum -7- Длинное целое Длина (байт) Примечание Первичный ключ Связь с таблицей firms (по полю ID) 3. Методы и алгоритмы решения задач В соответствии со структурой данных задания, в БД определены две таблицы: фирмы (firms), и операции с акциями фирм (Operations). Таблица Operations является подчиненной по отношению к firms. В поле Income (доход) таблицы Operations данные заносятся автоматически, в соответствии с формулой: Income = SalePrice*SaleCount – PurchasePrice*PurchaseCount, Где SalePrice, SaleCount, PurchasePrice, PurchaseCount – поля записи таблицы Operations. Дополнительно в таблицу Operations было добавлено поле MonthNum (уникальный номер месяца), для выполнения группировки по месяцам. Значение этого поля также вычисляется автоматически от даты (поле Date), по формуле: MonthNum = ГОД*12+МЕСЯЦ, Где ГОД, МЕСЯЦ – год и месяц текущей даты (поле Date). Вычисления полей Income и MonthNum выполняются в обработчике RowChanged для таблицы Operations (см. Row_Changed в EditForm.cs). В экранной таблице главной формы (form1.cs) отображаются совокупные данные по фирмам (см. таблицу firm1 в firmsDataSet.xsd), которые формируются следующим запросом: SELECT firms.ID, firms.Name, firms.Certificate, firms.Director, COUNT(Operations.ID) AS OpCount, SUM(Operations.Income) AS AllSum FROM (firms LEFT OUTER JOIN Operations ON firms.ID = Operations.FirmID) GROUP BY firms.ID, firms.Name, firms.Certificate, firms.Director ORDER BY firms.Name Поля OpCount – количество записей в таблице Operations по данной фирме, AllSum – совокупный доход по данной фирме. Добавление и редактирование записей фирм (а также операций по фирме) выполняется с помощью формы EditForm (EditForm.cs). При редактировании текущей записи фирмы таблицы набора данных firmsDataSet (компонент формы EditForm) заполняются временным адаптером (тексты запросов формируются во время работы программы), а обновляются стандартными адаптерами (которые добавлены в форму на этапе проектирования). Для таблицы firms используется запрос: SELECT * FROM firms WHERE(ID = XX) А для таблицы Operations – запрос: -8- SELECT * FROM Operations WHERE(FirmID = XX) ORDER BY [Date] Где XX – ID записи фирмы (в firms - запись текущей фирмы, в Operations – только связанные с данной фирмой записи). Также для таблицы Operations в форме EditForm определен обработчик TableNewRow (см. New_Row в EditForm.cs), в котором при добавлении новой записи инициализируется поле FirmID (заносится ID текущей фирмы) и Date (заносится текущая дата/время). Удаление записей фирм (включая удаление связанных записей из Operations) выполняется также с помощью динамически формируемых запросов (используются только временное подключение OleDbConnection, и запрос OleDbCommand). Для таблицы firms используется запрос: DELETE FROM firms WHERE(ID = XX) А для таблицы Operations – запрос: DELETE FROM Operations WHERE(FirmID = XX) Где XX – ID записи фирмы. Для отчета по фирмам и диаграммы по фирмам определяется диапазон времени (с помощью формы SelectDateForm), используется таблица firm1 набора данных (см. firmsDataSet.xsd). Для заполнения этой таблицы используется временный адаптер с динамически формируемым текстом запроса такого вида: SELECT firms.ID, firms.Name, firms.Certificate, firms.Director, COUNT(Operations.ID) AS OpCount, SUM(Operations.Income) AS AllSum FROM (firms LEFT OUTER JOIN Operations ON ((firms.ID = Operations.FirmID) AND (Operations.[Date] >=XXMin) AND (Operations.[Date] <=XXMax))) GROUP BY firms.ID, firms.Name, firms.Certificate, firms.Director ORDER BY firms.Name Где XXMin, XXMax – заданный временной диапазон. Для отчета по месяцам для фирмы и диаграммы по месяцам для фирмы определяется диапазон времени и фирма (с помощью формы SelectDateForm), используется таблица Operations1 набора данных (см. firmsDataSet.xsd). Для заполнения этой таблицы используется временный адаптер с динамически формируемым текстом запроса такого вида: -9- SELECT MonthNum, COUNT(ID) AS RecCount, SUM(PurchaseCount) AS PurchaseC, SUM(SaleCount) AS SaleC, SUM(Income) AS AllIncome FROM Operations WHERE (FirmID =XX)AND([Date] >= XXMin)AND ([Date] <= XXMax) GROUP BY MonthNum ORDER BY MonthNum Где XXMin, XXMax – заданный временной диапазон, XX – ID выбранной фирмы. Также в таблицу Operations1 набора данных добавлено вручную поле MonthName (наименование месяца, месяц+год). Значения в это поле заносится при заполнении таблицы, обработчиком RowChanged (см. Row_Changed в RepForm2.cs и Row_Changed в DiagramForm2.cs). - 10 - 4. Структура пользовательского интерфейса Структура пользовательского интерфейса: Фирмы Редактирование параметров фирмы EditForm Form1 label2_Click label3_Click Выбор фирмы и диапазона времени label5_Click SelectDateForm label6_Click label7_Click label8_Click label9_Click Отчет по фирмам Rep1Form Диаграмма по фирмам DiagramForm1 Отчет по месяцам для фирмы RepForm2 Диаграмма по месяцам для фирмы DiagramForm2 Окно «О программе» AboutBox1 - 11 - Назначение элементов управления главной формы(Form1) Элемент Имя Надпись Назначение, имя процедуры управления (идентификатор) Метка label2 Открыть Открыть форму EditForm для фирму... редактирования параметров фирмы; Form1.label2_Click Метка labe3 Добавить Открыть форму EditForm для новую добавления новой фирмы; фирму... Form1.label3_Click Метка label5 Отчет по Открыть форму SelectDateForm фирмам... для выбора временного диапазона, затем открыть форму Rep1Form с отчетом по фирмам; Form1.label5_Click Метка label6 Диаграмма Открыть форму SelectDateForm по фирмам... для выбора временного диапазона, затем открыть форму DiagramForm1 с диаграммой по фирмам; Form1.label6_Click Метка label7 Отчет по Открыть форму SelectDateForm месяцам для для выбора временного фирмы... диапазона и фирмы, затем открыть форму RepForm2 с отчетом по месяцам для фирмы; Form1.label7_Click Метка label8 Диаграмма Открыть форму SelectDateForm по месяцам для выбора временного для фирмы... диапазона и фирмы, затем открыть форму DiagramForm2 с диаграммой по месяцам для фирмы; Form1.label8_Click Метка label9 О Открыть форму AboutBox1 для программе... просмотра сведений о программе; Form1.label9_Click - 12 - 5. Структура программы Иерархическую модель программы смотри в приложении 1 Описания функций Form1.cs: Имя процедуры (класса Form1) Определение, назначение, выполняемые функции, используемые параметры Form1 public Form1() Form1_Load private void Form1_Load(object sender, EventArgs e) MouseEnterMove private void MouseEnterMove(object sender) label3_MouseEnter private void label3_MouseEnter(object sender, EventArgs e) конструктор, настраивает поля Обработчик Load - вызывается при открытии формы Настраивает адаптеры, заполняет таблицы Метод для визуального выбора метки при наведении на нее указателя мыши. Используется в обработчиках MouseEnter, MouseMove. Обработчик входа "мышь над элементом". Выделяет метку. label3_MouseLeave private void label3_MouseLeave(object sender, EventArgs e) Обработчик выхода "мышь над элементом". Сбрасывает выделение с метки. label2_MouseMove private void label2_MouseMove(object sender, MouseEventArgs e) Обработчик "мышь над элементом". Выделяет метку (если она еще не выделена). label3_Click private void label3_Click(object sender, EventArgs e) Обработчик метки "добавить фирму". Открывает форму EditForm для добавления новой фирмы. label2_Click private void label2_Click(object sender, EventArgs e) Обработчик метки "открыть фирму". Открывает форму EditForm для редактирования параметров фирмы. label4_Click private void label4_Click(object sender, EventArgs e) Обработчик метки "удалить фирму". Запрашивает подтверждение на удаление текущей фирмы, при подтверждении удаляет запись фирмы, с соответствующими записями из подчиненной таблицы (формируемыми в коде запросами). label5_Click private void label5_Click(object sender, EventArgs e) Обработчик метки "отчет по фирмам". Открывает окно выбора диапазона времени (SelF), и далее открывает форму Rep1Form с отчетом по доходам фирм за - 13 - выбранный период. Form1_FormClosing private void Form1_FormClosing(object sender, FormClosingEventArgs e) обработчик OnClosing (перед закрытием формы). Освобождает окно выбора времени. label6_Click private void label6_Click(object sender, EventArgs e) Обработчик метки "диаграмма по фирмам". Открывает окно выбора диапазона времени (SelF), и далее открывает форму DiagramForm1 с диаграммой по доходам фирм за выбранный период. label7_Click private void label7_Click(object sender, EventArgs e) Обработчик метки "отчет по месяцам для фирмы". Открывает окно выбора диапазона времени и фирмы(SelF), и далее - открывает форму RepForm2 с отчетом дохода фирмы по месяцам (за выбранный период). label8_Click private void label8_Click(object sender, EventArgs e) Обработчик метки "диаграмма по месяцам для фирмы". Открывает окно выбора диапазона времени и фирмы(SelF), и далее - открывает форму DiagramForm2 с отчетом дохода фирмы по месяцам (за выбранный период). label1_Click private void label1_Click(object sender, EventArgs e) Обработчик метки "выход". Закрывает главное окно. label9_Click private void label9_Click(object sender, EventArgs e) Обработчик метки "о программе". Открывает окно с информацией о программе. EditForm.cs: Имя процедуры (класса EditForm) EditForm Row_Changed Определение, назначение, выполняемые функции, используемые параметры public EditForm() Конструктор, инициализирует поля. private void Row_Changed(object sender, DataRowChangeEventArgs e) Обработчик изменения записи подчиненной таблицы. Заносит значения в поля MonthNum (номер месяца) и Income (доход). New_Row private void New_Row(object sender, DataTableNewRowEventArgs e) Обработчик добавления новой записи подчиненной таблицы. Заносит значения в поля FirmID (на текущую фирму) и Date (текущей датой/временем). - 14 - Operations_RowDeleted void Operations_RowDeleted(object sender, DataRowChangeEventArgs e) Обработчик удаления записи, запрашивает подтверждение на удаление. EditForm_Load private void EditForm_Load(object sender, EventArgs e) Обработчик OnLoad - при открытии формы настраивает компоненты доступа к БД, заполняет таблицы. OkButton_Click private void OkButton_Click(object sender, EventArgs e) Обработчик кнопки OK. Применяет внесенные изменения, сохраняет в БД (с обработкой исключений). EditForm_Shown private void EditForm_Shown(object sender, EventArgs e) Обработчик Shown - при открытии формы (после Load) настраивает поля ввода EditForm_FormClosed private void EditForm_FormClosed(object sender, FormClosedEventArgs e) Обработчик FormClosed. При закрытии формы, освобождает компоненты доступа к БД, созданные "кодом". SelectDateForm.cs: Имя процедуры (класса SelectDateForm) SelectDateForm comboBox1_SelectedIndexChanged Определение, назначение, выполняемые функции, используемые параметры public SelectDateForm() Конструктор, инициализирует поля. private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) Обработчик выбора значения в раскрывающемся списке comboBox1. Вычисляет начальную и конечную даты, в соответствии с выбором. SelectDateForm_Load private void SelectDateForm_Load(object sender, EventArgs e) Обработчик Load - вызывается при открытии формы. Настраивает компоненты окна. button1_Click private void button1_Click(object sender, EventArgs e) Обработчик кнопки "ОК". Проверяет начальную и конечную даты, а также выбор фирмы, закрывает окно с кодом OK. - 15 - Rep1Form.cs: Имя процедуры (класса Rep1Form) Rep1Form Определение, назначение, выполняемые функции, используемые параметры public Rep1Form() ToDate private string ToDate(DateTime T) Rep1Form_Load private void Rep1Form_Load(object sender, EventArgs e) Конструктор, настраивает компоненты окна. Эта функция возвращает строку даты/времени (для T), для использования в SQL-запросе. Обработчик OnLoad - при открытии формы. Настраивает адаптер, формирует запрос, заполняет таблицу, формирует и настраивает отчет. DiagramForm1.cs: Имя процедуры (класса DiagramForm1) DiagramForm1 Определение, назначение, выполняемые функции, используемые параметры public DiagramForm1() ToDate private string ToDate(DateTime T) DiagramForm1_Load private void DiagramForm1_Load(object sender, EventArgs e) Конструктор, настраивает компоненты окна. Эта функция возвращает строку даты/времени (для T), для использования в SQL-запросе. Обработчик OnLoad - при открытии формы настраивает адаптер, формирует запрос, заполняет таблицу. RepForm2.cs: Имя процедуры (класса RepForm2) RepForm2 Определение, назначение, выполняемые функции, используемые параметры public RepForm2() ToDate private string ToDate(DateTime T) Row_Changed private void Row_Changed(object sender, DataRowChangeEventArgs e) Конструктор, настраивает компоненты окна. Эта функция возвращает строку даты/времени (для T), для использования в SQL-запросе. Обработчик изменения записи. Заносит значения в дополнительное поле MonthName (имя месяца), в процессе заполнения таблицы. RepForm2_Load private void RepForm2_Load(object sender, EventArgs e) Обработчик OnLoad - при открытии формы настраивает адаптер, формирует запрос, заполняет таблицу, формирует - 16 - и настраивает отчет. DiagramForm2.cs: Имя процедуры (класса DiagramForm2) DiagramForm2 Определение, назначение, выполняемые функции, используемые параметры public DiagramForm2() ToDate private string ToDate(DateTime T) Row_Changed private void Row_Changed(object sender, DataRowChangeEventArgs e) Конструктор, настраивает компоненты окна. Эта функция возвращает строку даты/времени (для T), для использования в SQL-запросе. Обработчик изменения записи. Заносит значения в дополнительное поле MonthName (имя месяца), в процессе заполнения таблицы. DiagramForm2_Load private void DiagramForm2_Load(object sender, EventArgs e) Обработчик OnLoad - при открытии формы настраивает адаптер, формирует запрос, заполняет таблицу. AboutBox1.cs: Имя процедуры (класса AboutBox1) AboutBox1 AssemblyTitle, AssemblyVersion, AssemblyDescription, AssemblyProduct, AssemblyCopyright, AssemblyCompany Определение, назначение, выполняемые функции, используемые параметры public AboutBox1() Конструктор, инициализирует компоненты окна Эти функции сгенерированы автоматически и в программе не используются Program.cs: Имя процедуры (класса Program) Main Определение, назначение, выполняемые функции, используемые параметры static void Main() Это точка входа в программу, главная функция. Открывает главное окно приложения - 17 - обработчик OnLoad - при открытии формы настраивает компоненты доступа к БД, заполняет таблицы private void EditForm_Load(object sender, EventArgs e) Начало //настройка адаптера заполнения таблиц Connection = new System.Data.OleDb.OleDbConnection(); Connection.ConnectionString = ConnectString; SelectCommand = new System.Data.OleDb.OleDbCommand(); Adapter = new System.Data.OleDb.OleDbDataAdapter(); SelectCommand.Connection = Connection; Adapter.SelectCommand = SelectCommand; //настройка адаптеров (изменение таблиц) firmsTableAdapter.Connection.ConnectionString = ConnectString; operationsTableAdapter.Connection.ConnectionString = ConnectString; Это не новая фирма? CurrentID > 0 заполнение таблицы Operations - только для текущей фирмы SelectCommand.CommandText = "SELECT * FROM Operations…” Adapter.Fill(firmsDataSet.Operations); текущая запись пока на определена CurrentRow = null; заполнение таблицы firms - только одна (текущая) запись SelectCommand.CommandText = "SELECT * FROM firms…” Adapter.Fill(firmsDataSet.firms); выбрать эту запись CurrentRow = firmsDataSet.firms[0]; назначение обработчиков на таблицу Operations firmsDataSet.Operations.RowChanged += new DataRowChangeEventHandler(Row_Changed); firmsDataSet.Operations.TableNewRow += new DataTableNewRowEventHandler(New_Row); firmsDataSet.Operations.RowDeleted += new DataRowChangeEventHandler(Operations_RowDeleted); Конец Вышеуказанный алгоритм предназначен для настройки невизуальных компонентов окна редактирования параметров фирмы (EditForm). Параметры (по умолчанию входные): - CurrentID – ID текущей фирмы (если ноль – это новая фирма); - ConnectString – строка подключения; - таблицы Operations и firms набора данных firmsDataSet (выходные параметры); - ссылка на строку фирмы CurrentRow (из firmsDataSet.firms, выходной параметр). Вышеописанная процедура (обработчик) выполняется перед открытием окна EditForm. Cхема данных - в Приложении 2 - 18 - 6. Описание программы Схема взаимодействия компонентов прикладной программы между собой и с файлами БД: firms.mdb firmsTableAdapter operationsTableAdapter firms Operations Adapter (создано вручную) firmsDataSet (EditForm)) operationsBindingSource bindingNavigator1 (EditForm) firmsDataSet (form1) firms1TableAdapter Компоненты формы EditForm dataGridView1 (EditForm) firms1BindingSource dataGridView1 (form1) Adapter (временный) Adapter (временный) firmsDataSet (Rep1Form) firmsDataSet1 (DiagramForm1) Компоненты отчета Rep1Form firms1BindingSource chart1 (DiagramForm1) Adapter (временный) firmsDataSet1 (RepForm2) Adapter (временный) firmsDataSet1 (DiagramForm2) Компоненты отчета RepForm2 bindingSource1 chart1 (DiagramForm2) - 19 - Список файлов проекта: -<Исходный каталог> (файлы проекта) |-AboutBox1.cs 3 505 |-AboutBox1.Designer.cs 10 977 |-AboutBox1.resx 49 171 |-ClassDiagram1.cd 1 |-CrystalReport1.cs 5 403 |-CrystalReport1.rpt 16 384 |-CrystalReport2.cs 5 403 |-CrystalReport2.rpt 16 384 |-DiagramForm1.cs 2 980 |-DiagramForm1.Designer.cs 5 521 |-DiagramForm1.resx 6 223 |-DiagramForm2.cs 4 425 |-DiagramForm2.Designer.cs 5 494 |-DiagramForm2.resx 6 419 |-EditForm.cs 12 015 |-EditForm.Designer.cs 27 525 |-EditForm.resx 11 797 |-FirmIncomes.csproj 9 211 |-FirmIncomes.csproj.user 219 |-FirmIncomes.sln 911 |-FirmIncomes.suo 38 912 |-firmsDataSet.cs 91 |-firmsDataSet.Designer.cs 224 165 |-firmsDataSet.xsc 361 |-firmsDataSet.xsd 46 592 |-firmsDataSet.xss 2 088 |-Form1.cs 14 247 |-Form1.Designer.cs 19 886 |-Form1.resx 6 839 |-Program.cs 527 |-Rep1Form.cs 3 585 |-Rep1Form.Designer.cs 3 104 |-Rep1Form.resx 6 422 |-RepForm2.cs 4 979 |-RepForm2.Designer.cs 3 127 |-RepForm2.resx 6 219 |-SelectDateForm.cs 7 273 |-SelectDateForm.Designer.cs 8 543 |-SelectDateForm.resx 5 814 | L-<Properties> (свойства проекта) |-AssemblyInfo.cs 2 032 |-Resources.Designer.cs 3 479 |-Resources.resx 5 612 |-Settings.Designer.cs 1 096 L-Settings.settings 249 16.11.2015 16.11.2015 16.11.2015 12.11.2015 12.11.2015 12.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 11.11.2015 06.11.2015 17.11.2015 13.11.2015 13.11.2015 13.11.2015 13.11.2015 13.11.2015 16.11.2015 16.11.2015 16.11.2015 06.11.2015 16.11.2015 13.11.2015 13.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 16.11.2015 14:57:56 14:47:48 14:47:48 9:43:54 11:27:24 11:27:24 10:20:00 10:20:00 14:01:14 9:34:02 9:34:02 14:01:08 10:14:54 10:14:54 15:04:50 15:04:50 15:04:50 14:57:00 16:56:26 9:46:46 15:40:20 16:29:42 16:29:42 16:29:44 16:29:42 16:29:44 15:00:46 15:00:46 15:00:46 9:46:46 14:05:26 15:00:48 15:00:48 14:11:52 9:08:24 9:08:24 15:02:22 15:02:22 15:02:22 06.11.2015 06.11.2015 06.11.2015 06.11.2015 06.11.2015 9:46:46 9:46:46 9:46:46 9:46:46 9:46:46 Исходные тексты программы приведены в приложении 3. Сведения об использованных компонентах и значениях их свойств приводятся в исходных текстах программы с расширением «.Designer.cs» (к каждой форме), в соответствующих разделах «#region Windows Form Designer generated code» (функция InitializeComponent). В этой функции каждый настраиваемый компонент подписан соответствующим комментарием. - 20 - 7.Тестирование программы, примеры результатов работы программы База данных создавалась в СУБД Access из состава Microsoft Office. На этапе проектирования программы был жестко установлен путь к базе данных (firms.mdb), для возможности настройки и проверки всех компонентов доступа к данным (поля, содержание запросов). В конечном итоге путь к файлам БД определяется и задается программно (путь к исполняемому файлу программы), и записывается в строки подключения соответствующих компонентов Connection (OleDbConnection), которые используются SQL-запросами (OleDbCommand) из состава адаптеров подключения (OleDbDataAdapter) на этапе загрузки программы, а также на этапе подготовки диалоговых окон к открытию. Тестирование производилось для каждой функции программы – по мере их написания. - 21 - 8. Руководство пользователя - Программа предназначена для просмотра и редактирования базы данных «Фирмы» . - для установки программы запустите самораспаковывающийся архив FirmIncomes_Redist.exe, и распакуйте архив в выбранную папку. Загрузочный модуль программы - FirmIncomes.exe в выбранной папке. Примечания: 1. В операционной системе должен быть установлен пакет Microsoft Office, и среда исполнения.NET Framework 3.5 2. Также в среде исполнения должны быть установлены компоненты MSChart и Crystal Report (прилагаются в подпапке «Add» распакованного дистрибутива программы) - ОС Windows XP/7/8 , требования к машине (ПЭВМ) накладываются операционной системой. - Запуск программы, просмотр базы данных При запуске программы появляется главное окно (рисунок1). Рисунок 1 В главном окне присутствует таблица со сведениями по фирмам. Навигация по таблице осуществляется клавишами-стрелками, а также клавишами Page Up, Page Down на клавиатуре. Для прокрутки можно также воспользоваться линейкой скроллинга справа от таблицы. - 22 - В таблице главного окна представлены совокупные данные по фирмам, получаемые с помощью SQL-запроса. Поэтому непосредственно редактировать данные в оконной таблице журнала нельзя. - Работа с экранной таблицей, связанной с набором данных (таблицей базы данных) На рисунке 2 представлен пример экранной таблицы, связанной с набором данных (экранная таблица в режиме просмотра). Рисунок 2 У экранной таблицы два режима работы: режим просмотра и режим редактирования ячейки. В режиме просмотра выполняется навигация по таблице. Текущая строка таблицы выделяется специальным маркером ( ) с левой стороны строки. Сверху или снизу от таблицы располагается навигатор ( ). Кнопки навигатора для навигации по таблице: - - первая запись таблицы (набора данных); - - предыдущая запись таблицы (набора данных); - - следующая запись таблицы (набора данных); - - последняя запись таблицы (набора данных). В режиме редактирования содержание текущей ячейки становится доступно для редактирования. Это простое редактирование строки, или выбор значения из раскрывающегося списка (список раскрывается кнопкой в ячейке таблицы), или вызов диалогового окна для задания значения ячейки (вызывается кнопкой в ячейке таблицы). Вход в режим редактирования (текущей ячейки) можно осуществить следующими способами: - щелчком мыши на выделенной ячейке таблицы; - если ячейка редактируется непосредственно, можно сразу вводить текст – таблица автоматически перейдет в режим редактирования и сотрет предыдущее значение ячейки; При изменении содержания ячейки слева от строки появляется знак . В этом случае можно применить изменения («Enter» или переход на другую ячейку), или вернуть прежнее состояние ячейки («Esc»). - 23 - Выход из режима редактирования (текущей ячейки) можно осуществить следующими способами: - выделением щелчком мыши другой ячейки таблицы; - переходом на другую строку таблицы клавишами-стрелками на клавиатуре; - клавишей «Enter»(применение изменений) на клавиатуре, или «Esc» (откат изменений). Изменения текущей строки автоматически корректируются при переходе на другую строку экранной таблицы (вычисляются нередактируемые столбцы). Для вставки новой записи используется кнопка навигатора ( ), или можно выделить последнюю строку таблицы (с пометкой ), и редактировать ее ячейки. Для удаления текущей строки используется кнопка навигатора ( ). При этом программа может выдать запрос на подтверждение удаления. В этом случае нажмите «ОК» для подтверждения удаления текущей записи, или «Отмена» для отказа от удаления. -Добавление новой фирмы Для добавления новой фирмы надо в главном окне щелкнуть мышью по метке «Добавить новую фирму…». Откроется окно «Новая фирма» с параметрами новой фирмы (рисунок 3). рисунок 3 В этом окне необходимо ввести все параметры. Также нужно отметить, что в полях «Название фирмы» и «Номер свидетельства» должны быть непустые уникальные значения, не совпадающие с другими фирмами, иначе сохранить запись не получится. Для сохранения записи нажмите кнопку «Применить изменения записи». Новая запись будет сохранена, а окно покажет дополнительные средства управления (смотри далее «редактирование параметров фирмы»). Для отказа от добавления записи нажмите кнопку «Отмена», при этом окно закроется, новая запись добавлена не будет. -Редактирование параметров фирмы Для редактирования записи надо в таблице главного окна выделить нужную запись, и щелкнуть мышью по метке «Открыть фирму…», или сделать двойной - 24 - щелчок мышью на нужной записи таблицы. Откроется развернутое окно «Параметры фирмы» с параметрами фирмы (рисунок 4). рисунок 4 В группе «Операции с акциями фирмы» можно занести все операции с акциями данной фирмы. Поле «Доход фирмы» не редактируется, оно вычисляется автоматически. Для подтверждения изменений закройте окно кнопкой «Ввод». Для отказа от изменений – «Отмена». -Удаление фирмы Для удаления записи договора надо в таблице главного окна выделить нужную запись, и щелкнуть мышью по метке «Удалить фирму». При этом программа выдаст запрос на подтверждение удаления текущей записи (рисунок 5) Рисунок 5 Нажмите кнопку «Да» для подтверждения удаления текущей записи, или «Нет» для отказа от удаления. -Просмотр и печать отчета по фирмам Для просмотра отчета по фирмам надо в главном окне щелкнуть мышью на метке «Отчет по фирмам...». - 25 - Откроется окно «Выбор диапазона времени», в котором нужно выбрать диапазон времени, для фильтрации операций с акциями (текущая неделя, месяц, квартал и т. д.): Рисунок 6 Выберите нужный диапазон времени и закройте окно кнопкой «Ввод». Откроется предварительный просмотр отчета по договорам (рисунок 7). Рисунок 7 В отчете по фирмам отображается общие сведения по фирмам, а также по их операциям с акциями за указанный период времени: количество записей по операциям, и доход. В окне просмотра отчет можно пролистать (кнопками навигации), смасштабировать ( ), найти в отчете текст ( ). Отчет можно распечатать ( ), в диалоговом окне будет предложено выбрать принтер и указать диапазон страниц для печати. Также отчет можно экспортировать ( ), например, в документ Microsoft Word (.doc), или в документ Adobe Acrobat (.pdf). - 26 - - Диаграмма по фирмам Для просмотра диаграммы по фирмам надо в главном окне щелкнуть мышью на метке «Диаграмма по фирмам...». Откроется окно «Выбор диапазона времени», в котором нужно выбрать диапазон времени, для фильтрации операций с акциями (см. рисунок 6), и далее откроется окно с диаграммой (рисунок 8). Рисунок 8 Закройте окно кнопкой «Закрыть». -Просмотр и печать отчета по месяцам для фирмы Для просмотра отчета по месяцам для фирмы надо в главном окне щелкнуть мышью на метке «Отчет по месяцам для фирмы...». Откроется окно «Выбор фирмы и диапазона времени», в котором нужно выбрать фирму и диапазон времени, для фильтрации операций с акциями (текущая неделя, месяц, квартал и т. д.): - 27 - Рисунок 9 Выберите фирму и нужный диапазон времени и закройте окно кнопкой «Ввод». Откроется предварительный просмотр отчета по месяцам для фирмы (рисунок 10). Рисунок 10 В отчете по месяцам для фирмы отображаются сведения по операциям с акциями данной фирмы за указанный период времени с группировкой по месяцам: количество операций (записей) за месяц, сколько акций куплено/продано, и доход за месяц. В окне просмотра отчет можно пролистать (кнопками навигации), смасштабировать ( ), найти в отчете текст ( ). Отчет можно распечатать ( ), в диалоговом окне будет предложено выбрать принтер и указать диапазон страниц для печати. - 28 - Также отчет можно экспортировать ( ), например, в документ Microsoft Word (.doc), или в документ Adobe Acrobat (.pdf). - Диаграмма по месяцам для фирмы Для просмотра диаграммы по месяцам для фирмы надо в главном окне щелкнуть мышью на метке «Диаграмма по месяцам для фирмы...». Откроется окно «Выбор фирмы и диапазона времени», в котором нужно выбрать фирму и диапазон времени, для фильтрации операций с акциями (см. рисунок 9), и далее откроется окно с диаграммой (рисунок 11). Рисунок 11 Закройте окно кнопкой «Закрыть». - 29 - Сообщения программы: Сообщение программы Тип Действия оператора сообщения Поле ‘firms.Name’ не допускает Ошибка Значение указанного поля не ввод пустых строк. должно быть пустым. Ввести значение поля, или отказаться от изменения/добавления записи Изменения внесены не из-за были успешно Ошибка повторяющихся Фирма с указанным названием, или с указанным номером значений в индексе, ключевых свидетельства уже есть в таблице. полях Введите другие значения в эти или связях. Измените данные в поле или в полях, поля, содержащих изменения/добавления записи значения, удалите переопределите разрешить повторяющиеся индекс его, или чтобы повторяющиеся значения, и повторите попытку - 30 - или откажитесь от 9. Литература 1. Н. Культин. Microsoft Visual C# в задачах и примерах. – Спб: БХВПетербург, 2009. – 322 с. 2. Павловская Т.А. С#. Программирование на языке высокого уровня. – Спб: Питер, 2009. - 432 с. 3. Руководство по программированию на C# [Электронный ресурс] Заголовок с экрана.- Режим доступа: http://msdn.microsoft.com/ru-ru/library/67ef8sbd.aspx. 4. Благодатских В.А. и др. Стандартизация разработки программных средств: Учеб пособие / В.А. Благодатских, В.А. Волнин, К.Ф. Поскакалов; под ред. О.С. Разумова. – М.: Финансы и статистика, 2005. – 288 с. 5. Вендров А.М. Проектирование программного обеспечения экономических информационных систем: Учебник - М.: Финансы и статистика, 2000. – 352 с. 6. ГОСТ 19.103 – 77. ЕСПД. Обозначение программ и программных документов. - М.: Изд-во стандартов, 1977. 7. ГОСТ 19.401 – 78. ЕСПД. Текст программы. Требования к содержанию и оформлению. - М.: Изд-во стандартов, 1978. 8. ГОСТ 19.505 – 79. ЕСПД. Руководство оператора. Требования к содержанию и оформлению. - М.: Изд-во стандартов, 1977. 9. ГОСТ 19.701 - 90. ЕСПД. Схемы алгоритмов, программ, данных и систем. Условные обозначения и правила выполнения. - М.: Изд-во стандартов. - 1990. 10.Майерс Г. Искусство тестирования программ. - М.: Финансы статистика, 1982. - 176 с. - 31 - и Приложение 1 Иерархическая модель программы Program.cs Form1.cs EditForm.cs Form1 Form1_Load MouseEnterMove label3_MouseEnter EditRec RepForm2.cs EditForm AppIdle RepForm2 Row_Changed FormShow ToDate New_Row PostButtonClick Row_Changed Operations_RowDeleted CancelButtonClick EditForm_Load CloseButtonClick OkButton_Click FormClose label3_MouseLeave DiagramForm1 label2_MouseMove label3_Click label2_Click label4_Click EditForm_Shown ToDate AboutBox1.cs DiagramForm1_Load EditForm_FormClosed AboutBox1 DiagramForm2.cs DiagramForm2 ToDate Row_Changed Rep1Form.cs DiagramForm2_Load label5_Click Rep1Form Form1_FormClosing ToDate label6_Click Rep1Form_Load label7_Click label8_Click RepForm2_Load DiagramForm1.cs SelectDateForm.cs label1_Click SelectDateForm label9_Click comboBox1_SelectedIndexChanged SelectDateForm_Load button1_Click - 32 - Приложение 2 Схема данных Форма form1 для просмотра совокупных данных по фирмам Данные о фирмах Данные по операциям фирм с акциями Таблица «фирмы» Ввод данных по фирмам и операциях фирм с акциями Форма EditForm редактирования данных по фирме и ее операциям с акциями Таблица «Операции с акциями» Формирование Ведомости “...” Форма Rep1Form для просмотра и печати ведомости Ведомость "..." - 33 - обработчик Shown - при открытии формы(после Load) настраивает поля ввода private void EditForm_Shown(object sender, EventArgs e) Начало нет Это новая фирма? CurrentRow == null да Заголовок окна Text = "Параметры фирмы"; Заголовок окна Text = "Новая фирма"; поля ввода (параметры фирмы) textBox1.Text = CurrentRow.Name; textBox2.Text = CurrentRow.Certificate; textBox3.Text = CurrentRow.Director; поля ввода (параметры фирмы) textBox1.Text = ""; textBox2.Text = ""; textBox3.Text = ""; Показать сетку с операциями по фирме groupBox1.Visible = true; Скрыть сетку с операциями по фирме groupBox1.Visible = false; Конец Вышеуказанный алгоритм предназначен для настройки визуальных компонентов окна редактирования параметров фирмы (EditForm). Параметры (по умолчанию входные): - ссылка на строку фирмы CurrentRow (из firmsDataSet.firms). Вышеописанная процедура (обработчик) выполняется перед открытием окна EditForm, после обработчика Load. - 34 - обработчик кнопки OK применяет внесенные изменения, сохраняет в БД (с обработкой исключений) private void OkButton_Click(object sender, EventArgs e) Начало нет да новая фирма? CurrentRow == null Создать запись CurrentRow = firmsDataSet.firms.NewfirmsRow(); нет поля записи изменились, или были изменения в подчиненной таблице (IsChanged) настроить поля CurrentRow.Name = textBox1.Text; CurrentRow.Certificate = textBox2.Text; CurrentRow.Director = textBox3.Text; да закрыть окно с кодом Cancel (изменений записей не было) this.DialogResult = DialogResult.Cancel; включить в таблицу firmsDataSet.firms.AddfirmsRow(CurrentRow); применить изменения (сохранить в БД) this.firmsTableAdapter.Update(CurrentRow); настроить поля записи CurrentRow.Name = textBox1.Text; CurrentRow.Certificate = textBox2.Text; CurrentRow.Director = textBox3.Text; ошибка сохранения в БД нет применить изменения (сохранить в БД) this.firmsTableAdapter.Update(CurrentRow); нет ошибка сохранения в БД да очистить таблицу firmsDataSet.firms.Clear(); да сформировать запрос на чтение добавленной записи SelectCommand.CommandText = "SELECT * …” вывод сообщения об ошибке заполнить таблицу (прочесть запись) Adapter.Fill(firmsDataSet.firms); откат на прежние позиции(прочесть запись заново) firmsDataSet.firms.Clear(); SelectCommand.CommandText = "SELECT *” Adapter.Fill(firmsDataSet.firms); CurrentRow = firmsDataSet.firms[0]; текущая запись CurrentRow = firmsDataSet.firms[0]; узнать ID новой фирмы CurrentID = CurrentRow.ID; Изменить заголовок, показать подчиненную таблицу Text = "Параметры фирмы"; groupBox1.Visible = true; признак изменений в окне (создана новая фирма) IsChanged = true; применить изменения подчиненной таблицы(ошибок от БД Access не ожидается) operationsTableAdapter.Update(firmsDataSet.Operations); вывод сообщения об ошибке //закрыть окно с кодом OK this.DialogResult = DialogResult.OK; откат на прежние позиции firmsDataSet.firms.Clear(); CurrentRow = null; Конец Вышеуказанный алгоритм предназначен для обработки нажатия кнопки “OK” в окне редактирования параметров фирмы (EditForm), и выполняет различные действия в зависимости от контекста: новая фирма – сохраняет ее в БД, переоткрывает ее (чтобы узнать ID), и показывает сетку с операциями по фирме; существующая фирма – сохраняет изменения в БД, и закрывает окно с кодом OK. - 35 - обработчик метки "добавить фирму" открывает форму EditForm для добавления новой фирмы private void label3_Click(object sender, EventArgs e) Начало Создать и настроить окно(новая фирма) EditForm EditF = new EditForm(); EditF.CurrentID = 0; EditF.ConnectString = ConnectString; Открыть окно EditF.ShowDialog(this) нет окно закрыто кнопкой OK или была создана новая фирма EditF.ShowDialog(this) == DialogResult.OK || EditF.IsChanged да обновить запрос firms1TableAdapter.Fill(this.firmsDataSet.firms1); (найти текущую (новую) фирму) первая строка firms1BindingSource.MoveFirst(); firms1BindingSource.Current!=null нет да текущая строка firmsDataSet.firms1Row Row = (firmsDataSet.firms1Row)((DataRowView)firms1BindingSource.Current).Row; фирма найдена if (Row.ID == EditF.CurrentID) да нет последняя строка firms1BindingSource.Position + 1 >= firms1BindingSource.Count да нет следующая строка firms1BindingSource.MoveNext(); удалить окно EditF.Dispose(); Конец Вышеуказанный алгоритм предназначен для добавления новой фирмы (обработчик метки), с использованием окна параметров фирмы (EditForm). - 36 - обработчик метки "открыть фирму" открывает форму EditForm для редактирования параметров фирмы private void label2_Click(object sender, EventArgs e) Начало нет текущая фирма выбрана firms1BindingSource.Current!=null да Создать окно EditForm EditF = new EditForm(); текущая строка firmsDataSet.firms1Row Row = (firmsDataSet.firms1Row)((DataRowView)firms1BindingSource.Current).Row; Настроить окно(новая фирма) EditF.CurrentID = Row.ID; EditF.ConnectString = ConnectString; Открыть окно EditF.ShowDialog(this) окно закрыто кнопкой OK EditF.ShowDialog(this) == DialogResult.OK нет да обновить запрос firms1TableAdapter.Fill(this.firmsDataSet.firms1); (найти текущую (новую) фирму) первая строка firms1BindingSource.MoveFirst(); firms1BindingSource.Current!=null нет да текущая строка firmsDataSet.firms1Row Row = (firmsDataSet.firms1Row)((DataRowView)firms1BindingSource.Current).Row; фирма найдена if (Row.ID == EditF.CurrentID) да нет последняя строка firms1BindingSource.Position + 1 >= firms1BindingSource.Count да нет следующая строка firms1BindingSource.MoveNext(); удалить окно EditF.Dispose(); Конец Вышеуказанный алгоритм предназначен для редактирования параметров существующей фирмы (обработчик метки), с использованием окна EditForm. - 37 - Приложение 3 Текст программы. Файл программы Program.cs using using using using System; System.Collections.Generic; System.Linq; System.Windows.Forms; namespace FirmIncomes { static class Program { /// <summary> /// Главная точка входа для приложения. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } } Файл Form1.cs using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; namespace FirmIncomes { public partial class Form1 : Form - 38 - { public System.Windows.Forms.Label CurrentLabel; //текущая метка public string ConnectString; //строка подключения (путь к БД - где лежит exe-шник) private SelectDateForm SelF; //окно выбора диапазона времени, и фирмы //конструктор, настраивает поля public Form1() { InitializeComponent(); CurrentLabel = null; ConnectString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + System.AppDomain.CurrentDomain.BaseDirectory + "firms.mdb"; } //обработчик Load - вызывается при открытии формы //настраивает адаптеры, заполняет таблицы private void Form1_Load(object sender, EventArgs e) { // TODO: данная строка кода позволяет загрузить данные в таблицу "firmsDataSet.firms1". При необходимости она может быть перемещена или удалена. firms1TableAdapter.Connection.ConnectionString = ConnectString; this.firms1TableAdapter.Fill(this.firmsDataSet.firms1); SelF = new SelectDateForm();//создать окно выбора диапазона времени (чтобы сохранять выбранное время между вызовами) } //метод для визуального выбора метки при наведении на нее указателя мыши //используется в обработчиках MouseEnter, MouseMove private void MouseEnterMove(object sender) { System.Windows.Forms.Label label = (System.Windows.Forms.Label)sender; if (CurrentLabel != label) { if (CurrentLabel != null) CurrentLabel.BorderStyle = BorderStyle.None; label.BorderStyle = BorderStyle.FixedSingle; CurrentLabel = label; } } //обработчик входа "мышь над элементом" //выделяет метку - 39 - private void label3_MouseEnter(object sender, EventArgs e) { MouseEnterMove(sender); } //обработчик выхода "мышь над элементом" //сбрасывает выделение с метки private void label3_MouseLeave(object sender, EventArgs e) { System.Windows.Forms.Label label = (System.Windows.Forms.Label)sender; if (CurrentLabel == label) { label.BorderStyle = BorderStyle.None; CurrentLabel = null; } } //обработчик "мышь над элементом" //выделяет метку (если она еще не выделена) private void label2_MouseMove(object sender, MouseEventArgs e) { MouseEnterMove(sender); } //обработчик метки "добавить фирму" //открывает форму EditForm для добавления новой фирмы private void label3_Click(object sender, EventArgs e) { EditForm EditF = new EditForm(); EditF.CurrentID = 0; EditF.ConnectString = ConnectString; if (EditF.ShowDialog(this) == DialogResult.OK || EditF.IsChanged) { //обновить запрос this.firms1TableAdapter.Fill(this.firmsDataSet.firms1); //найти текущую запись this.firms1BindingSource.MoveFirst(); while (firms1BindingSource.Current!=null) { firmsDataSet.firms1Row Row = (firmsDataSet.firms1Row)((DataRowView)firms1BindingSource.Current).Row; if (Row.ID == EditF.CurrentID) break; if (firms1BindingSource.Position + 1 >= firms1BindingSource.Count) break; firms1BindingSource.MoveNext(); - 40 - } } EditF.Dispose(); } //обработчик метки "открыть фирму" //открывает форму EditForm для редактирования параметров фирмы private void label2_Click(object sender, EventArgs e) { if (firms1BindingSource.Current != null) { EditForm EditF = new EditForm(); firmsDataSet.firms1Row Row = (firmsDataSet.firms1Row)((DataRowView)firms1BindingSource.Current).Row; EditF.CurrentID = Row.ID; EditF.ConnectString = ConnectString; if (EditF.ShowDialog(this) == DialogResult.OK) { //обновить запрос this.firms1TableAdapter.Fill(this.firmsDataSet.firms1); //найти текущую запись this.firms1BindingSource.MoveFirst(); while (firms1BindingSource.Current != null) { Row = (firmsDataSet.firms1Row)((DataRowView)firms1BindingSource.Current).Row; if (Row.ID == EditF.CurrentID) break; if (firms1BindingSource.Position + 1 >= firms1BindingSource.Count) break; firms1BindingSource.MoveNext(); } } EditF.Dispose(); } else MessageBox.Show("Выберите фирму для открытия!", "ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); } //обработчик метки "удалить фирму" //запрашивает подтверждение на удаление текущей фирмы, //при подтверждении удаляет запись фирмы, с соответствующими записями из подчиненной таблицы (формируемыми в коде запросами). private void label4_Click(object sender, EventArgs e) { if (firms1BindingSource.Current != null) { - 41 - firmsDataSet.firms1Row Row = (firmsDataSet.firms1Row)((DataRowView)firms1BindingSource.Current).Row; if (MessageBox.Show("Удалить фирму \""+Row.Name+"\" (со всеми операциями по ней)?", "Предупреждение", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) { int CurrentID = Row.ID, NextID = 1, OperationsDeleted = 0; //поиск текущей записи после удаления if (firms1BindingSource.Position + 1 < firms1BindingSource.Count) firms1BindingSource.Position = firms1BindingSource.Position + 1; else if (firms1BindingSource.Count > 1) firms1BindingSource.Position = firms1BindingSource.Position - 1; else NextID = 0; if (NextID == 1) { firmsDataSet.firms1Row NewRow = (firmsDataSet.firms1Row)((DataRowView)firms1BindingSource.Current).Row; NextID = NewRow.ID; } { //удаление строк подчиненной таблицы и строки главной таблицы - формируемым запросом System.Data.OleDb.OleDbConnection Connection = new System.Data.OleDb.OleDbConnection(); Connection.ConnectionString = ConnectString; System.Data.OleDb.OleDbCommand SelectCommand = new System.Data.OleDb.OleDbCommand(); SelectCommand.Connection = Connection; Connection.Open(); SelectCommand.CommandText = "DELETE FROM Operations WHERE(FirmID = " + Convert.ToString(CurrentID) + ")"; OperationsDeleted = SelectCommand.ExecuteNonQuery(); SelectCommand.CommandText = "DELETE FROM firms WHERE(ID = " + Convert.ToString(CurrentID) + ")"; SelectCommand.ExecuteNonQuery(); Connection.Close(); SelectCommand.Dispose(); Connection.Dispose(); } //обновить запрос firmsDataSet.firms1.Clear(); this.firms1TableAdapter.Fill(this.firmsDataSet.firms1); - 42 - //найти текущую запись(NextID) if (NextID > 0) { this.firms1BindingSource.MoveFirst(); while (firms1BindingSource.Current != null) { Row = (firmsDataSet.firms1Row)((DataRowView)firms1BindingSource.Current).Row; if (Row.ID == NextID) break; if (firms1BindingSource.Position + 1 >= firms1BindingSource.Count) break; firms1BindingSource.MoveNext(); } } } } else MessageBox.Show("Выберите фирму для удаления!", "ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); } //обработчик метки "отчет по фирмам" //открывает окно выбора диапазона времени (SelF), и далее - открывает форму Rep1Form //с отчетом по доходам фирм за выбранный период private void label5_Click(object sender, EventArgs e) { SelF.FDataSet = null; if (SelF.ShowDialog() == DialogResult.OK) { Rep1Form F = new Rep1Form(); F.SelectF = SelF; F.ConnectString = ConnectString; F.ShowDialog(); F.Dispose(); } } //обработчик OnClosing (перед закрытием формы), освобождает окно выбора времени private void Form1_FormClosing(object sender, FormClosingEventArgs e) { SelF.Dispose(); } //обработчик метки "диаграмма по фирмам" //открывает окно выбора диапазона времени (SelF), и далее - открывает форму DiagramForm1 //с диаграммой по доходам фирм за выбранный период private void label6_Click(object sender, EventArgs e) - 43 - { SelF.FDataSet = null; if (SelF.ShowDialog() == DialogResult.OK) { DiagramForm1 F = new DiagramForm1(); F.SelectF = SelF; F.ConnectString = ConnectString; F.ShowDialog(); F.Dispose(); } } //обработчик метки "отчет по месяцам для фирмы" //открывает окно выбора диапазона времени и фирмы(SelF), и далее - открывает форму RepForm2 //с отчетом дохода фирмы по месяцам (за выбранный период) private void label7_Click(object sender, EventArgs e) { SelF.FDataSet = firmsDataSet; if (SelF.ShowDialog() == DialogResult.OK) { RepForm2 F = new RepForm2(); F.SelectF = SelF; F.ConnectString = ConnectString; F.firms1 = firmsDataSet.firms1; F.ShowDialog(); F.Dispose(); } } //обработчик метки "диаграмма по месяцам для фирмы" //открывает окно выбора диапазона времени и фирмы(SelF), и далее - открывает форму DiagramForm2 //с отчетом дохода фирмы по месяцам (за выбранный период) private void label8_Click(object sender, EventArgs e) { SelF.FDataSet = firmsDataSet; if (SelF.ShowDialog() == DialogResult.OK) { DiagramForm2 F = new DiagramForm2(); F.SelectF = SelF; F.ConnectString = ConnectString; F.firms1 = firmsDataSet.firms1; F.ShowDialog(); F.Dispose(); - 44 - } } //обработчик метки "выход" //закрывает главное окно private void label1_Click(object sender, EventArgs e) { Close(); } //обработчик метки "о программе" //открывает окно с информацией о программе private void label9_Click(object sender, EventArgs e) { AboutBox1 Box = new AboutBox1(); Box.ShowDialog(); Box.Dispose(); } } } Файл EditForm.cs using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; namespace FirmIncomes { public partial class EditForm : Form { public int CurrentID; private firmsDataSet.firmsRow CurrentRow; private bool NoChange; public bool IsChanged; public string ConnectString; //ID текущей записи фирмы //текущая запись фирмы //признак пропуска обработчиков событий (для БД) //признак изменения данных в окне //строка подключения private System.Data.OleDb.OleDbConnection Connection; //набор компонентов - 45 - private System.Data.OleDb.OleDbCommand SelectCommand; private System.Data.OleDb.OleDbDataAdapter Adapter; //для заполнения таблиц //(формируемым в коде запросом) //конструктор, инициализирует поля public EditForm() { InitializeComponent(); CurrentID = 0; NoChange = false; IsChanged = false; ConnectString = ""; } //обработчик изменения записи подчиненной таблицы //заносит значения в поля MonthNum (номер месяца) и Income (доход) private void Row_Changed(object sender, DataRowChangeEventArgs e) { if (!NoChange) { firmsDataSet.OperationsRow Row = (firmsDataSet.OperationsRow)e.Row; DateTime T = Row.Date; NoChange = true; Row.MonthNum = T.Year * 12 + T.Month; if(Row["SalePrice"]==DBNull.Value) Row.SalePrice = 0; if (Row["SaleCount"] == DBNull.Value) Row.SaleCount = 0; if (Row["PurchasePrice"] == DBNull.Value) Row.PurchasePrice = 0; if (Row["PurchaseCount"] == DBNull.Value) Row.PurchaseCount = 0; Row.Income = Row.SalePrice * Row.SaleCount - Row.PurchasePrice * Row.PurchaseCount; IsChanged = true; //CancButton.Text = "Cancel"; NoChange = false; } } //обработчик добавления новой записи подчиненной таблицы //заносит значения в поля FirmID (на текущую фирму) и Date (текущей датой/временем) private void New_Row(object sender, DataTableNewRowEventArgs e) { firmsDataSet.OperationsRow Row = (firmsDataSet.OperationsRow)e.Row; Row.FirmID = CurrentID; - 46 - Row.Date = DateTime.Now; Row.MonthNum = 12 * Row.Date.Year + Row.Date.Month; } //обработчик удаления записи, запрашивает подтверждение на удаление void Operations_RowDeleted(object sender, DataRowChangeEventArgs e) { //throw new NotImplementedException(); if (e.Row.RowState == DataRowState.Deleted) { if (MessageBox.Show("Удалить текущую строку?", "Предупреждение", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel) { NoChange = true; e.Row.RejectChanges();//восстановить запись NoChange = false; return; } } IsChanged = true;// CancButton.Text = "Cancel"; } //обработчик OnLoad - при открытии формы //настраивает компоненты доступа к БД, заполняет таблицы private void EditForm_Load(object sender, EventArgs e) { //настройка адаптера заполнения таблиц Connection = new System.Data.OleDb.OleDbConnection(); Connection.ConnectionString = ConnectString; SelectCommand = new System.Data.OleDb.OleDbCommand(); Adapter = new System.Data.OleDb.OleDbDataAdapter(); SelectCommand.Connection = Connection; Adapter.SelectCommand = SelectCommand; //настройка адаптеров this.firmsTableAdapter.Connection.ConnectionString = ConnectString; this.operationsTableAdapter.Connection.ConnectionString = ConnectString; if (CurrentID > 0) { {//заполнение таблиц Operations - только для текущей фирмы, firms - только текущая запись (формируется запрос) - 47 - SelectCommand.CommandText = "SELECT * FROM Operations WHERE(FirmID = " + Convert.ToString(CurrentID) + ") ORDER BY [Date]"; Adapter.Fill(firmsDataSet.Operations); SelectCommand.CommandText = "SELECT * FROM firms WHERE(ID = " + Convert.ToString(CurrentID) + ")"; Adapter.Fill(firmsDataSet.firms); CurrentRow = firmsDataSet.firms[0]; } } else CurrentRow = null; //обработчики событий на Operations firmsDataSet.Operations.RowChanged += new DataRowChangeEventHandler(Row_Changed); firmsDataSet.Operations.TableNewRow += new DataTableNewRowEventHandler(New_Row); firmsDataSet.Operations.RowDeleted += new DataRowChangeEventHandler(Operations_RowDeleted); } //обработчик кнопки OK //применяет внесенные изменения, сохраняет в БД (с обработкой исключений) private void OkButton_Click(object sender, EventArgs e) { if (CurrentRow == null) //новая фирма { //создать запись, настроить поля и включить в таблицу CurrentRow = firmsDataSet.firms.NewfirmsRow(); CurrentRow.Name = textBox1.Text; CurrentRow.Certificate = textBox2.Text; CurrentRow.Director = textBox3.Text; firmsDataSet.firms.AddfirmsRow(CurrentRow); try { //применить изменения (сохранить в БД) this.firmsTableAdapter.Update(CurrentRow); } catch(Exception Ex) { //откат на прежние позиции при ошибке(от БД Access) MessageBox.Show(Ex.Message, "Ошибка БД", MessageBoxButtons.OK, MessageBoxIcon.Error); firmsDataSet.firms.Clear(); CurrentRow = null; return; } - 48 - //DataRow[] Rows = firmsDataSet.firms.Select("(Name='" + textBox1.Text+"')AND(Certificate='"+ textBox2.Text+"')AND(Director='"+ textBox3.Text+"')"); //CurrentRow = (firmsDataSet.firmsRow)Rows[0]; //заново открыть примененную запись, чтобы узнать ID записи (автоинкрементное поле, назначается в БД Access) firmsDataSet.firms.Clear(); SelectCommand.CommandText = "SELECT * FROM firms WHERE(Name='" + textBox1.Text + "')AND(Certificate='" + textBox2.Text + "')AND(Director='" + textBox3.Text + "')"; Adapter.Fill(firmsDataSet.firms); CurrentRow = firmsDataSet.firms[0]; CurrentID = CurrentRow.ID; //изменить заголовок, показать подчиненную таблицу Text = "Параметры фирмы"; IsChanged = true;// CancButton.Text = "Cancel"; groupBox1.Visible = true; } else //существующая фирма { //создать настроить поля записи string aName = CurrentRow["Name"] == DBNull.Value ? "" : CurrentRow.Name; string aCertificate = CurrentRow["Certificate"] == DBNull.Value ? "" : CurrentRow.Certificate; string aDirector = CurrentRow["Director"] == DBNull.Value ? "" : CurrentRow.Director; if (!IsChanged && textBox1.Text == aName && textBox2.Text == aCertificate && textBox3.Text == aDirector) { //закрыть отно с кодом Cancel (изменений записей не было) this.DialogResult = DialogResult.Cancel; return; } //настроить поля записи CurrentRow.Name = textBox1.Text; CurrentRow.Certificate = textBox2.Text; CurrentRow.Director = textBox3.Text; try { //применить изменения (сохранить в БД) this.firmsTableAdapter.Update(CurrentRow); } catch (Exception Ex) { //откат на прежние позиции при ошибке(от БД Access) - 49 - MessageBox.Show(Ex.Message, "Ошибка БД", MessageBoxButtons.OK, MessageBoxIcon.Error); firmsDataSet.firms.Clear(); SelectCommand.CommandText = "SELECT * FROM firms WHERE(ID = " + Convert.ToString(CurrentID) + ")"; Adapter.Fill(firmsDataSet.firms); CurrentRow = firmsDataSet.firms[0]; return; } //применить изменения подчиненной таблицы(ошибок от БД Access не ожидается) this.operationsTableAdapter.Update(firmsDataSet.Operations); //закрыть отно с кодом OK this.DialogResult = DialogResult.OK; } } //обработчик Shown - при открытии формы(после Load) //настраивает поля ввода private void EditForm_Shown(object sender, EventArgs e) { if (CurrentRow == null) { Text = "Новая фирма"; textBox1.Text = ""; textBox2.Text = ""; textBox3.Text = ""; groupBox1.Visible = false; } else { Text = "Параметры фирмы"; textBox1.Text = CurrentRow.Name; //(string)CurrentRow["Name"]; textBox2.Text = CurrentRow.Certificate; //(string)CurrentRow["Certificate"]; textBox3.Text = CurrentRow.Director; //(string)CurrentRow["Director"]; groupBox1.Visible = true; } } //обработчик Closed - при закрытии формы - освобождает компоненты доступа к БД, созданные "кодом" private void EditForm_FormClosed(object sender, FormClosedEventArgs e) { Adapter.Dispose(); SelectCommand.Dispose(); Connection.Dispose(); - 50 - } } } Файл SelectDateForm.cs using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; namespace FirmIncomes { public partial class SelectDateForm : { public DateTime MinDate, MaxDate; public int SelDateValue; private int FirmID; public firmsDataSet FDataSet; public int SelFirm; Form //начальная, конечная даты //индекс в раскр-ся списке comboBox1 (выбор даты) //ID записи фирмы //набор данных главной формы(для заполнения списка фирм) //индекс в раскр-ся списке comboBox2 (выбор фирмы) //конструктор, инициализирует поля public SelectDateForm() { InitializeComponent(); SelDateValue = 0; FirmID = 0; FDataSet = null; } //обработчик выбора значения в раскрывающемся списке comboBox1 //вычисляет начальную и конечную даты, в соответствии с выбором private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { switch (comboBox1.SelectedIndex) { case 0://текущая неделя { DateTime CurrentDate = DateTime.Now; int DayOfW = (int)CurrentDate.DayOfWeek; - 51 - DateTime MDate = new DateTime(CurrentDate.Year, CurrentDate.Month, CurrentDate.Day); if (DayOfW == 0) DayOfW = 6; else DayOfW--; if (DayOfW > 0) MDate = MDate.AddDays(-DayOfW); dateTimePicker1.Value = MDate; MDate = MDate.AddDays(7); MDate = MDate.AddSeconds(-1); dateTimePicker2.Value = MDate; } break; case 1://текущий месяц { DateTime CurrentDate = DateTime.Now; DateTime MDate = new DateTime(CurrentDate.Year, CurrentDate.Month, 1); dateTimePicker1.Value = MDate; MDate = MDate.AddMonths(1); MDate = MDate.AddSeconds(-1); dateTimePicker2.Value = MDate; } break; case 2://текущий квартал { DateTime CurrentDate = DateTime.Now; int Month = CurrentDate.Month; DateTime MDate = new DateTime(CurrentDate.Year, Month, 1); Month--; Month %= 3; if (Month > 0) MDate = MDate.AddMonths(-Month); dateTimePicker1.Value = MDate; MDate = MDate.AddMonths(3); MDate = MDate.AddSeconds(-1); dateTimePicker2.Value = MDate; } break; case 3://текущий год { DateTime CurrentDate = DateTime.Now; DateTime MDate = new DateTime(CurrentDate.Year, 1, 1); dateTimePicker1.Value = MDate; - 52 - MDate = MDate.AddYears(1); MDate = MDate.AddSeconds(-1); dateTimePicker2.Value = MDate; } break; case 4://определить даты { } break; case 5://за все время { } break; } dateTimePicker1.Enabled = (comboBox1.SelectedIndex == 4); dateTimePicker2.Enabled = (comboBox1.SelectedIndex == 4); } //обработчик Load - вызывается при открытии формы //настраивает компоненты окна private void SelectDateForm_Load(object sender, EventArgs e) { comboBox1.SelectedIndex = SelDateValue; if (SelDateValue == 4 || SelDateValue == 5) { dateTimePicker1.Value = MinDate; dateTimePicker2.Value = MaxDate; } if (FDataSet != null) { Text = "Выбор фирмы и диапазона времени"; label4.Visible = true; comboBox2.Visible = true; comboBox2.Items.Clear(); for (int i = 0; i < FDataSet.firms1.Rows.Count; i++) comboBox2.Items.Add(FDataSet.firms1[i].Name); if (comboBox2.Items.Count > 0) { if (FirmID == 0) comboBox2.SelectedIndex = 0; else { int i; for (i = 0; i < FDataSet.firms1.Rows.Count; i++) - 53 - if (FDataSet.firms1[i].ID == FirmID) break; if (i < FDataSet.firms1.Rows.Count) comboBox2.SelectedIndex = i; else comboBox2.SelectedIndex = 0; } } } else { Text = "Выбор диапазона времени"; label4.Visible = false; comboBox2.Visible = false; } } //обработчик кнопки "ОК" //проверяет начальную и конечную даты, а также выбор фирмы, //закрывает окно с кодом OK private void button1_Click(object sender, EventArgs e) { if (dateTimePicker1.Value >= dateTimePicker2.Value) { MessageBox.Show("Дата 'С:' должна быть меньше даты 'По:'!", "ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } MinDate = dateTimePicker1.Value; MaxDate = dateTimePicker2.Value; SelDateValue = comboBox1.SelectedIndex; if (FDataSet != null) { if (comboBox2.Items.Count > 0) { SelFirm = comboBox2.SelectedIndex; FirmID = FDataSet.firms1[SelFirm].ID; } else { MessageBox.Show("Выберите фирму!", "ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } DialogResult = DialogResult.OK; } - 54 - } } Файл Rep1Form.cs using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; CrystalDecisions.CrystalReports.Engine; namespace FirmIncomes { public partial class Rep1Form : Form { public SelectDateForm SelectF; //окно выбора диапазона дат public string ConnectString; //строка подключения private ReportDocument customerReport;//текущий отчет //конструктор, настраивает компоненты окна public Rep1Form() { InitializeComponent(); } //эта функция возвращает строку даты/времени (для T), для использования в SQL-запросе private string ToDate(DateTime T) { return "#" + T.ToString("MM") + "/" + T.ToString("dd") + "/" + T.ToString("yyyy") + " " + T.ToString("HH:mm:ss") + "#"; } //обработчик OnLoad - при открытии формы //настраивает адаптер, формирует запрос, заполняет таблицу, формирует и настраивает отчет private void Rep1Form_Load(object sender, EventArgs e) { TextObject text; string OnStr; System.Data.OleDb.OleDbConnection Connection = new System.Data.OleDb.OleDbConnection(); - 55 - Connection.ConnectionString = ConnectString; System.Data.OleDb.OleDbCommand SelectCommand = new System.Data.OleDb.OleDbCommand(); System.Data.OleDb.OleDbDataAdapter Adapter = new System.Data.OleDb.OleDbDataAdapter(); SelectCommand.Connection = Connection; Adapter.SelectCommand = SelectCommand; //"#dd/MM/yyyy HH:mm:ss#" if (SelectF.SelDateValue == 5) OnStr = "firms.ID = Operations.FirmID"; else OnStr = "((firms.ID = Operations.FirmID)AND(Operations.[Date] >=" + ToDate(SelectF.MinDate) + ")AND(Operations.[Date] <=" + ToDate(SelectF.MaxDate) + "))"; SelectCommand.CommandText = "SELECT firms.ID, firms.Name, firms.Certificate, firms.Director, COUNT(Operations.ID) AS OpCount, SUM(Operations.Income) AS AllSum " + "FROM (firms LEFT OUTER JOIN Operations ON " + OnStr + ")"+ "GROUP BY firms.ID, firms.Name, firms.Certificate, firms.Director " + "ORDER BY firms.Name "; Adapter.Fill(firmsDataSet1.firms1); Adapter.Dispose(); SelectCommand.Dispose(); Connection.Dispose(); customerReport = new ReportDocument(); string reportPath = Application.StartupPath + "\\" + "CrystalReport1.rpt"; customerReport.Load(reportPath); text = customerReport.ReportDefinition.ReportObjects["Text6"] as TextObject; if (SelectF.SelDateValue == 5) text.Text = "Итоговый отчет по фирмам за все время"; else text.Text = "Итоговый отчет по фирмам с " + SelectF.MinDate.ToString("dd.MM.yyyy HH:mm:ss") + " по " + SelectF.MaxDate.ToString("dd.MM.yyyy HH:mm:ss"); customerReport.SetDataSource(firmsDataSet1); crystalReportViewer1.ReportSource = customerReport; } } } Файл DiagramForm1.cs using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; - 56 - using System.Text; using System.Windows.Forms; namespace FirmIncomes { public partial class DiagramForm1 : Form { public SelectDateForm SelectF; //окно выбора диапазона дат public string ConnectString; //строка подключения //конструктор, настраивает компоненты окна public DiagramForm1() { InitializeComponent(); } //эта функция возвращает строку даты/времени (для T), для использования в SQL-запросе private string ToDate(DateTime T) { return "#" + T.ToString("MM") + "/" + T.ToString("dd") + "/" + T.ToString("yyyy") + " " + T.ToString("HH:mm:ss") + "#"; } //обработчик OnLoad - при открытии формы //настраивает адаптер, формирует запрос, заполняет таблицу private void DiagramForm1_Load(object sender, EventArgs e) { string OnStr; System.Data.OleDb.OleDbConnection Connection = new System.Data.OleDb.OleDbConnection(); Connection.ConnectionString = ConnectString; System.Data.OleDb.OleDbCommand SelectCommand = new System.Data.OleDb.OleDbCommand(); System.Data.OleDb.OleDbDataAdapter Adapter = new System.Data.OleDb.OleDbDataAdapter(); SelectCommand.Connection = Connection; Adapter.SelectCommand = SelectCommand; //"#dd/MM/yyyy HH:mm:ss#" if (SelectF.SelDateValue == 5) OnStr = "firms.ID = Operations.FirmID"; else OnStr = "((firms.ID = Operations.FirmID)AND(Operations.[Date] >=" + ToDate(SelectF.MinDate) + ")AND(Operations.[Date] <=" + ToDate(SelectF.MaxDate) + "))"; SelectCommand.CommandText = "SELECT firms.ID, firms.Name, firms.Certificate, firms.Director, COUNT(Operations.ID) AS OpCount, SUM(Operations.Income) AS AllSum " + - 57 - "FROM (firms LEFT OUTER JOIN Operations ON " + OnStr + ")" + "GROUP BY firms.ID, firms.Name, firms.Certificate, firms.Director " + "ORDER BY firms.Name "; Adapter.Fill(firmsDataSet1.firms1); Adapter.Dispose(); SelectCommand.Dispose(); Connection.Dispose(); if (SelectF.SelDateValue == 5) Text = "Диаграмма по доходам фирм за все время"; else Text = "Диаграмма по доходам фирм с " + SelectF.MinDate.ToString("dd.MM.yyyy HH:mm:ss") + " по " + SelectF.MaxDate.ToString("dd.MM.yyyy HH:mm:ss"); } } } Файл RepForm2.cs using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; CrystalDecisions.CrystalReports.Engine; namespace FirmIncomes { public partial class RepForm2 : Form { public SelectDateForm SelectF; //окно выбора диапазона дат public string ConnectString; //строка подключения public firmsDataSet.firms1DataTable firms1;//таблица из набора данных главной формы private ReportDocument customerReport;//текущий отчет private bool NoChange;//признак пропуска обработчиков(для защиты от рекурсии) static string[] MonthNames = { "Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь" };//имена месяцев //конструктор, настраивает компоненты окна public RepForm2() - 58 - { InitializeComponent(); NoChange = false; } //эта функция возвращает строку даты/времени (для T), для использования в SQL-запросе private string ToDate(DateTime T) { return "#" + T.ToString("MM") + "/" + T.ToString("dd") + "/" + T.ToString("yyyy") + " " + T.ToString("HH:mm:ss") + "#"; } //обработчик изменения записи //заносит значения в дополнительное поле MonthName (имя месяца), в процессе заполнения таблицы private void Row_Changed(object sender, DataRowChangeEventArgs e) { if (!NoChange) { firmsDataSet.Operations1Row Row = (firmsDataSet.Operations1Row)e.Row; NoChange = true; Row.MonthName = MonthNames[(Row.MonthNum-1) % 12] + ", " + Convert.ToString((Row.MonthNum-1) / 12)+" г."; NoChange = false; } } //обработчик OnLoad - при открытии формы //настраивает адаптер, формирует запрос, заполняет таблицу, формирует и настраивает отчет private void RepForm2_Load(object sender, EventArgs e) { TextObject text; string OnStr; System.Data.OleDb.OleDbConnection Connection = new System.Data.OleDb.OleDbConnection(); Connection.ConnectionString = ConnectString; System.Data.OleDb.OleDbCommand SelectCommand = new System.Data.OleDb.OleDbCommand(); System.Data.OleDb.OleDbDataAdapter Adapter = new System.Data.OleDb.OleDbDataAdapter(); SelectCommand.Connection = Connection; Adapter.SelectCommand = SelectCommand; //"#dd/MM/yyyy HH:mm:ss#" if (SelectF.SelDateValue == 5) OnStr = "WHERE (FirmID = " + Convert.ToString(firms1[SelectF.SelFirm].ID)+") "; - 59 - else OnStr = "WHERE (FirmID = " + Convert.ToString(firms1[SelectF.SelFirm].ID) + ") AND ([Date] >= " + ToDate(SelectF.MinDate) + ") AND ([Date] <= " + ToDate(SelectF.MaxDate) + ") "; SelectCommand.CommandText = "SELECT MonthNum, COUNT(ID) AS RecCount, SUM(PurchaseCount) AS PurchaseC, SUM(SaleCount) AS SaleC, SUM(Income) AS AllIncome " + "FROM Operations "+OnStr + "GROUP BY MonthNum " + "ORDER BY MonthNum "; firmsDataSet1.Operations1.RowChanged += new DataRowChangeEventHandler(Row_Changed); Adapter.Fill(firmsDataSet1.Operations1); Adapter.Dispose(); SelectCommand.Dispose(); Connection.Dispose(); customerReport = new ReportDocument(); string reportPath = Application.StartupPath + "\\" + "CrystalReport2.rpt"; customerReport.Load(reportPath); text = customerReport.ReportDefinition.ReportObjects["Text8"] as TextObject; if (SelectF.SelDateValue == 5) text.Text = "Отчет по месяцам для фирмы \""+firms1[SelectF.SelFirm].Name+"\" за все время"; else text.Text = "Отчет по месяцам для фирмы \"" + firms1[SelectF.SelFirm].Name + "\" с " + SelectF.MinDate.ToString("dd.MM.yyyy HH:mm:ss") + " по " + SelectF.MaxDate.ToString("dd.MM.yyyy HH:mm:ss"); customerReport.SetDataSource(firmsDataSet1); crystalReportViewer1.ReportSource = customerReport; } } } Файл DiagramForm2.cs using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; namespace FirmIncomes - 60 - { public partial class DiagramForm2 : Form { public SelectDateForm SelectF; //окно выбора диапазона дат public string ConnectString; //строка подключения public firmsDataSet.firms1DataTable firms1;//таблица из набора данных главной формы private bool NoChange;//признак пропуска обработчиков(для защиты от рекурсии) static string[] MonthNames = { "Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь" };//имена месяцев //конструктор, настраивает компоненты окна public DiagramForm2() { InitializeComponent(); NoChange = false; } //эта функция возвращает строку даты/времени (для T), для использования в SQL-запросе private string ToDate(DateTime T) { return "#" + T.ToString("MM") + "/" + T.ToString("dd") + "/" + T.ToString("yyyy") + " " + T.ToString("HH:mm:ss") + "#"; } //обработчик изменения записи //заносит значения в дополнительное поле MonthName (имя месяца), в процессе заполнения таблицы private void Row_Changed(object sender, DataRowChangeEventArgs e) { if (!NoChange) { firmsDataSet.Operations1Row Row = (firmsDataSet.Operations1Row)e.Row; NoChange = true; Row.MonthName = MonthNames[(Row.MonthNum - 1) % 12] + ", " + Convert.ToString((Row.MonthNum - 1) / 12) + " г."; NoChange = false; } } //обработчик OnLoad - при открытии формы //настраивает адаптер, формирует запрос, заполняет таблицу - 61 - private void DiagramForm2_Load(object sender, EventArgs e) { string OnStr; System.Data.OleDb.OleDbConnection Connection = new System.Data.OleDb.OleDbConnection(); Connection.ConnectionString = ConnectString; System.Data.OleDb.OleDbCommand SelectCommand = new System.Data.OleDb.OleDbCommand(); System.Data.OleDb.OleDbDataAdapter Adapter = new System.Data.OleDb.OleDbDataAdapter(); SelectCommand.Connection = Connection; Adapter.SelectCommand = SelectCommand; //"#dd/MM/yyyy HH:mm:ss#" if (SelectF.SelDateValue == 5) OnStr = "WHERE (FirmID = " + Convert.ToString(firms1[SelectF.SelFirm].ID) + ") "; else OnStr = "WHERE (FirmID = " + Convert.ToString(firms1[SelectF.SelFirm].ID) + ") AND ([Date] >= " + ToDate(SelectF.MinDate) + ") AND ([Date] <= " + ToDate(SelectF.MaxDate) + ") "; SelectCommand.CommandText = "SELECT MonthNum, COUNT(ID) AS RecCount, SUM(PurchaseCount) AS PurchaseC, SUM(SaleCount) AS SaleC, SUM(Income) AS AllIncome " + "FROM Operations " + OnStr + "GROUP BY MonthNum " + "ORDER BY MonthNum "; firmsDataSet1.Operations1.RowChanged += new DataRowChangeEventHandler(Row_Changed); Adapter.Fill(firmsDataSet1.Operations1); Adapter.Dispose(); SelectCommand.Dispose(); Connection.Dispose(); if (SelectF.SelDateValue == 5) Text = "Диаграмма доходов по месяцам для фирмы \"" + firms1[SelectF.SelFirm].Name + "\" за все время"; else Text = "Диаграмма доходов по месяцам для фирмы \"" + firms1[SelectF.SelFirm].Name + "\" с " + SelectF.MinDate.ToString("dd.MM.yyyy HH:mm:ss") + " по " + SelectF.MaxDate.ToString("dd.MM.yyyy HH:mm:ss"); } } } Файл AboutBox1.cs using using using using using System; System.Collections.Generic; System.ComponentModel; System.Drawing; System.Linq; - 62 - using System.Reflection; using System.Windows.Forms; namespace FirmIncomes { partial class AboutBox1 : Form { public AboutBox1() { InitializeComponent(); //this.Text = String.Format("О {0} {0}", AssemblyTitle); //this.labelProductName.Text = AssemblyProduct; //this.labelVersion.Text = String.Format("Версия {0} {0}", AssemblyVersion); //this.labelCopyright.Text = AssemblyCopyright; //this.labelCompanyName.Text = AssemblyCompany; //this.textBoxDescription.Text = AssemblyDescription; } #region Методы доступа к атрибутам сборки public string AssemblyTitle { get { object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); if (attributes.Length > 0) { AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; if (titleAttribute.Title != "") { return titleAttribute.Title; } } return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); } } public string AssemblyVersion { get { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); - 63 - } } public string AssemblyDescription { get { object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); if (attributes.Length == 0) { return ""; } return ((AssemblyDescriptionAttribute)attributes[0]).Description; } } public string AssemblyProduct { get { object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); if (attributes.Length == 0) { return ""; } return ((AssemblyProductAttribute)attributes[0]).Product; } } public string AssemblyCopyright { get { object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); if (attributes.Length == 0) { return ""; } return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; } - 64 - } public string AssemblyCompany { get { object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); if (attributes.Length == 0) { return ""; } return ((AssemblyCompanyAttribute)attributes[0]).Company; } } #endregion } } - 65 -