|
[ Главная ] [ Статьи ] [ Для новичков ] [ Примеры ] [ Программы ] [ Microsoft Agent 2.0 ] [ Пособие ] [ Уроки ] [ Разное ] |
Диалоговые панели Microsoft Common Dialog ControlОчевидно, что программа должна как-то открывать и сохранять файлы, а так же изменять параметры принтера, шрифт, цвет фона и текста. К счастью всю эту функциональность в одном флаконе предоставляет элемент управления Common Dialog. Но ряд не больших проблем всё же остаётся. Во первых, Common Dialog - действительно элемент управления, а нам это как раз и не нужно. Он должен находится в каком ни будь контейнере, например в форме, а часто бывает необходимо использовать его в программе без форм. Но мои основные претензии в том, что его архитектура... Как бы выразится по мягче... Отсутствует напрочь. Его разработали в те далёкие времена, когда элементы управления были единственным средством, обеспечивающим повторное использование, и его интерфейс представляет собой мешанину свойств. Сейчас компоненты которым не нужны визуальный интерфейс и события, можно поставлять в гораздо более удобной форме открытых классов. Опять же у счастью, Visual Basic включает в себя не визуальный компонент Microsoft Dialog Automation Objects (DLGOBJS.DLL). Забудьте об элементах управления. Теперь можно создавать диалоговые объекты и вызывать их методы и свойства без всяких форм. Я был приятно удивлен обнаружив этот компонент в каталоге \Tool\Unsupprt на установочном диске Visual Basic. Им намного проще пользоваться чем элементом управления Common Dialog. Но увы, когда говорят "Не поддерживается", значит так оно и есть. Я нашел у него одно серьёзное ограничение, которое смог обойти, и несколько небольших которые обойти не смог. Надеюсь, что в следующей версии Visual Basic диалоговые объекты станут "поддерживаться" и будут интегрированы в библиотеку самого языка. А тем временем... элемент управления. Стоп!!! Какой элемент управления?! Не нужен нам этот ужасный Common Dialog! Реализация стандартных диалоговых окон: Windows плюс Basic. Сравним несколько подходов к стандартным диалоговым окнам. Начнём с одного из самых простых - предназначенного для выбора цвета - и рассмотрим способы вывода его на экран. Первый - традиционный приём с использованием Common Dialog. Здесь предполагается, что элемент управления расположен на Form, UserControl или PropertyPage:
Этот код не без шероховатостей. Управление поведением требует записи в свойство Flags определённой константы, а VB представляет н все константы. Хорошо когда знаешь что этот элемент управления лишь очень тонкая оболочка API - функций и распознаёт любые константы, какие только упомянуты в документации Windows API. Обработка кнопки Cancel организована просто отвратительно, но раньше было ещё хуже. Кто работал с более ранними версиями знает, о чём я говорю, а кто не работал, тому и знать не зачем. Версия с Dialog Automation Objects выглядит гораздо лучше:
Характеристики окна определяются свойствами. Перед выводом окна на экран вы их устанавливаете, а за тем считываете. Только вот разработчики не дали нам одного важного свойства : для показа лишь основных цветов (без составных). RichTextBox не понимает составных цветов ни для фона ни для текста - зачем же их показывать? Понятно, что разработчики хотели упростить работу большинству пользователей, а если их выбор не совпал с моим или Вашим, то нам просто не повезло. И наконец, моя версия:
В место свойств я применил именованные аргументы. Поскольку разработчик я, то я позаботился обо всех нужных мне параметрах, но Вам, возможно, понадобятся и другие. В этом примере мой код короче, но так бывает не всегда. Я, конечно, предпочёл бы более структурированный интерфейс доступа к диалоговым объектом, и, как только в Dialog Automation Objects появится всё, что мне надо, тут же выброшу свою версию. Есть еще один способ вывода стандартного диалогового окна: разработать свой собственный вариант, но об этом в другой раз. Использование стандартных диалоговых окон. Если вы видели хоть одну функцию стандартного диалогового окна, значит, Вы видели все. Поэтому я расскажу только о создании самой сложной и самой нужной из них - функции, открывающей диалоговое окно Open. Диалоговое окно Save As ему практически идентично, Font и Color сравнительно просты, а Print Setup и Page Setup, хоть они и несколько отличаются я не стану разбирать в деталях. Вызываем функцию VBGetOpenFileName. Реализация оболочки - VBGetOpenFileName. И наконец, о самом трудном - о реализации оболочки для GetOpenFileName. Фокус в том, чтобы заполнить поля UDT (User Defended Type),ожидаемый GetOpenFileName, замаскировав этот процесс именованными аргументами. Все закрытые типы и объявления, используемые в открытых функциях VBGetOpenFileName, VBGetSaveFileName, VBChooseFont, VBPrintDlg и VBPageSetupDlg находятся в модуле COMDLG. Структура OPENFILENAME Private
Type OPENFILENAME Это громоздкий UDT, но не все его поля нужны. Некоторые можно игнорировать, так как это просто выкрутасы. Вам например совершенно не зачем получать здесь позицию начала имени файла и его расширение в полном пути, когда это необходимо то проще самому разбить путь или вызвать GetFullPathName. Обрабатываемых полей вполне достаточно в 98% случаев.
Поля UDT служат и для входных, и для выходных данных. Перед вызовом инициализируются одни поля, после вызова считываются другие. Некоторые (к примеру Flags) работают в обе стороны. Наша функция может получить выходные данные через переменные передаваемые по ссылки. Конечно, переменные нужны не всегда, так как все аргументы, кроме одного, необязательные. Можно , например, опустить параметр Flags или передать его как константу. В последнем случае функция не заметит разницы и запишет результат во временную переменную, созданную Visual Basic. Ничего страшного не произойдёт, Вы просто не увидите результатов. Обработка не обязательных параметров. Не обязательные параметры обрабатывает первая часть функции VBGetOpenFileName, присваивая всем пропущенным значения по умолчанию: Function VBGetOpenFileName(FileName As
String, _ Dim opfile As OPENFILENAME, s As
String, afFlags As Long
Как видите параметров много, но лишь один обязательный - FileName, поскольку без него функция недееспособна. Остальные параметры определяют входные и в нескольких случаях выходные данные. Так например HideReadOnly указывает, надо ли помещать в диалоговое окно флажок Open As Read-Only, а параметр ReadOnly задаёт начальное состояние этого флажка. На выходе из функции в параметр ReadOnly записывается значение, которое сообщает конечное состояние флажка Open As Read-Only. И вновь вы должны передать переменную. Если вы передадите константу, то поместить результат будет некуда. Параметры FileMustExist, MultiSelect, ReadOnly и HideReadOnly представляют наиболее часто используемые флаги. Сейчас их свыше десятка, а в будущих версиях Windows к ним могут добавится новые. Параметр Flags позволяет обрабатывать любые интересующие вас флаги. Иными словами, моя реализация Вас ни чем не сковывает. Обработка фильтров, имён файлов и флагов. VBGetOpenFileName ожидает, что строки фильтров разделены вертикальной чертой ( | ) или двоеточием. Элемент управления Common Dialog допускает в качестве разделителя только первый символ, но я следую стилю компонента Dialog Automation Objects, где описание можно отделить от соответствующего ему расширения двоеточием: Rich text files (*.rtf): *.rtf| ..... Работает и формат Common Dialog. Но ни один из этих форматов не устраивает Windows, которая ждёт в качестве разделителя нулевой символ и два нулевых символа в конце списка. Приходится самому преобразовывать строку: ' Чтобы создать фильтр в стиле Windows, заменяем | и : null-символами Dim ch As String, i As Long For i = 1 To Len(filter) ch = Mid$(filter, i, 1) If ch = "|" Or ch = ":" Then s = s & vbNullChar Else s = s & ch End If Next ' Помещаем в конец два null-символа s = s & vbNullChar & vbNullChar .lpstrFilter = s .nFilterIndex = FilterIndex Создав новую строку фильтра, Вы просто записываете её в поле UDT-переменной. Поля lpstrFile и lpstrFileTitle должны указывать на строковые буферы, размер которых достаточен для размещения в них любого возможного значения. Этот максимальный размер задаётся в полях nMaxFile и nMaxFileTitle. Вы записываете в них константы cMaxPath и cMaxFile, а строковые буфера заполняете строками этой длинны. Это позволяет избежать неприятностей из-за слишком малого буфера. Полученные строки преобразуем в формат Visual Basic: ' Создаём буфер максимальной длинны s = FileName & String$(cMaxPath - Len(FileName), 0) .lpstrFile = s .nMaxFile = cMaxPath s = FileTitle & String$(cMaxFile - Len(FileTitle), 0) .lpstrFileTitle = s .nMaxFileTitle = cMaxFile ' Остальные поля приравниваем к нулю Остальное пусть делает Windows. К этому моменту мы уже поместили все необходимые входные данные в UDT-переменную и готовы вызвать API-функцию GetOpenFileName. Данные, которые диалоговое окно вернёт вам, будут представлены в формате Windows с нулевым символом на конце. Придётся слегка преобразовать их чтобы вернуть вызывающей программе в формате Visual Basic: If GetOpenFileName(opfile) Then VBGetOpenFileName = True FileName = MUtility.StrZToStr(.lpstrFile) FileTitle = MUtility.StrZToStr(.lpstrFileTitle) Flags = .Flags ' Возвращаем индекс фильтра FilterIndex = .nFilterIndex ' Подставляем, выбранный пользователем в диалоговом окне filter = FilterLookup(.lpstrFilter, FilterIndex) If (.Flags And OFN_READONLY) Then ReadOnly = True Else VBGetOpenFileName = False FileName = sEmpty FileTitle = sEmpty Flags = 0 FilterIndex = -1 filter = sEmpty End If End With End Function Строки в UDT-переменной - на самом деле буферы максимальной длинны. Windows запишет в буфер выходную строку, но не изменит размер буфера. Вы должны сами отсечь лишние символы и вернуть строку в ссылочную переменную, переданную пользователем. Если же пользователь такой переменной не передал, Visual Basic создаст временную переменную, но результат будет утерян. Параметр Filter на выходе изменяется и возвращает выбранный фильтр, поэтому предавайте ему копию строки фильтра, а не оригинал. VBGetOpenFileName служит моделью для других функций, написанных на Visual Basic и поддерживающие стандартные диалоговые окна. Все они находятся в модуле COMDLG.BAS. |
|
|
|
>>>Если у вас есть статья которой нет на сайте
пришлите ее мне--------> Послать статью >>>Если вы хотите задать вопрос пишите--------> Мне нужна помощь |
|
|
|