Часть 1. Основы Visual Basiс
На главную самоучителя
02.06.2005
Глава 20.
Объект Screen. Определение разрешения экрана.
Объект Clipboard. Работа с системным буфером обмена.
Скачать исходник примера "Clipboard"

В Visual Basic существуют объекты, не отображаемые на форме, но использование которых несложно и может принести некоторую пользу. В прошлых главах мы говорили об объектах Printer, Err и DataObject. Давайте поговорим еще о парочке.

Объект Screen.

По-сути, объект Screen представляет собой весь экран или иначе Десктоп (DeskTop). Как и другие объекты, объект Screen имеет определенные свойства. Так, например, почему-то считается, что для определения разрешения экрана надо использовать API-функции. Но это прекрасно можно сделать и внутренними возможностями VB. У объекта Screen есть свойства .Height и .Width, которые и возвращают высоту и ширину экрана в твипах. Эти самые твипы легко преобразовать в пиксели, если использовать два других свойства объекта Screen - .TwipsPerPixelX (которое возвращает количество твипов в пикселе по-горизонтали) и .TwipsPerPixelY (которое возвращает количество твипов в пикселе по-вертикали). Таким образом, чтобы определить разрешение экрана, мы пишем приблизительно следующий код:

Private Sub Command1_Click()
'Объявить переменные
Dim VisotaScr As Long 'для высоты
Dim ShirinaScr As Long 'для ширины
VisotaScr = Screen.Height / Screen.TwipsPerPixelX 'узнаем ширинуэкрана и преобразовываем ее в пиксели
ShirinaScr = Screen.Width / Screen.TwipsPerPixelY 'узнаем высоту экрана и преобразовываем ее в пиксели
Text1 = VisotaScr & " x " & ShirinaScr 'выводим результат в Text1
End Sub

Еще одно свойство .ActiveControl содержит ссылку на элемент управления (и его свойства), имеющий фокус. Смысл использования этого свойства следующий. Например, у тебя на формe три текстбокса. И ты хочешь активный текстбокс очистить. Вот в этом случае и можно использовать свойство .ActiveControl, например

Screen.ActiveControl.Text=""

т. е. очищается тот объект ( в нашем случае TextBox) , на котором в данный момент находится фокус. Это, конечно, несколько упрощено, поскольку, во-первых, необходимо проверить, а текстбокс ли это? Может у тебя на форме есть другие элементы, например, PictureBox. Во-вторых, реально это свойство можно использовать только в меню, так как меню не получает фокус и активным элементом остается выбранный объект. При использовании, например, свойства .ActiveControl в процедуре CommandButton, при нажатии на кнопку Command1 фокус перейдет с нужного нам элемента на командную кнопку и мы не получим желаемого результата. Ниже, в этой главе, мы на примере работы с объектом Clipboard будем использовать это свойство применительно к меню.

Аналогично свойству .ActiveControl и свойство и .ActiveForm, но содержит ссылку на активную форму. Тогда, чтобы добраться до какого-либо элемента можно применить, например, такой оператор:

Screen.ActiveForm.ActiveControl.Picture

Надо сказать, что объект Screen имеет еще свойства MouseIcon и MousePointer, которые позволяют менять вид курсора, но их использование совершенно аналогично этим свойствам для формы, которые мы анализировали в главе 5. Поэтому я не стану занимать этой дребеденью наше драгоценное время и предлагаю перейти к более нужному и интересному.

Свойства SelLength, SelStart, SelText.

Сейчас мы коротенько поговорим о довольно-таки нужных текстовых свойствах, тем более, что мы будем их использовать далее при работе с объектом Clipboard. Мы уже использовали свойство SelText в прошлой главе, но на этом не остановимся. Если мы выделим кусочек текста в Text, то мы можем получить (или установить) об этом выделенном фрагменте некоторую полезную информацию как раз с помощью этих свойств:

.SelLength — возвращает или устанавливает число выделенных символов. (синтаксис объект.SelLength [= число выбранных символов])
.SelStart — возвращает или устанавливает начало выделенного текста, а если текст не выбран, то указывает положение места вставки. (синтаксис объект.SelStart [= положение начала вставки])
.SelText — возвращает или устанавливает строку, в которой содержится выделенный текст. Если никаких символов не выбрано, то представляет строку нулевой длины ("").(синтаксис объект.SelText [= текст выделения]).

Наиболее часто эти свойства как раз и используются с объектом Clipboard для операций вставки и вырезания. Причем установка .SelLenght меньше нуля приводит к ошибке выполнения. Изменение .SelStart устанавливает .SelLength в значение ноль. Если установить .SelLength больше, чем длина текста, то оно автоматически станет равной длине текста. Установка .SelText в новое значение устанавливает .SelLength в ноль.
Ну вот, теперь можно двигать дальше.

Объект Clipboard.

С системным буфером обмена данных Clipboard мы сталкиваемся постоянно. Именно в него помещаются данные приложения при использовании операций Cut (Вырезать) и Copy (Копировать) и из него берутся при операции Paste (Вставить) в меню Edit, которое есть в практически любой виндусовой программе. Буфер обмена представляет своего рода промежуточное место для хранения данных, которое позволяет, не устанавливая связь между приложениями, тем не менее, переносить данные одного типа из одной программы в другую.
Буфер обмена для всего Windows один. Забрав в буфер данные одного приложения, а затем другого, мы обнаружим, что в буфере хранятся лишь данные последней операции Cut или Copy. Это вызвано тем, что в большинстве случаев, чтобы в буфере не хранилось данных разных приложений, перед загрузкой данных в буфер программа-донор обычно производит его очистку. Посмотреть содержимое буфера можно с помощью утилиты CLIPBRD.EXE, которая обычно имеется в директории C:\Windows\System32 или аналогичной (в зависимости от Windows, установленной на твоем компьютере). В буфер обмена можно забрать и текст и картинку и черте что, потому что он поддерживает разные форматы данных.
Из VB доступ к буферу организуется с помощью объекта Clipboard. Методы объекта практически те же, что и разобранные нами в главе 19 с объектом DataObject, однако повторенье - мать ученья (банальность). Они представлены в нижеследующей таблице:

Методы объекта Clipboard
Clipboard.SetText data, format Помещает текстовые данные в буфер обмена,
где data - строка данных, помещаемая в Clipboard
Значение format для текстовых данных может принимать следующие значения:

vbCFLink (&HBF00) - Диалоговая информация DDE
vbCFRTF (&HBF01) - Текст в формате RTF(Rich Text Format)
vbCFText (1) - Текст (Установка по умолчанию)
Clipboard.GetText (format) Возвращает текстовые данные из буфера обмена. Необязательный. Если ожидаемого формата в буфере нет, то возвращается пустая строка.
Clipboard.SetData data, format Помещает графические данные в буфер обмена,
где data - графическое изображение, помещаемое в Clipboard. Устанавливается функцией LoadPicture либо свойствами Picture.
Значение format для графических данных может принимать следующие значения:

vbCFBitmap (2) - Растр (.bmp-файлы)
vbCFMetafile (3) - Метафайл (.wmf-файлы)
vbCFDIB (8) - Независимые от устройств растровые рисунки (DIB)
vbCFPalette (9) - Цветовая палитра
vbCFEMetafile (14) - Расширенный метафайл (.emf-файлы)
vbCFFiles (15) - Список имен файлов (Microsoft Windows Explorer)
Clipboard.GetData (format) Возвращает графические данные из буфера обмена. Если значение format опущено, то подбирается подходящий формат. Если графический формат не соответствует ожидаемому, то ничего не возвращается.
Clipboard.GetFormat (format) Возвращает логические True или False, в зависимости от содержащихся в буфере данных. Для проверки более чем одного метод вызывается повторно.

Значение format может принимать следующие значения:

vbCFLink (&HBF00) - Диалоговая информация DDE
vbCFText (1) - Текст
vbCFBitmap (2) - Растр (.bmp-файлы)
vbCFMetafile (3) - Метафайл (.wmf-файлы)
vbCFDIB (8) - Независимые от устройств растровые рисунки (DIB)
vbCFPalette (9) - Цветовая палитра

vbCFEMetafile (14) - Расширенный метафайл (.emf-файлы)
vbCFFiles (15) - Список имен файлов (Microsoft Windows Explorer)

Clipboard.Clear Очищает содержание системного буфера обмена.

Использовать эти методы очень просто. Для примера создадим новый exe-проект и положим на него два TextBox'а и два PictureBox'а. В качестве управления нашими процессами с помощью Редактора меню создадим простое меню Edit. Подробно о создании меню написано в Главе 9.
Имя нашего меню будет mnuEdit, а строками
mnuCut - Вырезать
mnuCopy - Копировать
mnuPaste - Вставить
mnuDelate - Удалить
Вообще-то у TextBox'а есть свое контекстное меню, но мы сделаем свое общее.

Ну сперва в процедуре Form_Load загрузим в Text1 и Picture1 данные, чтобы нам было с чем работать. В примере я использовал маленькую картинку P00027.jpg. (Кстати поставь свойства TextBox'ов Multiline=True)

Option Explicit 'хоть у нас и не будет ни одной переменной, но дело принципа
Private Sub Form_Load()
Text1 = "Проще Visual Basic ничего нету"
Picture1 = LoadPicture(App.Path & "\P00027.jpg")
End Sub

Начнем с процедуры для первого пункта подменю "Вырезать" - mnuCut, которая должна копировать данные в буфер и затем очищать объект (Text или Picture):

Private Sub mnuCut_Click()

Сперва нам надо очистить буфер, чтобы в нем не осталась другая информация. Используя метод .Clear это предельно просто.

Clipboard.Clear

Далее мы будем использовать свойство .ActiveControl объекта Screen. С его помощью мы легко затащим в буфер содержимое объекта, которое в настоящий момент активно, т.е. по которой мы щелкнули мышью. Но сперва нам надо определить, а какой это объект, ведь для текста используется метод .SetText, а для графики - .SetData. Здесь мы снова, как и в Главе 18 используем ключевое слово TypeOf, которое поможет определить тип элемента управления, а значит и тип данных.

'итак, если это текст
If TypeOf Screen.ActiveControl Is TextBox Then
'забираем выделенный текст в буфер
Clipboard.SetText Screen.ActiveControl.SelText
'а затем удаляем этот выделенный текст из TextBox'а
Screen.ActiveControl.SelText = ""
'а теперь пишем ветвь, если это картинка
ElseIf TypeOf Screen.ActiveControl Is PictureBox Then
'забираем картинку из активного элемента в буфер
Clipboard.SetData Screen.ActiveControl.Picture
'и удаляем картинку
Screen.ActiveControl.Picture = LoadPicture()
End If
End Sub

Готово, наши данные в буфере обмена. Если у тебя открыт CLIPBRD.EXE, то ты можешь видеть, что творится в буфере. Теперь напишем процедуру для копирования mnuCopy. Единственное, чем она отличается от вырезания, так это тем, что мы не очищаем Text или Picture от копируемых данных.

Private Sub mnuCopy_Click()
'Очищаем буфер
Clipboard.Clear
'проверяем тип данных
'если если это текст
If TypeOf Screen.ActiveControl Is TextBox Then
'забор текста в буфер
Clipboard.SetText Screen.ActiveControl.SelText
'если это картинка
ElseIf TypeOf Screen.ActiveControl Is PictureBox Then
'забор картинки в буфер
Clipboard.SetData Screen.ActiveControl.Picture
End If
End Sub

Теперь нам хорошо-бы из буфера вставить данные в элемент управления. Для этого пишем процедуру Вставить - mnuPaste.

Private Sub mnuPaste_Click()
'Ну сперва, конечно, проверяем тип, куда мы хотим запихнуть содержимое буфера и если это текст
If TypeOf Screen.ActiveControl Is TextBox Then
'но все равно сразу не пихаем. А вдруг даные были забраны из PictureBox, поэтому мы еще и проверяем
'с помощью метода GetFormat, а текстовой ли тип в буфере
If Clipboard.GetFormat(vbCFText) Then
'вот если да, то тогда уж вставляем без сомнения
Screen.ActiveControl.SelText = Clipboard.GetText
End If
'а теперь проверка для графических данных
ElseIf TypeOf Screen.ActiveControl Is PictureBox Then
'и здесь мы проверяем тип данных буфера
If Clipboard.GetFormat(vbCFDIB) Then
'и если совпадает, то вставляем
Screen.ActiveControl.Picture = Clipboard.GetData
End If
End If
End Sub

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

Private Sub mnuDelate_Click()
'проверяем тип данных
'если это текст

If TypeOf Screen.ActiveControl Is TextBox Then
'удаление выделенного текста
Screen.ActiveControl.SelText = ""
ElseIf TypeOf Screen.ActiveControl Is PictureBox Then
'удаление картинки
Screen.ActiveControl.Picture = LoadPicture()
End If
End Sub

Казалось бы, вот оно счастье, рядом, но фиг, дело не закончено. Если ты обратил внимание на фирменные программы, то не всегда все строки меню редактирования доступны юзеру. Например, если нет выделения в тексте, то и нечего копировать или вырезать. Или наоборот, в буфере нет данных? Поэтому в определенные моменты доступ к определенным строкам меню надо перекрыть! Для решения этой проблемы надо написать небольшую, но ответственную процедуру. И используем мы для этого самый верхний, казалось бы совершенно ненужный пункт меню mnuEdit. Именно по клику юзера по этой строчке нам будет очень удобно проверять, что можно делать из наших процедур, а что нельзя.

Private Sub mnuEdit_Click()

Сначала обязательно проверяем, соответствует ли тип данных элемента, на котором находится фокус.

If TypeOf Screen.ActiveControl Is TextBox Then

В случае, если из текста ничего не выделено, мы должны сделать недоступными строки "Вырезать", "Копировать" и "Удалить". Для этого надо ее свойству .Enabled присвоить значение False. Если ничего не выделено, значит длина выделения (свойство .SelLength) равна нулю. Это можно было бы записать приблизительно так:

  If Screen.ActiveControl.SelLength=0 Then mnuCut.Enabled = False

Однако, для краткости записи мы можем напрямую присвоить свойству .Enabled значение длины выделения .SelLength, исходя из того, что значение ноль всегда соответствует для логических типов False, а любое положительное - True. В итоге то мы получаем более короткую, но по смыслу абсолютно такую же запись. Кроме того, при этом, нам не надо каждый раз в начале процедуры восстанавливать доступность строк, так как длина строки больше нуля сама переведет .Enabled в состояние True.

mnuCut.Enabled = Screen.ActiveControl.SelLength

аналогично две другие строки

mnuCopy.Enabled = Screen.ActiveControl.SelLength
mnuDelate.Enabled = Screen.ActiveControl.SelLength


Далее мы должны запретить Вставить, если формат данных в буфере не соответствует требуемому. Здесь даже еще проще. Метод .GetFormat возвращает True, если формат соответствет проверяемому и False - если нет. Именно эти значения мы напрямую и присваиваем для свойства .Enabled строки mnuPaste.

mnuPaste.Enabled = Clipboard.GetFormat(vbCFText)


Абсолютно также мы поступаем с веткой для графических данных


ElseIf TypeOf Screen.ActiveControl Is PictureBox Then
mnuCut.Enabled = Screen.ActiveControl.Picture
mnuCopy.Enabled = Screen.ActiveControl.Picture
mnuDelate.Enabled = Screen.ActiveControl.Picture
mnuPaste.Enabled = Clipboard.GetFormat(vbCFDIB)
End If
End Sub


Ну вот мы и сделали это. Исходник примера можно скачать вверху страницы.


Copyright © 2005 4us

 

Сайт создан в системе uCoz