Электронная библиотека » Александр Чиртик » » онлайн чтение - страница 4


  • Текст добавлен: 10 ноября 2013, 00:08


Автор книги: Александр Чиртик


Жанр: Программирование, Компьютеры


сообщить о неприемлемом содержимом

Текущая страница: 4 (всего у книги 24 страниц)

Шрифт:
- 100% +
Окно с элементами управления

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

• BUTTON – оконный класс, реализующий работу обычной кнопки, флажка, переключателя и даже рамки для группы элементов управления (GroupBox);

• COMBOBOX – раскрывающийся список;

• EDIT – текстовое поле, может быть как однострочным, так и многострочным, с полосами прокрутки и без;

• LISTBOX – список;

• SCROLLBAR – полоса прокрутки;

• STATIC – статический текст (он же Label, надпись, метка и пр.), кроме текста, может содержать изображение.

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

Создание элементов управления

Целесообразно написать более краткие функции создания элементов управления, чтобы, формируя интерфейс формы «на лету», не приходилось усложнять код громоздкими вызовами функций CreateWindow или CreateWindowEx. Этим мы сейчас и займемся. Сразу необходимо отметить: предполагается, что все функции помещены в модуль (модуль Controls в файле Controls.pas), в котором объявлены глобальные переменные hAppInst и hParentWnd. Эти переменные инициализируются перед вызовом первой из перечисленных ниже процедур или функций создания и работы с элементами управления (инициализацию можно посмотреть в листинге 2.21).


Внимание!

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

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

Листинг 2.7. Создание кнопки

function CreateButton(x, y, width, height, id:Integer;

caption: String):HWND;

begin

CreateButton:=

CreateWindow('BUTTON', PAnsiChar(caption), WS_CHILD or WS_VISIBLE or

BS_PUSHBUTTON or WS_TABSTOP, x, y, width, height,

hParentWnd, HMENU(id), hAppInst, nil);

end;


Приведенная в листинге 2.8 функция создает флажок и устанавливает его.

Листинг 2.8. Создание флажка

function CreateCheck(x, y, width, height, id: Integer; caption: String;

checked: Boolean):HWND;

var

res: HWND;

begin

res:=

CreateWindow('BUTTON', PAnsiChar(caption), WS_CHILD or WS_VISIBLE or

BS_AUTOCHECKBOX or WS_TABSTOP, x, y, width, height,

hParentWnd, HMENU(id), hAppInst, nil);

if ((res <> 0) and checked) then

SendMessage(res, BM_SETCHECK, BST_CHECKED, 0); //Флажок установлен

CreateCheck:= res;

end;


Следующая функция создает переключатель (листинг 2.9). Если нужно, то он устанавливается. Новый переключатель может начинать новую группу переключателей, для чего нужно параметру group присвоить значение True.

Листинг 2.9. Создание переключателя

function CreateOption(x, y, width, height, id: Integer; caption: String;

group: Boolean; checked: Boolean):HWND;

var

res: HWND;

nGroup: Integer;

begin

if (checked) then nGroup:= WS_GROUP else nGroup:= 0;

res:=

CreateWindow('BUTTON', PAnsiChar(caption), WS_CHILD or WS_VISIBLE or

BS_AUTORADIOBUTTON or nGroup or WS_TABSTOP, x, y, width,

height, hParentWnd, HMENU(id), hAppInst, nil);

if ((res <> 0) and checked) then

//Переключатель установлен

SendMessage(res, BM_SETCHECK, BST_CHECKED, 0);

CreateOption:= res;

end;


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

Листинг 2.10. Создание рамки

function CreateFrame(x, y, width, height, id: Integer;

caption: String):HWND;

begin

CreateFrame:=

CreateWindow('BUTTON', PAnsiChar(caption), WS_CHILD or WS_VISIBLE or

BS_GROUPBOX, x, y, width, height, hParentWnd,

HMENU(id), hAppInst, nil);

end;


Для создания раскрывающегося списка (ComboBox) пригодится функция Create-Combo, приведенная в листинге 2.11.

Листинг 2.11. Создание раскрывающегося списка

function CreateCombo(x, y, width, height, id: Integer):HWND;

begin

CreateCombo:=

CreateWindow('COMBOBOX', nil, WS_CHILD or WS_VISIBLE or CBS_DROPDOWN

or CBS_AUTOHSCROLL or WS_TABSTOP, x, y, width, height,

hParentWnd, HMENU(id), hAppInst, nil);

end;


Для создания простого списка (ListBox) вполне подойдет функция CreateList, описанная в листинге 2.12.

Листинг 2.12. Создание простого списка

function CreateList(x, y, width, height, id: Integer):HWND;

begin

CreateList:=

CreateWindowEx(WS_EX_CLIENTEDGE, 'LISTBOX', nil, WS_CHILD or WS_VISIBLE

or LBS_NOTIFY or WS_BORDER or WS_TABSTOP, x, y, width,

height, hParentWnd, HMENU(id), hAppInst, nil);

end;


Функция CreateLabel, приведенная в листинге 2.13, создает статическую надпись (Label), предназначенную только для вывода текста.

Листинг 2.13. Создание надписи

function CreateLabel(x, y, width, height, id: Integer;

caption: String):HWND;

begin

CreateLabel:=

CreateWindow('STATIC', PAnsiChar(caption), WS_CHILD or WS_VISIBLE, x,

y, width, height, hParentWnd, HMENU(id), hAppInst, nil);

end;


Однострочное текстовое поле с привычной рамкой создается функцией CreateEdit (листинг 2.14).

Листинг 2.14. Создание однострочного текстового поля

function CreateEdit(x, y, width, height, id: Integer; strInitText: String):HWND;

begin

CreateEdit:=

CreateWindowEx(WS_EX_CLIENTEDGE, 'EDIT', PAnsiChar(strInitText),

WS_CHILD or WS_VISIBLE or ES_AUTOHSCROLL or WS_TABSTOP,

x, y, width, height, hParentWnd,

HMENU(id), hAppInst, nil);

end;


Код создания многострочного текстового поля (аналог Memo) отличается от кода создания однострочного поля только указанием дополнительного флага ES_MULTILINE (листинг 2.15).

Листинг 2.15. Создание многострочного текстового поля

function CreateMemo(x, y, width, height, id: Integer; strInitText: String):HWND;

begin

CreateMemo:=

CreateWindowEx(WS_EX_CLIENTEDGE, 'EDIT', PAnsiChar(strInitText),

WS_CHILD or WS_VISIBLE or ES_AUTOVSCROLL or ES_MULTILINE

or WS_TABSTOP, x, y, width, height, hParentWnd,

HMENU(id), hAppInst, nil);

end;


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

Использование элементов управления

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

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

Итак, в демонстрационном проекте для управления переключателями и флажками предусмотрены следующие функции и процедуры (листинг 2.16).

Листинг 2.16. Управление флажками и переключателями

//Установка/снятие флажка (установка/снятие переключателя)

procedure SetChecked(id: Integer; checked: BOOL);

var state: Integer;

begin

if (checked) then state:= BST_CHECKED

else state:= BST_UNCHECKED;

SendDlgItemMessage(hParentWnd, id, BM_SETCHECK, state, 0);

end;

//Получение информации о том, установлен ли флажок

//(установлен ли переключатель)

function GetChecked(id: Integer):BOOL;

begin

if (SendDlgItemMessage(hParentWnd, id, BM_GETCHECK, 0, 0) = BST_CHECKED)

then GetChecked:= True

else GetChecked:= False;

end;


Функции и процедуры, описанные в листинге 2.17, предназначены для управления раскрывающимся списком (элементом ComboBox).

Листинг 2.17. Управление раскрывающимся списком

//Добавление строки в список

procedure AddToCombo(id: Integer; str: String);

begin

SendDlgItemMessage(hParentWnd, id, CB_ADDSTRING, 0,

Integer(PAnsiChar(str)));

end;

//Удаление строки из списка

procedure DeleteFromCombo(id: Integer; index: Integer);

begin

SendDlgItemMessage(hParentWnd, id, CB_DELETESTRING, index, 0);

end;

//Выделение строки с заданным номером

procedure SetComboSel(id: Integer; index: Integer);

begin

SendDlgItemMessage(hParentWnd, id, CB_SETCURSEL, index, 0);

end;

//Получение номера выделенной строки (CB_ERR, если нет выделения)

function GetComboSel(id: Integer): Integer;

begin

GetComboSel:= SendDlgItemMessage(hParentWnd, id, CB_GETCURSEL, 0, 0);

end;

//Получение количества строк

function GetComboCount(id: Integer): Integer;

begin

GetComboCount:= SendDlgItemMessage(hParentWnd, id, CB_GETCOUNT, 0, 0);

end;

//Получение текста строки по ее индексу

function GetComboItemText(id: Integer; index: Integer):String;

var buffer: String;

begin

SetLength(buffer,

SendDlgItemMessage(hParentWnd, id, CB_GETLBTEXTLEN, index, 0)

);

SendDlgItemMessage(hParentWnd, id, CB_GETLBTEXT, index,

Integer(Addr(buffer)));

GetComboItemText:= buffer;

end;


Сходные функции и процедуры, приведенные в листинге 2.18, предназначены для управления списком (элементом ListBox).

Листинг 2.18. Управление списком

//Добавление строки в список

procedure AddToList(id: Integer; str: String);

begin

SendDlgItemMessage(hParentWnd, id, LB_ADDSTRING, 0, Integer(PAnsiChar(str)));

end;

//Удаление строки из списка

procedure DeleteFromList(id: Integer; index: Integer);

begin

SendDlgItemMessage(hParentWnd, id, LB_DELETESTRING, index, 0);

end;

//Выделение строки с заданным номером

procedure SetListSel(id: Integer; index: Integer);

begin

SendDlgItemMessage(hParentWnd, id, LB_SETCURSEL, index, 0);

end;

//Получение номера выделенной строки (LB_ERR, если нет выделения)

function GetListSel(id: Integer): Integer;

begin

GetListSel:= SendDlgItemMessage(hParentWnd, id, LB_GETCURSEL, 0, 0);

end;

//Получение количества строк

function GetListCount(id: Integer): Integer;

begin

GetListCount:= SendDlgItemMessage(hParentWnd, id, LB_GETCOUNT, 0, 0);

end;

//Получение текста строки по ее индексу

function GetListItemText(id: Integer; index: Integer):String;

var buffer: String;

begin

SetLength(buffer,

SendDlgItemMessage(hParentWnd, id, LB_GETTEXTLEN, index, 0)

);

SendDlgItemMessage(hParentWnd, id, LB_GETTEXT, index,

Integer(Addr(buffer)));

GetListItemText:= buffer;

end;


Функции и процедуры, приведенные в листинге 2.19, дают возможность управлять текстовыми полями (элементы Edit и Memo).

Листинг 2.19. Управление текстовыми полями

//Получение позиции первого выделенного символа (нумерация с нуля)

function GetSelStart(id: Integer): Integer;

var selStart, selEnd: Integer;

begin

SendDlgItemMessage(hParentWnd, id, EM_GETSEL, Integer(Addr(selStart)),

Integer(Addr(selEnd)));

GetSelStart:= selStart;

end;

//Получение длины выделенного фрагмента текста

function GetSelLength(id: Integer): Integer;

var selStart, selEnd: Integer;

begin

SendDlgItemMessage(hParentWnd, id, EM_GETSEL, Integer(Addr(selStart)),

Integer(Addr(selEnd)));

GetSelLength:= selEnd – selStart;

end;

//Выделение фрагмента текста (позиция первого символа с нуля)

procedure SetSel(id: Integer; start, length: Integer);

begin

SendDlgItemMessage(hParentWnd, id, EM_SETSEL, start, start + length);

end;

//Получение выделенного фрагмента текста

function GetSelText(id: Integer): String;

var allText: String;

begin

allText:= GetText(id);

GetSelText:= Copy(allText, GetSelStart(id)+1,GetSelLength(id));

end;

//Замена выделенного текста

procedure ReplaceSelText(id: Integer; newText: String);

begin

SendDlgItemMessage(hParentWnd, id, EM_REPLACESEL,

0, Integer(PAnsiChar(newText)));

end;


В листинге 2.20 приведены функции и процедуры, которые можно применять ко всем элементам управления с одинаковым успехом.

Листинг 2.20. Общие функции и процедуры

//Установка текста окна

procedure SetText(id: Integer; str: String);

begin

SetWindowText(GetDlgItem(hParentWnd, id), PAnsiChar(str));

end;

//Получение текста окна

function GetText(id: Integer): String;

var buffer: String;

begin

SetLength(buffer, GetWindowTextLength(hParentWnd));

GetWindowText(hParentWnd, PAnsiChar(buffer), Length(buffer));

GetText:= buffer;

end;

//Активизация/деактивизация окна

procedure SetEnabled(id: Integer; fEnabled: BOOL);

begin

EnableWindow(GetDlgItem(hParentWnd, id), fEnabled);

end;

Реакция на сообщения элементов управления

При возникновении какого-либо предусмотренного для элемента управления события родительскому окну посылается сообщение WM_COMMAND.

Примечание

Сообщение WM_COMMAND приходит также при перерисовке так называемых «самоперерисовывающихся» (Owner Draw) элементов управления. Однако ввиду специфики данного вопроса и ограниченности объема главы оно рассматриваться не будет.

Таким образом, когда родительское окно получает сообщение WM_COMMAND, то из двух прилагающихся параметров (lParam и wParam) можно извлечь следующие сведения:

• старшие 16 бит wParam представляют собой целочисленный код уведомления, позволяющий определить, что именно произошло с элементом управления;

• младшие 16 бит wParam представляют собой идентификатор элемента управления, состояние которого изменилось (именно этот идентификатор передавался вместо дескриптора меню при создании элементов управления);

• lParam содержит дескриптор (HWND) окна элемента управления, состояние которого изменилось.

Для выделения старших 16 бит из 32-битного значения можно использовать функцию HiWord. Для получения младших 16 бит можно использовать функцию с именем LoWord. Обе функции объявлены в модуле Windows.

В качестве примеров можно привести следующие коды уведомлений:

• BN_CLICKED – нажата кнопка;

• EN CHANGE – изменен текст в текстовом поле;

• LBN_SELCHANGE – изменилось выделение в списке;

• CBN_SELCHANGE – изменилось выделение в раскрывающемся списке.

Эти и все остальные константы уведомлений стандартных элементов управления объявлены в модуле Messages.

Примечание

Коды и описания уведомлений рассматриваемых в этой главе элементов управления приведены в приложении 3.

Пример приложения

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

Не буду заострять внимание на регистрации класса главного окна приложения, так как она аналогична приведенной в листинге 2.4. Рассмотрим создание окна с элементами управления в нем (листинг 2.21).

Листинг 2.21. Создание главного окна приложения (с элементами управления)

program ControlsDemo;

uses

Windows, Messages,

Controls in 'Controls.pas';

{$R *.res}

var

hMainWnd: HWND;

hInst: Cardinal;

mess: MSG;

//Функция обработки сообщений

...

//Создание окна и цикл обработки сообщений

begin

hInst:= GetModuleHandle(nil);

//Регистрация и создание главного окна

if not RegisterWindow() then Exit;

hMainWnd:= CreateWindow(

'MyWindowClass', //Имя класса окна

'Главное окно', //Заголовок окна

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, //Координата X по умолчанию

CW_USEDEFAULT, //Координата Y по умолчанию

CW_USEDEFAULT, //Ширина по умолчанию

CW_USEDEFAULT, //Высота по умолчанию

HWND(nil), //Нет родит ельского окна

HMENU(nil), //Нетменю

hInst,

nil);

if (hMainWnd = HWND(nil)) then Exit;

//Инициализация модуля Controls для работы с главным окном

Controls.hParentWnd:= hMainWnd;

Controls.hAppInst:= hInst;

//Создание элементов управления

CreateFrame(10, 80, 170, 70, –1, 'Кнопки');

CreateButton(2 0, 100, 70, 30, 1001, 'Кнопка 1');

CreateButton(100, 100, 70, 30, 1002,'Кнопка 2');

CreateFrame(2 00, 10, 200, 180, –1, 'Флажки и переключатели');

CreateCheck(2 10, 30, 180, 20, 2001, 'Флажок 1');

CreateCheck(2 10, 60, 180, 20, 2002, 'Флажок 2', True);

CreateOption(2 10, 100, 180, 20, 3001, 'Переключатель 1', True);

CreateOption(2 10, 130, 180, 20, 3002, 'Переключатель 2', False, True);

CreateOption(2 10, 160, 180, 20, 3003, 'Переключатель 3', True);

CreateFrame(420, 10, 300, 180, –1, 'Списки и статические надписи');

CreateLabel(430, 30, 70, 20, -1, 'Надпись');

CreateCombo(510, 30, 200, 100, 4001);

CreateList(430, 60, 280, 120, 5001);

CreateFrame(2 00, 200, 200, 240, –1, 'Текстовые поля');

CreateEdit(2 10, 22 0, 180, 20, 6001, 'Текст в текстовом поле');

CreateMemo(2 10, 25 0, 180, 180, 6002, 'Текст в многострочном'+ #13

+ #10 + 'текстовом поле');

//Добавление строк в списки

AddToCombo(4001, 'Строка 1');

AddToCombo(4001, 'Строка 2');

AddToCombo(4001, 'Строка 3');

AddToList(5 001, 'Строка 1');

AddToList(5 001, 'Строка 2');

AddToList(5 001, 'Строка 3');

ShowWindow(hMainWnd, SW_NORMAL);

//Запуск цикла обработки сообщений

while (Longint(GetMessage(mess, 0, 0, 0)) <> 0)

do begin

TranslateMessage(mess);

DispatchMessage(mess);

end;

end.


Код листинга 2.21 заодно демонстрирует использование некоторых из приведенных ранее функций работы с элементами управления. Выглядит созданное окно так, как показано на рис. 2.3.

Рис. 2.3. Окно с элементами управления


Принцип построения функции обработки сообщений для этого окна описан в листинге 2.22.

Листинг 2.22. Функция обработки сообщений

//Функция обработки сообщений

function WindowFunc(hWnd:HWND; msg:UINT;

wParam:WPARAM; lParam:LPARAM):LRESULT; stdcall;

var

ps: PAINTSTRUCT;

begin

case msg of

WM_PAINT:

begin

//Перерисовка содержимого окна

BeginPaint (hWnd, ps);

Text Out (ps.hdc, 10, 10, 'Текст в окне', 12);

EndPaint(hWnd, ps);

end;

WM_CLOSE:

if (hWnd = hMainWnd) then

PostQuit Message(0); //При закрытии этого окна завершается

//приложение

WM_COMMAND:

begin

case LOWORD(wParam) of

//нажата "Кнопка 1"

1001: if HIWORD(wParam) = BN_CLICKED then;

//нажата "Кнопка 2"

1002: if HIWORD(wParam) = BN_CLICKED then;

//установлен "Флажок 1"

2001: if HIWORD(wParam) = BN_CLICKED then;

//установлен "Флажок 2"

2002: if HIWORD(wParam) = BN_CLICKED then;

//установлен "Переключатель 1"

3001: if HIWORD(wParam) = BN_CLICKED then;

//установлен "Переключатель 2"

3002: if HIWORD(wParam) = BN_CLICKED then;

//установлен "Переключатель 3"

3003: if HIWORD(wParam) = BN_CLICKED then;

//выделение в ComboBox

4001: if HIWORD(wParam) = CBN_SELCHANGE then;

//выделение в ListBox

5001: if HIWORD(wParam) = LBN_SELCHANGE then;

//изменен текст в Edit

6001: if HIWORD(wParam) = EN_CHANGE then;

//изменен текст в Memo

6002: if HIWORD(wParam) = EN_CHANGE then;

end;

end;

else

begin

//Обработка по умолчанию

WindowFunc:= DefWindowProc(hWnd, msg, wParam, lParam);

Exit;

end;

end;

WindowFunc:= S_OK; //Сообщение обработано

end;


Приведенная в листинге 2.22 функция не претендует на то, чтобы быть эталоном в порядке классификации сообщений от элементов управления. Иногда бывает полезно сразу классифицировать сообщения не по элементам управления, которые их прислали, а по типу самих сообщений. К тому же в ряде случаев можно предусмотреть один обработчик сообщений сразу для нескольких элементов управления, например, для группы переключателей. В таком случае полезным окажется параметр lParam сообщения WM COMMAND.

Кстати, размер исполняемого файла этого приложения равен всего 19 Кбайт.

Стандартные окна Windows

Теперь рассмотрим, как можно с помощью только функций Windows API вызывать некоторые распространенные окна. Чтобы использовать API-функции и структуры с информацией для этих окон, необходимо подключить следующие модули:

• CommDlg – для окон открытия и сохранения файла, выбора цвета и шрифта, поиска и замены текста;

• ShlObj и ActiveX – для окна выбора папки (второй модуль нужен для доступа к интерфейсу IMalloc, зачем – будет рассказано далее);

• Windows – помимо объявления основных структур и API-функций, этот модуль содержит объявления функций для работы с окнами подключения и отключения от сетевого ресурса (сетевого диска);

• ShellAPI – для системного окна О программе.

Вариант использования рассматриваемых в этом разделе окон приведен в подразделе «Демонстрационное приложение» данной главы (стр. 81).

Примечание

В приведенных далее примерах вызова окон можно увидеть не объявленные, но используемые в программах переменные hAppInst и hParentWnd. Подразумевается, что это глобальные переменные, которые инициализируются вне процедур и функций, приведенных в примерах. Для инициализации этих переменных можно также написать специальную процедуру, например, с именем Init, в которую и передавать значения для hParentWnd и hAppInst.

Окно открытия и сохранения файла

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

Листинг 2.23. Окно открытия файла

function ShowOpen(strFilter: string; nFilterIndex: Integer= 0;

strInitFileName: string = '';

var

ofn: OPENFILENAME;

begin

ZeroMemory(Addr(ofn), SizeOf(ofn));

//Формирование буфера (260 символов)

SetLength(strInitFileName, MAX_PATH);

PrepareFilterString(strFilter);

//Заполнение структуры для окна

ofn.lStructSize:= SizeOf(ofn);

ofn.hWndOwner:= hParentWnd;

ofn.hInstance:= hAppInst;

ofn.lpstrFilter:= PAnsiChar(strFilter);

ofn.nFilterIndex:= nFilterIndex;

ofn.lpstrFile:= PAnsiChar(strInitFileName);

ofn.nMaxFile:= MAX_PATH;

ofn.lpstrTitle:= pAnsiChar(strTitle);

ofn.Flags:= OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_HIDEREADONLY;

//Отображение окна и обработка результата

if(GetOpenFileName(ofn) = True) then

ShowOpen:= ofn.lpstrFile;

end;


Приведенная в листинге 2.23 функция возвращает непустую строку – полный путь файла в случае, если пользователь выбрал или ввел имя файла. Здесь главной трудностью является заполнение довольно большой структуры OPENFILENAME. В данном примере используются только базовые возможности окна открытия файла и лишь некоторые из поддерживаемых им флагов (поле Flags):

• OFN_FILEMUSTEXIST – при этом установленном флаге, если окно успешно завершило свою работу, можно быть уверенным, что результирующий путь является путем существующего файла;

• OFN_PATHMUSTEXIST – данный флаг не дает ввести имя файла в несуществующей папке (например, при вводе c: docsmydoc1.doc, если папки docs не существует, будет выдано соответствующее сообщение);

• OFN_HIDEREADONLY – позволяет скрыть флажок Только для чтения.

Теперь отдельно рассмотрим, зачем в приведенном примере вызывается дополнительная функция PrepareFilterString (листинг 2.24).

Листинг 2.24. Преобразование строки фильтра

procedure PrepareFilterString(var strFilter: string);

var

i: Integer;

begin

for i:= 1 to length(strFilter) do

if (strFilter[i] = '|') then strFilter[i]:= #0;

end;


Дело в том, что при задании фильтров (поле lpstrFile) требуется, чтобы каждое название и обозначение фильтров были отделены символом #0, а за последним фильтром шла последовательность из двух нулевых символов. На практике задавать строку из нескольких фильтров в следующем виде недостаточно удобно:


'Текстовые файлы'+ #0 + '*.txt'+ #0 + 'Все файлы'+ '*.*'+ #0 + #0


Поэтому часто применяются другие разделители, которые впоследствии преобразуются в символы #0. В данном случае в качестве разделителя используется символ |, благодаря чему приведенная выше строка фильтра может быть записана так:


'Текстовые файлы|*.txt |Все файлы|*.*||'


Согласитесь, что получилось более кратко и понятно.

Теперь обратимся к окну сохранения файла. Для его вызова достаточно переделать код из листинга 2.23 следующим образом (листинг 2.25).

Листинг 2.25. Окно сохранения файла

function ShowSave(strFilter: string; nFilterIndex: Integer = 0;

strInitFileName: string = '';

strTitle: string = 'Сохранение файла'):string;

var

ofn: OPENFILENAME;

begin

ZeroMemory(Addr(ofn), SizeOf(ofn));

//Формирование буфера (260 символов)

SetLength(strInitFileName, MAX_PATH);

PrepareFilterString(strFilter);

//Заполнение структуры для окна

ofn.lStructSize:= SizeOf(ofn);

ofn.hWndOwner:= hParentWnd;

ofn.hInstance:= hAppInst;

ofn.lpstrFilter:= PAnsiChar(strFilter);

ofn.nFilterIndex:= nFilterIndex;

ofn.lpstrFile:= PAnsiChar(strInitFileName);

ofn.nMaxFile:= MAX_PATH;

ofn.lpstrTitle:= pAnsiChar(strTitle);

ofn.Flags:= OFN_PATHMUSTEXIST or OFN_OVERWRITEPROMPT;

//Отображение окна и обработка результата

if (GetSaveFileName(ofn) = True) then

ShowSave:= ofn.lpstrFile;

end;


Здесь дополнительно к упомянутому ранее флагу OFN_PATHMUSTEXIST добавлен флаг OFN_OVE RWRITEPROMPT для того, чтобы при указании имени уже существующего файла был задан вопрос, желает ли пользователь заменить этот файл.


Страницы книги >> Предыдущая | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | Следующая
  • 0 Оценок: 0

Правообладателям!

Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.


Популярные книги за неделю


Рекомендации