Г.Тяпичев «Начальный курс быстрого программирования на СИ++». Глава 6.

 

Часть 3. Программирование различных устройств. 1

Глава 6. Программирование устройств. 1

Предисловие. 1

Работа с принтером. 1

Особенности печати. 1

Что можно печатать. 1

Выбор и настройка принтера. 2

Печатаем с применением компонента RichEdit 2

Печатаем с применением компонента Memo. 5

Печать графики. 6

Кроме того …... 10

Программируем звук. 10

Функции воспроизведения звуков. 11

Создаем звук программированием. 14

 

Часть 3. Программирование различных устройств

Глава 6. Программирование устройств

Предисловие.

В этой главе я приведу примеры программирования различных устройств, подключаемых к компьютеру. Представленные в этой главе небольшие проекты программ не должны существовать в качестве самостоятельных Windows приложений. В то же время их исходные коды могут (и должны) включаться как составные части в проекты других приложений. Это относится ко всем устройствам, о программировании которых будет идти речь в этой главе.

Работа с принтером

Особенности печати

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

Вывод на печать во многом напоминает вывод на экран или в файл, однако существует и ряд принципиальных отличий:

q      В результате вывода на печать получается твердая копия нужного материала, которая представляет собой изображение на бумаге или пленке.

q      Если для печати используются лазерные или струйные принтеры, то точки, из которых формируется изображение на бумаге, обычно намного меньше, чем на экране, поэтому изображение получается более четким.

q      По сравнению с выводом на дисплей или в файл печать является длительным процессом, который можно приостановить  или вообще прервать.

Все эти перечисленные возможности нужно иметь в виду при создании программ, в которых должен часто и на долгое время использоваться принтер. При создании приложений следует также учитывать и соизмерять стоимости программ и принтеров.

Что можно печатать

На печать можно выводить текст, картинки, диаграммы и любые другие изображения вплоть до портретов программистов. В C++ Builder печать можно осуществлять из многих различных компонентов, которые по своей природе обладают свойствами вывода информацией. Такими  компонентами являются  Memo (имеет окно для просмотра текста, следовательно, этот текст можно распечатать), RichEdit, ChartFX, QuickReport и некоторые другие. Одни из них  в смысле печати более приспособленные и имеют специально предназначенные для печати методы, например Print, в других –  программист должен сам организовать печать данных, которые они хранят (как упомянутый выше Memo).

Если перед вами встала проблема печати, в первую очередь исследуйте материал, который собираетесь печатать. Если нужно печатать форматированный текст, то непременно следует использовать компонент RichEdit.

Если ваше приложение должно по ходу работы распечатать пользователю диаграмму, то, скорее всего, это следует делать с помощью компонента ChartFX. В нем поддержка печати тоже предусмотрена. Если вы работаете с обычным неформатированным ASCII- текстом, то, вполне возможно, использовать для печати его компонента Memo. Этот компонент печатать не умеет, и вы должны программировать печать текста сами.

Если задача в том, чтобы печатать рисуемые на экране геометрические фигуры, то никакой компонент вам не поможет и единственный выход – работать непосредственно с объектом класса TPrinter, в котором предусмотрен интерфейс печати Windows.

Выбор и настройка принтера

Заниматься программированием принтера следует только тогда, когда  принтер у вас есть, и он подключен к компьютеру и исправлен. Не следует забывать о том, что для принтера необходима бумага, иногда даже специальная бумага. Подключенный к компьютеру принтер позволит выполнить проверку правильной распечатки текста создаваемым приложением.

На чем лучше печатать? На любых принтерах (матричных, струйных, лазерных, черно-белых, цветных). Лучшие изображения и документы получаются на цветных лазерных принтерах с высоким разрешением. На доисторических принтерах, которые выводят только символы, графическое изображение вообще распечатать не удастся.

При создании приложений, в которых должен часто использоваться принтер (например, в различного рода редакторах текста) следует предусмотреть возможность выбора и настройки принтера. В C++ Builder этим занимается компонент PrinterSetupDialog, размещенный в библиотеке компонентов Dialog.

 

Печатаем с применением компонента RichEdit

Далее предлагаю вам создать проект вспомогательного учебного приложения, которое поможет разобраться в вопросах печати с применением RichEdit.

Сначала создадим директорию для нового проекта, например: D:\Print_prob1\.

Начинаем новое приложение, выбрав команду меню FileèNewèApplication.

Сохраняем созданную заготовку для проекта в новой директории командой меню FileèSave Project ass, при этом первому сохраняемому файлу (с расширением .cpp) назначаем имя prn_prob.cpp, а файл проекта получит имя prn_prob1.bpr.

На форме, в верхней её части,  сначала разместим компонент  Panel, расположенный в библиотеке компонентов Standard.  На эту панель будут устанавливаться кнопки управления приложением.

В библиотеке компонентов  Additional выбераем компонент SpeedButton и размещаем его на панели слева. Затее рядом с этой кнопкой устанавливаем еще две кнопки SpeedButton, а в правой части панели устанавливаем компонент Button из библиотеки Standard. У вас должно получиться изображение формы, соответствующее рис. 6.1.

Рис. 6.1. Форма создаваемого проекта

Кроме того, на форму установим три невидимых компонента из библиотеки Dialogs:

q      OpenDialog – это средство для открытия нужного файла;

q      PrinterSetupDialog – компонент для выбора и настройки принтера;

q      PrintDialog – компонент для установки параметров и начала печати.

В компоненте OpenDialog следует установить значения для двух свойств:

Свойство DefaultExt = rtf, а свойство Filter = Text (*.rtf)|*.rtf, при этом последнее свойство устанавливается через окно Filter Edit, изображенное на рис. 6.2.

Рис. 6.2. Окно Filter Edit

Выполним оформление установленных видимых компонентов.

q      Для первой кнопки заполним следующие свойства

·          Caption = Open – это надпись на кнопке.

·          Name = OpenBtn – это название кнопки как компонента.

q      Для второй кнопки свойства должны быть:

·          Caption = Printer Setup – это надпись на кнопке.

·          Name = PrnSetBtn – это название кнопки как компонента.

q      Для третьей кнопки свойства должны быть:

·          Caption = Print – это надпись на кнопке.

·          Name = PrintBtn – это название кнопки как компонента.

q      Для четвертой кнопки Caption = Выход – это название кнопки.

В заключение устанавливаем на форму компонент RichEdit, расположенный в библиотеке компонентов Win32 (или Win95).

Работа над текстовой частью проекта большого труда не представляет. Двойной щелчок на графическом изображении компонента открывает окно редактора, при этом курсор всегда бывает установлен во вновь созданной функции, которую нужно заполнить командными строками.  

Ниже, в листинге 6.1, приведен текст файла prn_prob.cpp. По аналогии с текстом этого файла вы должны провести доработку одноименного файла, расположенного в директории создаваемого проекта.

В начальной части файла никаких изменений нет.

В функции 1 записывается строка:  Caption = "Демонстрация печати";

Этой строкой создается заголовок для формы. Далее выполняем двойной щелчок на кнопке Выход, на экране появляется окно редактора с заготовкой под функцию 2. В теле этой функции делаем одну единственную запись – Close();

Листинг 6.1. Файл prn_prob.cpp

//---------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "prn_prob.h"

//---------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------

// Функция описания формы

__fastcall TForm1::TForm1(TComponent* Owner)             // 1

        : TForm(Owner)

{

 Caption = "Демонстрация печати";

}

//----------------------------------------------------------------------

// Функция реагирует на нажатие кнопки Выход

void __fastcall TForm1::Button1Click(TObject *Sender)        // 2

{

 Close();       

}

//----------------------------------------------------------------------

// Функция реагирует на нажатие кнопки Open

void __fastcall TForm1::OpenBtnClick(TObject *Sender)        // 3

{

 if(OpenDialog1->Execute())

   {

   Caption = "Print Demo - "+OpenDialog1->FileName;

   RichEdit1->Lines->LoadFromFile(OpenDialog1->FileName);

   }

}

//---------------------------------------------------------------------

// Функция реагирует на нажатие кнопки Print Dialog

void __fastcall TForm1::PrnDlgBtnClick(TObject *Sender)         // 4

{

 PrintDialog1->Execute();       

}

//---------------------------------------------------------------------

// Функция реагирует на нажатие кнопки Print

void __fastcall TForm1::PrintBtnClick(TObject *Sender)          // 5

{

  if(PrintDialog1->Execute())

   RichEdit1->Print(OpenDialog1->FileName);

}

//---------------------------------------------------------------------

// Функция реагирует на нажатие кнопки Printer Setup

void __fastcall TForm1::PrnSetBtnClick(TObject *Sender)          // 6

{

 PrinterSetupDialog1->Execute();       

}

//---------------------------------------------------------------------

 

После того, как вы убедитесь, что файл prn_prob.cpp , находящийся в составе проекта, стал полностью соответствовать тексту в листинге 6.1, следует Выполнить команду из меню ProjectèMake prn_prob1.  После исправления случайных ошибок командой ProjectèBuild prn_prob1 создается исполняемый файл проекта, а командой RunèRun проект запускается на выполнение и на экране должно появиться главное окно приложения, изображенное на рис. 6.3.

Рис. 6.3. Главное окно приложения

Теперь можно просмотреть работу всех задействованных в проекте диалоговых компонентов, предназначенных для работы с печатанием тексти.

На рис. 6.4 изображено диалоговое окно для выбора текста – Open Dialog.

Рис. 6.4. Окно выбора текста

На рис. 6.5 изображено диалоговое окно для настройки принтера – Printer Setup.

Рис. 6.5. Окно настройки принтера

Дополнительные свойства при настройке принтера можно задействовать с помощью окна, изображенного на рис. 6.6.

Рис. 6.6. Окно свойств

Дополнительная настройка может быть выполнена с использованием окна, изображенного на рис. 6.7.

Рис. 6.7. Окно дополнительной настройки принтера

После выполнения настройки принтера можно приступать к печати находящегося в RichEdit текста. Для этих целей служит диалоговый компонент PrintDialog. Этот компонент не имеет в нашем приложении своей собственной кнопки управления и запускается в работу нажатием кнопки Print. Сначала на экране появляется диалоговое окно, предлагающее уточнить некоторые элементы печати. Это окно изображено на рис. 6.8.

Рис. 6.8. Окно подготовки к печати.

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

Рис. 6.9. Дополнительные уточнения.

Для начала печати следует выбрать ОК в окне рис. 6.8.

Во время процесса печати главное окно нашего приложения примет вид, изображенный на рис. 6.10.

Рис. 6.10. Текст готов к печати.

На примере этого приложения подробно рассмотрены действия диалоговых компонентов, необходимых для печати текста с применением окна многстрочного редактирования RichEdit. Это был рассмотрен самый простой из вариантов организации работы принтера, т.к. в составе компонента RichEdit уже заложены некоторые предназначенные для печати функции.

Печатаем с применением компонента Memo

Этот редактор многострочного текста не имеет функций для печати, поэтому при использовании Memo программист сам должен сам их написать. При этом применяется метод языка Си, использующий функцию frintf().

Как обычно, создаем директорию для нового приложения, которое будет решать задачу печати текста с использованием Memo. Поскольку это приложение будет состоять почти из тех же компонентов, что и предыдущее, скопируем все файлы предыдущего приложения в новую директорию и вызовем команду из меню FileèSave Project ass. Название новому проекту дадим prn_prob2.

В листинге 6.2 размещен новый вариант файла prn_prob.cpp. Чтобы использовать новые для вас методы работы с файлами, подключим заголовочный файл <stdio.h> (см. строку №1).

Листинг 6.2. Файл prn_prob.cpp (вариант 2)

//----------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "prn_prob.h"

#include <stdio.h>                             // №1

//----------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//----------------------------------------------------------------------

// Функция описания формы

__fastcall TForm1::TForm1(TComponent* Owner)               // 1

        : TForm(Owner)

{

 OpenDialog1->DefaultExt = "txt";

 OpenDialog1->Filter = "Text(*.txt)|*.txt";

 Caption = "Демонстрация печати";

  }

//----------------------------------------------------------------------

// Функция закрытия программы

void __fastcall TForm1::Button1Click(TObject *Sender)          // 2

{

 Close();       

}

//----------------------------------------------------------------------

// Функция реагирует на нажатие кнопки Open

void __fastcall TForm1::OpenBtnClick(TObject *Sender)         // 3

{

 if(OpenDialog1->Execute())

   {

   Caption = "Print Demo - "+OpenDialog1->FileName;

   Memo1->Lines->LoadFromFile(OpenDialog1->FileName);

   }

}

//---------------------------------------------------------------------

// Функция реагирует на нажатие кнопки Print

void __fastcall TForm1::PrintBtnClick(TObject *Sender)          // 4

{

 FILE *stdprn;                                             // №2

 

   if((stdprn = fopen("prn","w")) != NULL)                 // №3  

      if(PrintDialog1->Execute())

        {

         for(int i =0;i<Memo1->Lines->Count; i++)          // №4

             fprintf(stdprn, "%s", Memo1->Lines[i].Text.c_str());  

        }

 }

//---------------------------------------------------------------------

// Функция выбора принтера

void __fastcall TForm1::PrintSetBtnClick(TObject *Sender)      // 5

{

 PrinterSetupDialog1->Execute();       

}

//---------------------------------------------------------------------

 

Функции 1, 2, 3 и 5 ничего нового, по сравнению с предыдущим вариантом, не имеют. Все изменения начинаются в функции 4.

В самом начале этой функции происходит объявление  FILE *stdprn; ,  которое используется заголовочным файлом <stdio.h>  для открытия файла с указателем stdprn, который фактически представляет собой принтер, в режиме записи. Открытие файла, представляющего собой указатель на принтер, выполняется в строке №3, а в строке №4 происходит построчная передача на принтер текста, расположенного в Memo.           

Подобный метод использования принтера считается устаревшим, но иногда бывают обстоятельства, заставляющие вспомнить старину.

Печать графики

Рассмотрим случай, когда возникает необходимость распечатать созданные  на экране какие-то  фигуры, созданные  с помощью стандартных процедур Ellipse, Line и т.д. Если вдруг получилось что-то интересное, имеет смысл сохранить результат на бумаге и посмотреть более внимательно.

Задачи подобного рода решаются просто: графическое изображение рисуется на принтере так же, как на экране, т. с помощью свойств и методов объекта Canvas. Однако при печати объект Canvas берется у объекта класса TPrinter, возвращаемого функцией Printer. Для начала печати у объекта, возвращенного функцией Printer, вызывается метод BeginDoc, а для завершения печати – метод EndDoc. Для преждевременной остановки печати вызывается метод Abort. Проброс страниц выполняет метод NewPage. Параметры печати хранятся в свойствах объекта, которые описаны в таблице 6.1.

Таблица 6.1. Свойства объектов класса TPrimter.

Свойство

Описание

Aborted

Показывает, прервана ли печать.

PageHeight

Высота страницы в пикселях.

PageWidth

Ширина страницы в пикселях.

PageNumber

Номер печатаемой страницы.

Printing

Показывает, выполняется ли печать.

Title

Текстовая строка, идентифицирующая печатаемый документ в окне менеджера печати (Print Manager).

 

В C++ Builder имеется класс печатающих объектов TPrinter, который обеспечивает печать текстов, изображений и других объектов, расположенных на его канве – Canvas. Свойства канвы подробно рассматривать здесь мы не будем. Это не входит в задачу этой книги. Пока достаточно знать, что на канве могут размещаться различные изображения и текст.

Класс объектов TPrinter объявлен в модуле Printers. Поэтому для работы с этим классом надо включить в текст директиву препроцессора

#include <Printers.hpp>

Рассмотрим некоторые свойства и методы объекта типа TPrinter, размещенные в таб. 6.2.

Таблица 6.2. Свойства и методы TPrinter

Свойство, метод

Описание

Canvas

Канва Canvas – место в памяти, в котором формируется страница или документ перед печатью. Canvas обладает рядом свойств, включая Pen (перо) и Brush (кисть), которые позволяют вам делать рисунки и помещать на них текст.

TextOut

Метод канвы, который позволяет посылать в нее текст

Draw

Метод канвы, который позволяет посылать в нее изображение

BeginDoc

Используется для начала задания печати

EndDoc

Используется для окончания задания печати. Фактическая печать происходит только при вызове EndDoc.

PageHeight

Высота страницы в пикселях

PageWidth

Ширина страницы в пикселях

NewPage

Принудительно начинает новую страницу на принтере

PageNumber

Возвращает текущий номер печатаемой страницы

 

Часто бывает необходимо напечатать текст и изображение, используя печатающий объект. Изображение размещено на форме в Picture. Вы можете осуществить эту печать следующим кодом:

TPrinter *Prntr = Printer();

Prntr->Canvas->Font->Size = 12;

Prntr->BeginDoc();

Prntr->Canvas->TextOut(10, 10, “Печатаем через объект Printer”);

Prntr->Canvas->Draw(

           (Prntr->PageWidth )/2,

            40, Picture->Bitmap);

Prntr->EndDoc();

Первый оператор этого кода использует функцию Printer, который создает глобальный объект типа TPrinter. В этом же операторе создается указатель на этот объект Prntr.

Следующий оператор задает размер шрифта канвы принтера. Затем функция BeginDoc запускает задание на печать. Следующий оператор посылает на канву принтера с помощью метода канвы TextOut, начиная с точки с координатами (10,10), текст «Я печатаю через объект Printer». Следующий оператор методом Draw рисует на канве принтера изображение. При этом изображение выравнивается по горизонтали на середину страницы. Координата верхней стороны изображения задается равной 40.

В заключение метод EndDoc вызывает печать текста и изображения и останавливает задание на печать.

Печатающий объект Printer не производит автоматического переноса строк и разбиение текста на страницы. Поэтому печать длинных текстов с помощью объекта Printer требует достаточно сложного программирования. Проще это делать описанными ранее способами или с помощью системы QuickRepot.

В качестве примера применения объекта Printer для печати текста и картинки, взятой из файла, создадим проект небольшого приложения.

Сначала создаем директорию, в которой будут находиться файлы проекта, затем создаем проект, у которого файл с исходными кодами назовем grafika.cpp, а файл проекта будет grafika1.bpr.

На рис. 6.11 изображена форма создаваемого приложения с установленными компонентами.

Рис. 6.11. Форма проекта grafika1

Ниже кнопок на форме сначала установлен компонент Panel, затем сверху наложен компонент PaintBox.

В этом проекте придется вносить небольшое дополнение в файл grafika.h, поэтому в листинге 6.3 приведем текст этого файла.

Листинг 6.3. Файл grafika.h

//---------------------------------------------------------------------

#ifndef grafikaH

#define grafikaH

//---------------------------------------------------------------------

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

#include <Buttons.hpp>

#include <Dialogs.hpp>

#include <ExtCtrls.hpp>

//---------------------------------------------------------------------

class TForm1 : public TForm

{

__published:    // IDE-managed Components

        TPanel *Panel1;

        TSpeedButton *OpenBtn;

        TSpeedButton *PrintSetBtn;

        TSpeedButton *PrintBtn;

        TButton *Button1;

        TOpenDialog *OpenDialog1;

        TPrinterSetupDialog *PrinterSetupDialog1;

        TPrintDialog *PrintDialog1;

        TPaintBox *Image1;

        void __fastcall Button1Click(TObject *Sender);

        void __fastcall OpenBtnClick(TObject *Sender);

        void __fastcall PrintSetBtnClick(TObject *Sender);

        void __fastcall PrintBtnClick(TObject *Sender);

private:  // User declarations

          TPicture *Picture;                            // №1

public:         // User declarations

        __fastcall TForm1(TComponent* Owner);

};

//----------------------------------------------------------------------

extern PACKAGE TForm1 *Form1;

//----------------------------------------------------------------------

#endif

//----------------------------------------------------------------------

 

Дополнение в этом файле сделано в разделе private: . В этом разделе выполнено объявление класса Picture в строке №1.

Далее, в листинге 6.4. приводим текст файла grafika.cpp.  

В строке №1 показано подключение заголовочного файла <Printers.hpp>.  Этот файл организует печать графики. В строке №2 проведено объявление класса Printer() и присвоено имя Prntr.   

В функции 1, которая служит для описания формы, назначаем необходимые имена и значения для переменных величин.                       

Листинг 6.4. Файл grafika.cpp

//----------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include <Printers.hpp>                             // №1

#include "grafika.h"

//----------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

TPrinter *Prntr = Printer();                       // №2

//-----------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)                // 1

        : TForm(Owner)

{

 Caption = "Печатаем графику";          // заголовок на форме

 Picture = new TPicture;                // объявляем создание Picture

 OpenDialog1->DefaultExt = "bmp";       // выбираем только файлы .bmp

 OpenDialog1->Filter = "Image(*.bmp)|*.bmp";

 Prntr->Canvas->Font->Size = 12;       // назначаем размер шрифта для

 Prntr->Canvas->Font->Name = "Arial";  // назначаем шрифт

}

//---------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)          // 2

{

 Close();

}

//---------------------------------------------------------------------

void __fastcall TForm1::OpenBtnClick(TObject *Sender)           // 3

{

 if(OpenDialog1->Execute());

    {

     Picture->LoadFromFile(OpenDialog1->FileName);             // №3

     Canvas->Draw(10,100,Picture->Graphic);                    // №4

    }

}

//---------------------------------------------------------------------

void __fastcall TForm1::PrintSetBtnClick(TObject *Sender)      // 4

{

 PrinterSetupDialog1->Execute();

}

//----------------------------------------------------------------------

void __fastcall TForm1::PrintBtnClick(TObject *Sender)          // 5

{

 if(PrintDialog1->Execute())

  {

 Prntr->BeginDoc();                                              // №5

 Prntr->Canvas->TextOutA(10,80,"Печатаем через объект Printer");  //№6

 Prntr->Canvas->Draw((Prntr->PageWidth )/2,40,Picture->Bitmap);   //№7

 Prntr->EndDoc();                                                 //№8

   }

}

//----------------------------------------------------------------------

 

Функция 2 является реакцией на нажатие кнопки Выход и служит для завершения работы программы.

Функция 3 является реакцией на нажатие кнопки Open. Строка №3 в этой функции выбирает файл с расширением *.bmp и размещает его в Picture. Строка №4 рисует содержимое объекта Picture на канву Canvas.  Этот момент изображен на рис. 6.12. В качестве объекта для рисования выбран один из рисунков программы Induktiw.

Рис. 6.12. Окно приложения с картинкой.

Функция 4 является реакцией на нажатие кнопки Printer Setup и устанавливает необходимые свойства принтера.

Функция 5 является реакцией на нажатие кнопки Print и служит для выполнения печати принтером заданного текста и картинки. Строка №5 этой функции объявляет начало организации заданий для печати. Строка №6 показывает, каким образом можно распечатать текстовую строку. Цифровые параметры, размещенные перед началом строки, являются координатами первой буквы для этой строки. Так что строку можно вывести в любое место бумажного лиса, заложенного в принтер.

Строка 7 показывает, каким образом можно распечатать рисунок, расположенный на канве Canvas. Цифры перед названием рисунка являются координатами левого верхнего угла рисунка. Строка 8 говорит о том, что все задания для печати выданы и включает принтер.

Приведенный выше пример поможет вам выполнить и печать картинки и печать текста в определенных местах листа бумаги, установленного в принтер.

 

Кроме того …

Кроме описанных выше примеров, имеется много других возможностей организовать печать посредством принтера.

Печать форм методом Print

Формы в C++ Builder имеют метод Print, который печатает клиентскую область формы. При этом полоса заголовка формы и полоса главного меню не печатаются. Таким образом, можно включить в приложение форму, в которой пользователь во время выполнения размещает необходимые для печати результаты: тексты и изображения. Если имя этой формы Form2, то ее печать может выполняться оператором

Form2->Print();

Свойство формы PrintScale определяет опции масштабирования изображения при печати. Возможные значения PrintScale:

Таблица 6.3. Опции масштабирования при печати

poNome

Масштабирование не используется. Размер изображения может изменяться в зависимости от используемого принтера

poProportional

Делается попытка напечатать изображение формы того же размера, который виден на экране

poPrintToFit

Увеличивает или уменьшает размер изображения, подгоняя его под размер страницы, заданной при установке принтера. Это значение принято по умолчанию

Методы компонентов, обеспечивающие печать

Ряд компонентов в C++ Builder имеют методы, обеспечивающие печать хранящихся в них данных. Выше были подробно рассмотрены вопросы печати с использованием компонентов RichEdit и Memo.

 Компонент Chart, используемый для отображения графиков и диаграмм, также имеет метод Print, обеспечивающий печать. Предварительно может быть выполнен метод PrintPortrait, задающий книжную (вертикальную) ориентацию бумаги, или метод PrintLandscape, задающий альбомную (горизонтальную) ориентацию.

Компонент Chartfx имеет быструю кнопку печати , с помощью которой пользователь в любой момент может напечатать текущий график или диаграмму.

Печать с помощью функции ShellExecute

Для печати файлов средствами стандартных офисных приложений Windows можно использовать функцию ShellExecute. Чтобы воспользоваться функцией ShellExecute, надо ввести в модуль директиву препроцессора

#includeShellApi.h

которая подключает заголовочный файл ShellApi.h, содержащий объявление функции ShellExecute и некоторых других функций Windows API. Функция ShellExecute при соответствующем задании ее параметров ищет по расширению заданного для печати файла соответствующую ему системную программу Windows, и, если находит, то осуществляет печать. Например, обычно Windows настроен так, что файлы с расширением .txt соответствует программа Notepad, а файлы с расширением .doc Word. В этом случае выполнение оператора

ShellExecute(Handle, “print”, “Test.txt”,NULL, NULL, SW_HIDE);

вызовет печать файла с именем test.txt средствами программы Notepad.

ShellExecute(Handle, “print”, “Test.doc”,NULL, NULL, SW_HIDE);

вызовет печать файла с именем test.doc средствами программы Word.

Этот способ печати можно использовать как для распечатки заранее созданных файлов, так и для распечатки файлов, созданных во время выполнения приложения методами SaveToFile, имеющимися у многих компонентов.

Программируем звук

Звук в компьютерных программах играет большую роль. Не говоря уже об игровых и специальных музыкальных программах.

Например, в некоторых программах имеются голосовые подсказки для выполнения последующих действий, голосовое предупреждение о возможной ошибке и т.д..  Во многих радиолюбительских программах звуковая карта компьютера может выполнять роль заменителя аппаратного модема (служить «эрзац модемом»), либо изначально ей предназначается быть звуковым модемом (программы PSK31).

C++Builder может работать со всеми возможными вариантами управления звуковыми картами компьютера, заложенными в системах Windows.

 

Функции воспроизведения звуков

Таблица 6.4. Функции воспроизведения звука

Функция

Синтаксис / описание

Файл

Beep

Extern PACKAGE void Beep(void)

Функция C++Builder, воспроизводит стандартный звуковой сигнал

SysUtils.hpp

Beep

BOOL Beep(DWORD dwFreq, DWORD dwDuration);

Функция API Windows, только для Windows NT, воспроизводит звуковой сигнал с частотой dwFreq Герц и длительностью dwDuration миллисекунд

 

MessageBeep

BOOL MessageBeep(UINT uType);

Функция API Windows, воспроизводит звуковой сигнал типа uType

 

PlaySound

BOOL PlaySound(LPCSTR pszSound,

                  HMODULE hmod,  DWORD fdwSound)

Функция API Windows, воспроизводит звук указанного волнового файла, или звук системного события, или звука из ресурса

 

mmsystem.hpp

 

Введем некоторые пояснения. Функция C++ Builder Beep воспроизводит стандартный звуковой сигнал, вызывая функцию MessageBeep API Windows с нулевым параметром. При этом воспроизводится стандартный звуковой сигнал, установленный в Windows. Если звуковой карты нет или стандартный сигнал не установлен, звук воспроизводится через динамик компьютера.

Воспроизведение асинхронное, т.е. приложение продолжает выполняться во время  воспроизведения звука.

Функция Beep API Windows, примененная в Windows NT, синхронно воспроизводит звук простого тона через динамик и не возвращается до окончания звука. В Windows NT параметр dwFreq задает частоту звука в Герцах. Он может иметь значения в диапазоне от 37 до 32 767 (от 0х25 до 0х7FFF). Параметр dwDuration устанавливает длительность звука в миллисекундах.

Воспроизведение синхронное, т.е. функция не возвращается до окончания воспроизведения звука.

Все сказанное относится только к Windows NT. В Windows 95 и 98 параметры игнорируются и функция становится подобной функции Beep C++ Builder. Отличие этих функций остается только в том, что Beep C++ Builder ничего не возвращает, а Beep API Windows при успешном выполнении возвращает ненулевое значение. При аварийном завершении она возвращает нуль. Тогда более развернутую информацию об ошибке можно получить вызовом функции GetLasrError .

В качестве примера использования функции Beep для Windows XT (а у меня сейчас установлен именно этот вариант Windows), предлагаю создать проект простого приложения с использованием этой функции.

Создаем проект под названием bepsnd1, при этом файл с исходными кодами будет иметь название bepsnd. Форма приложения показана на рис. 6.13.

Рис. 6.13. Форма проекта bepsnd1

На форме установлены только хорошо вам известные компоненты Label и Button, поэтому никаких описаний не требуется.

В листинге 6.5 приводится текст файла bepsnd.cpp

Листинг 6.5. Файл bepsnd.cpp

//----------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "bepsnd.h"

//---------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

//---------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

        : TForm(Owner)

{

 Caption = "Проверка звучания";

 Label1->Caption = "Частота  400 Гц, звучит 2 секунды";

 Label2->Caption = "Частота  800 Гц, звучит 3 секунды";

 Label3->Caption = "Частота 1000 Гц, звучит 4 секунды";

 Label4->Caption = "Частота 1400 Гц, звучит 3 секунды";

 Label5->Caption = "Частота 1600 Гц, звучит 2 секунды";

 Label6->Caption = "Частота 2000 Гц, звучит 2 секунды";

}

//---------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{

 Beep(400, 2000);

}

//---------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)

{

 Beep(800,3000);

}

//---------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)

{

 Beep(1000,4000);

}

//----------------------------------------------------------------------

void __fastcall TForm1::Button4Click(TObject *Sender)

{

 Beep(1400,3000);       

}

//---------------------------------------------------------------------

void __fastcall TForm1::Button5Click(TObject *Sender)

{

 Beep(1600,2000);       

}

//---------------------------------------------------------------------

void __fastcall TForm1::Button6Click(TObject *Sender)

{

 Beep(2000,2000);       

}

//---------------------------------------------------------------------

void __fastcall TForm1::Button7Click(TObject *Sender)

{

 Close();       

}

//---------------------------------------------------------------------

 

Мне думается, что нет необходимости комментировать этот простейший проект. На рис. 6.14 показано главное окно работающего приложения.

Рис. 6.14. Окно работающего приложения bepsnd

Компилятор автоматически разбирается, какая именно из функций Beep использована в программе, по наличию или отсутствию параметров.

Функция MessageBeep воспроизводит звуковой сигнал указанного типа. Звуки, соответствующие различным типам сигналов, хранятся в реестре в разделе {sounds] и устанавливаются пользователем с помощью программы «Панель управления» щелчком на пиктограмме Звук.

Целый без знака параметр uType функции MessageBeep определяет воспроизводимый звук. Для него предопределены следующие константы:

Таблица 6.5. Параметры аргумента uType

Значение

Звук

OxFFFFFFFF

Стандартный звук через динамик

MB_ICONASTERISK

Звездочка

MB_ICONEXCLAMATION

Восклицание

MB_ICONHAND

Критическая ошибка

MB_ICONQUESTION

Вопрос

MB_OK

Стандартный звук

 

При успешном завершении функция возвращает ненулевое значение (true). Если функция вернула нулевое значение, то получить информацию об ошибке можно с помощью вызова GetLastError.

После инициализации воспроизведения звука функция MessageBeep возвращает управление в точку вызова и воспроизведение звука производится асинхронно.

Если функция MessageBeep не нашла указанный тип звука, она пытается воспроизвести стандартный звук. Если и он не установлен или если компьютер не снабжен звуковой картой, то звук воспроизводится через динамик компьютера.

Функция PlaySound API Windows воспроизводит звук указанного волнового файла, или звук системного события, или звук из ресурса.

Параметр pszSound представляет собой строку с нулевым символом в конце и определяет воспроизводимый звук. В зависимости от значений флага fdwSound (SND_FILENAME, SND_ALIAS или SND_RESOURCE) параметр pszSound может определять имя волнового файла, псевдоним системного события или идентификатор ресурса. Если ни одни из этих файлов не указан, функция ищет в реестре Windows или файле WIN.INI указанное имя звука. Если звук найден, то он воспроизводится. Если звук не найден, то параметр pszSound интерпретируется как имя файла.

Звук, указанный параметром pszSound, должен помещаться в доступную память и должен подходить для установленного драйвера устройства воспроизведения волновых файлов. Функция PlaySound ищет файл звука в следующих каталогах: текущем, каталоге Windows, системном каталоге Windows, каталогах, перечисленных в переменной среде PATH, в списке каталогов, предоставляемых сетью. Более подробно последовательность поиска в каталогах рассмотрена в документации по функции OpenFile.

Если указанный звук не находится, функция PlaySound воспроизводит системный звук по умолчанию. Если функция не может найти и его, то воспроизведения не будет, а вернется значение false.

Если параметр pszSound задан равным 0, то воспроизведение любого волнового файла прерывается. Для прерывания воспроизведения звука, не связанного с волновым файлом, надо указывать SND_PURGE в параметре fdwSound.

Параметр hmod используется только при параметре fdwSound равном SND_RESOURCE. В этом случае hmod является дискриптором выполняемого файла, содержащего ресурс, который должен загружаться. В противном случае значение hmod задается равным 0.

Параметр fdwSound задает флаги воспроизведения звука. Флаги могут комбинироваться друг с другом комбинацией ИЛИ «|». Возможны следующие значения флагов:

Таблица 6.6. Флаги параметра fwdSound

SND_ALIAS

Параметр pszSound определяет псевдоним системного события в реестре Windows или в файле WIN.INI. Нельзя использовать совместно с SND_FILENAME и SND_RESOURCE

SND_ALIAS_ID

Параметр szSound является предопределенным идентификатором звука.

SND_APPLICATION

Звук воспроизводится с использованием установок приложения

SND_ASYNC

Звук производится асинхронно и функция PlaySound возвращается немедленно после начала воспроизведения. Чтобы прекратить асинхронное воспроизведение волнового файла, надо вызвать PlaySound с параметром pszSound, равным 0.

SND_FILENAME

Параметр pszSound является именем файла

SND_LOOP

Воспроизведение звука постоянно повторяется, пока не вызовется PlaySound с параметром pszSound, равным 0. Одновременно надо указать флаг SND_ASYNC асинхронного воспроизведения звука

SND_MEMORY

Файл звука события загружен в память. В этом случае параметр pszSound должен указывать на образ звука в памяти

SND_NODEFAULT

Звук события, кроме звука по умолчанию. Если указанный звук не найден, PlaySound вернется, не воспроизведя звук по умолчанию

SND_NOSTOP

Если заданный звук не может быть воспроизведен, поскольку ресурсы, необходимые для воспроизведения, заняты воспроизведением другого звука, функция PlaySound немедленно вернет false, не воспроизведя заданного звука. Если данный флаг не указан, функция PlaySound пытается остановить воспроизведение другого звука, чтобы устройство могло быть использовано для воспроизведения нового звука

SND_NOWAIT

Если драйвер занят, функция сразу вернется без воспроизведения заданного звука

SND_PURGE

Останавливается воспроизведение любых звуков, вызванных в данной задаче. Если pszSound не 0, то останавливаются все экземпляры указанного звука. Если pszSound равен 0, то останавливаются все звуки, связанные с данной задачей. Отдельно надо указать дескриптор для остановки события SND_RESOURCE

SND_RESOURCE

Параметр pszSound является идентификатором ресурса. Параметр hmod должен указывать на источник ресурса.

SND_SYNC

Синхронное воспроизведение звука события. Функция PlaySound возвращается только после окончания воспроизведения

 

Функция PlaySound при успешном выполнении возвращает true, в противном случае – false.

Примеры использования функции PlaySound приведены в главе 3. Функция используется в подключаемой DLL библиотеки для формирования звуковых сигналов кода Морзе.

Использовать эту функцию можно для создания в работающей программе голосовых подсказок. Для этого посредством микрофона и программы записи звука от Windows создать (наговорить в микрофон и записать в файл) необходимое количество голосовых файлов. При создании проекта программы в определенных местах включается функция PlaySound для выдачи нужного голосового сигнала или сообщения.

Создаем звук программированием

Очень часто, особенно в программах для любительской радиосвязи, возникает необходимость создавать гармонические (синусоидальные) звуки определенных частот и длительностей. Например, в главе 8 все используемые библиотеки DLL создают звуки, из которых формируются передаваемые сигналы, только  путем синтезирования звука, т.е. создания его программным путем.

Сейчас мы создадим проект приложения, в котором будет рассмотрен один из простейших вариантов создания гармонического звукового сигнала.

Создадим для нового проекта директорию, например, D:\Sound2\. Далее создадим новый проект приложения, у которого файл с кодами (.cpp) назовем sinwave.cpp, а файл проекта назовем sinwave1.bpr.  Сохраним созданную заготовку для нового проекта в заданной директории.

Предлагаемый вариант заполнения компонентами формы проекта представлен на рис. 6.15.

Рис. 6.15. Форма проекта

Все установленные на форме компоненты вам хорошо известны. Это – Label и Button. Никаких изменений в файле sinwave.h делать не т необходимости.

Ниже расположим листинг 6.6, в котором разместим текст файла sinwave.cpp.

В текст этого файла следует добавить подключение двух заголовочных файлов: <math.h> и <mmsystem.h>, а также добавить объявления большого числа переменных величин, задействованных в функциях этого проекта.

В этой части файла следует также объявить  функцию void __fastcall TestOut(int), которая объявляется здесь только по той причине, что не является членом класса TForm, функции которого объявляются в файле sinwave.h.

Функция 1 представляет собой описание формы и в её теле задано название формы и названия всех компонентов Label.

Функция 2 прекращает работу программы, закрывает программу.

Листинг 6.6. Файл sinewave.cpp

//----------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "sinwave.h"

#include <math.h>

#include <mmsystem.h>

//---------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

   TForm1 *Form1;

   HWND m_hWnd;

 HWAVEIN hWaveIn;

 HWAVEOUT hWaveOut;

 int ton = 1600; //440;

 const nwh = 3;

 const BUFLEN = 44100; WAVEHDR wh[nwh];

 WAVEHDR whout[nwh];

 char buf[BUFLEN*nwh];

 char bufout[BUFLEN*nwh];

 int OutCnt = 0;

 DWORD SoundLevel[BUFLEN];

 BYTE interbuf[BUFLEN];

 bool bWaveInIsStarted = 0;

 bool bWaveOutIsStarted = 0;

 

 void __fastcall TestOut(int);

 

//----------------------------------------------------------------------

// Функция описания формы

__fastcall TForm1::TForm1(TComponent* Owner)               // 1

        : TForm(Owner)

{

 Caption = "Гармонический сигнал";

 Label1->Caption = "Частота звука  400 Герц";

 Label2->Caption = "Частота звука  600 Герц";

 Label3->Caption = "Частота звука  800 Герц";

 Label4->Caption = "Частота звука 1000 Герц";

 Label5->Caption = "Частота звука 1200 Герц";

 Label6->Caption = "Частота звука 1600 Герц";

 Label7->Caption = "Частота звука 2000 Герц";

 Label8->Caption = "Частота звука 2200 Герц";

}

//-----------------------------------------------------------------------

// Функция реагирует на нажатие кнопки Выход

void __fastcall TForm1::Button1Click(TObject *Sender)          // 2

{

 Close();       

}

//-----------------------------------------------------------------------

// Функция реагирует на нажатие кнопки Стоп – прекращает звук

void __fastcall TForm1::StopOutClick(TObject *Sender)           // 3

{

     if (!bWaveOutIsStarted)

          return;

    

     bWaveInIsStarted = 0;

 

     MMRESULT mmresult;

     mmresult= waveOutPause(  hWaveOut  );

     if (mmresult!=MMSYSERR_NOERROR)

          return;

 

     mmresult = waveOutReset(  hWaveOut  );

     if (mmresult!=MMSYSERR_NOERROR)

          return;

 

    for (int i = 0; i < nwh; i++)

     {

          waveOutUnprepareHeader(hWaveOut, whout+i, sizeof(WAVEHDR));

     }

     mmresult = waveOutClose(  hWaveOut  );

     if (mmresult!=MMSYSERR_NOERROR)

          return;

}

//----------------------------------------------------------------------

// Функция проигрывает звук, записанный в буфере

 void __fastcall TestOut(int)                           // 4

{

  int NumInputDevices = waveOutGetNumDevs();

     UINT uDeviceID = 0;

     WAVEOUTCAPS woc;

     MMRESULT mmresult;

     mmresult = waveOutGetDevCaps( uDeviceID, &woc,

                                        sizeof(woc) );

     if(mmresult!=MMSYSERR_NOERROR)

          return;

     WAVEFORMATEX wfx;

    wfx.wFormatTag = WAVE_FORMAT_PCM;

     wfx.nChannels = 1;

     wfx.nSamplesPerSec = 44100;

    wfx.nAvgBytesPerSec = 11025;

     wfx.nBlockAlign = 1;

        wfx.wBitsPerSample = 8;

    wfx.cbSize = 0;

 

 DWORD fdwOpen = /* WAVE_FORMAT_DIRECT; |*/ CALLBACK_WINDOW;

 

  mmresult = waveOutOpen(&hWaveOut, uDeviceID, &wfx,

                            (ULONG)m_hWnd, 0, fdwOpen);

     if(mmresult!=MMSYSERR_NOERROR) return;

 

     for (int i=0; i< nwh; i++)

     {

          whout[i].lpData = bufout+i*BUFLEN;

          whout[i].dwBufferLength = BUFLEN;

          whout[i].dwFlags = 0;

 

          mmresult = waveOutPrepareHeader(hWaveOut,

                                 whout+i, sizeof(WAVEHDR));

          if (mmresult!=MMSYSERR_NOERROR) return;

 

  double scale = 2.0 * M_PI / BUFLEN;

  int amplitude = 3;                // выбранная величина

     for(int j=0;j<BUFLEN;j++)

       {

 int time = j;      //характеризует долю периода колебаний

 whout[i].lpData[j] = int(amplitude * sin(time * ton * scale));

        }

          // Проиграть buffer

  mmresult = waveOutWrite(hWaveOut, whout+i,

                          sizeof(WAVEHDR));

     if (mmresult!=MMSYSERR_NOERROR)

                return;        

     }

     bWaveOutIsStarted = 1;

}

//----------------------------------------------------------------------

// Функция реагирует на нажатие кнопки

void __fastcall TForm1::Button2Click(TObject *Sender)           // 5

{

 ton = 440;

 TestOut(ton);

}

//----------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)            // 6

{

   ton = 6000;

 TestOut(ton);

}

//----------------------------------------------------------------------

void __fastcall TForm1::Button4Click(TObject *Sender)            // 7

{

 ton = 800;

 TestOut(ton);

}

//----------------------------------------------------------------------

void __fastcall TForm1::Button5Click(TObject *Sender)            // 8

{

  ton = 1000;

 TestOut(ton);

}

//-----------------------------------------------------------------------

void __fastcall TForm1::Button6Click(TObject *Sender)              // 9

{

  ton = 1200;

 TestOut(ton);

}

//----------------------------------------------------------------------

void __fastcall TForm1::Button7Click(TObject *Sender)             // 10

{

  ton = 1600;

 TestOut(ton);

}

//----------------------------------------------------------------------

void __fastcall TForm1::Button8Click(TObject *Sender)            // 11

{

  ton = 2000;

 TestOut(ton);

}

//----------------------------------------------------------------------

void __fastcall TForm1::Button9Click(TObject *Sender)             // 12

{

  ton = 2200;

 TestOut(ton);

}

//----------------------------------------------------------------------

 

Функция 3 служит для прекращения проигрывания звука. Функция 4 выполняет проигрывание звука с заданной величиной звуковой частоты.

Следует заметить, что указанные величины частот могут не соответствовать истинным величинам, измеренным при помощи частотомера. Моей целью было только показать один из возможных вариантов получения синусоидального звука. Для тех читателей, которые хотели бы познакомиться с различными методами получения звука цифровыми методами рекомендую прочитать [4].

Функции 5 … 12 являются реакциями на нажатие соответствующих клавиш и выполняют проигрывание звука, записанного в цифровом виде в буфере.

На рис. 6.16 показано главное окно работающего приложения. При нажатии на любую из кнопок, на которых указана величина частоты, начинается звучание гармонического сигнала с примерно указанной частотой. Звучание длится примерно 3 … 4 секунды. Кнопкой Стоп можно прервать звучание в любой момент.

Рис. 6.16. Проверка гармонического звука

Подобного типа программу можно использовать при разработке проекта DLL библиотеки (см. главу 3), предназначенной для передачи телеграфного сигнала. Результаты будут значительно лучшими, чем при использовании функции PlaySound. Попробуйте сами выполнить такой вариант DLL.