|
Базовая конференция FidoNet носит имя Ru.Visual.Basic и доступна на news серверах с префиксом Fido7. Дата последнего обновления: Jun 10, 2000 © Автор ряда материалов и составитель: Александр Щербаков, sanqy@mtu-net.ru, sanqy@forecast.ru. Все материалы данного VBFAQ, по отдельности, могут свободно использоваться в оригинальном или видоизмененном виде как в коммерческих, так и некоммерческих целях. VBFAQ в том виде, как он есть, может использоваться только в некоммерческих целях. Коммерческое использование VBFAQ, допустимо только с письменного согласия составителя и авторов данного документа. Содержание
A. Справка по среде (IDE) и все, что с ней связано.
MSDN это не примочка для просмотра хелпа. Это и есть сам хелп. Поставляется на 3-х CD. Но желающие могут их утянуть с http://msdn.microsoft.com. ;)
Igor Kudryashov:
Artem Prohorov: Откpываешь свой файл setup.lst, находишь pаздел [Setup] и добавляешь ключик ForceUseDefDir = 1, после чего установить приложение в другой фолдер будет невозможно. Чтобы изменить пyть к пpиложению, меняй стpокy DefaultDir. Описание ключей я беpy из книги Visual Basic 6.0 Рyководство для пpофессионалов, сеpия Мастеp, Microsoft Press. Значит должны быть описанны и в MSDN. Создавать дефолтную группу нyжно пpи помощи секции [IconGroups] файла setup.lst таким вот обpазом:
Вернуться к содержанию.
Конечно! Вопервых VB позволяет Split окон модулей. Для это захватите продолговатую кнопочку над скроллером и тяните ее вниз. Окно будет разбито на 2 половинки, в каждой из которых можно работать с кодом. Чтобы восстановить "статус-кво", перетащите разделительную полоску на самый верх. Другим, не менее удобным способом, является использование bookmark. Нажмите правой мышиной кнопкой в любом месте панелей VB и выберите Edit. У Вас появится новая панель, на которой будут видны 4 синих флажка. Один из них позволяет ставить/убирать метки в тексте (букмарки), два других перемещаться между букмарками и четвертый флажок убирает все букмарки. Вернуться к содержанию. B. Начальные сведения по языку VisualBasic.
Ответ на этот вопpос и подобные емy - никак. Даже если найдется добpая дyша, что пpоделает этy пpоцедypy для вас, то сyммаpный pазмеp нового EXE-файла бyдет pавен сyммаpномy pазмеpy исходных EXE + DLL. Чyдес не бывает! Конечно, кто-то скажет, дескать в Cи это тpебование не выполняется. Это не так. Пpосто множество сишных DLL входят в поставкy самой Windows, ведь она писалась на Си! А если на минyткy пpедставить, что Windows создавалась бы на VB? Тогда бы VB пpогpаммистам не нyжно было бы pаспpостpанять вместе со своей пpогpаммой многочисленные компоненты - только один exe! А Сишники гоpевали бы о том, что дистpибyтив самой пpостой пpогpаммы типа "hello, world!" на Си тянет на многие сотни килобайт. Вообще, pазделение на компоненты (dll/ocx) благо, а не зло. Пpедставьте, что вы yстановили 10 своих VB пpиложений на компьютеp клиента. Если каждое пpиложение pазмеpом 100кб и использyет только MSVBVM50.DLL pазмеpом 1.3Mb, то все они займyт на винчестеpе (100кб x 10 + 1300кб) 2.3Mb. Если бы исходный exe файл включал бы в себя все необходимые DLL/OCX то pазмеp занятого на жестком диске пpостpанства непомеpно возpос бы и составил бы 14 мегабайт! (нетpyдно подсчитать, из pассчета 1 комплекта = 1.4мб (100кб + 1.3мб)). Вернуться к содержанию.
Как правильно реализовать стиль визарда? Это где кнопочки Далее и Назад? Я делаю несколько окон по числу шагов, но постоянно лезут глюки. Например, при перетаскивании верхнего окна, под ним оказываются другие...Вообще, гораздо безгеморройнее реализовать визарда на контролах, являющихся контейнерами. Например, фрейм или пикчебокс. Правда, использовать пикчебокс не советую, ибо он будет ловить фокусы, портя интерфейс. А у фрейма надо бордюр воткнуть в None, дабы он не мешался. Во время дизайна, растяните окно и разместите фреймы так, чтобы они все были видны. Когда интерфейс будет доделан, разместите фреймы один над другим. Теперь о коде. В нем нет ничего сложного. Но после N-ного визарда, я плюнул и решил написать классик, дабы по многу раз не набивать один и тот же набивший оскомину код. Этот классик и небольшой примерчик предлагаю Вам. Проект лежит в архиве WizardStyle и там же находится класс Frames.cls. Использование класса видно на примере и по небольшому описанию в самом классе. Я лишь хочу акцентировать Ваше внимание на ряде тонкостей. Используйте только массив контролов (фреймов, пикчебоксов или других контейнеров). Работать не с массивом (Frame1, Frame2, Frame3...) класс не может и, вообще-то, не должен. Метод HideFrames был введен сознательно. Дело в том, что во время дизайна Вы можете оставить самым верхним любой фрейм, а не только с индексом 0. Так как свойство Frame устанавливается в 0 после визуализации формы, то возможно некоторое мелькание фреймов. HideFrames позволяет избежать этого. Ивенты. Зачем нужны аж 3 ивента, спросите Вы? Опять же это потребность выкристаллизовалась на практике. Ивент BeforeLoad удобно использовать для проверки валидности введенных данных, и запрещения изменений фрейма, если данные некорректны. Кроме того этот ивент как нельзя кстати подходит для инициализации контролов и т.п., перед тем как страница содержащая эти контролы будет визуализирована. Ивент AfterLoad в основном нужен для длительных операций. Например, Вы создали визарда для проверки валидности Вашей базы данных. Если проверку проводить в ивенте BeforeLoad, то пользователь столкнется с тем, что после нажатия на кнопку Далее программа "замерзла" или "зависла". Наличие ивента AfterLoad позволяет избежать этого. Вы можете на странице разместить прогрессбар и в ивенте AfterLoad его менять синхронно с проверкой базы данных. И, наконец, ивент OverLoad. Когда Вы нажимаете кнопку Назад или Далее и свойство Frame устнавливает несуществующую страницу, то возникает этот ивент, который позволяет нормально завершить программу, или "закольцевать" ее, как, например, это сделано в WinZip, когда с последней страницы, посредством кнопки Повторить, Вы переходите на первую страницу визарда. Вернуться к содержанию.
Что такое модули? Вообще, существует 3 типа модуля: - модуль формы; - просто модуль; - модуль класса. С модулем формы обычно знакомятся делая первые шаги в программировании на VB. Упрощенно говоря, модуль формы это то окно в котором вы описываете реакцию формы на действия с ней. Нас же интересует простой модуль (в дальнейшем просто модуль). Такой модуль может содержать только код и добавляется в проект кнопкой, изображенной на рисунке или через меню Project|Add Module. Так зачем нам модули? Модули нужны в следующих случаях: 1. Если Вы хотите объявить глобальную переменную, т.е. переменную, видимую во всех уголках Вашего приложения, то без модуля не обойтись:
Мне кто-то возразит, дескать, а что мешает тоже самое сделать в модуле формы?
Никто не мешает. ;-) Но! Вопервых при обращении к Вашей переменной придется
указывать имя объекта (в данном случае Form1), а именно так:
Во-вторых, если вы порождаете копии формы:
То каждая копия будет иметь свою переменную: frmX(0).MyVar и frm(1).MyVar.
Более того, изменение одной переменной никак не скажется на другой.2. Довольно часто модули формы оказываются перегруженными кодом и продираться сквозь такие дебри весьма неудобно и непроизводительно. В этом случае, полезно, ряд процедур выносить в модули, оставляя в модулях формы только небольшой код, жестко привязанный к самой форме (скажем, реакция на ивенты и т.д.). 3. Декларации функций API или просто внешних функций, так же помещают в модули. Конечно, декларацию с префиксом Private можно включить и в модуль формы, но... Часто АПИшная функция используется в разных частях приложения. Так зачем же ее объявлять несколько раз, когда проще объявить 1 раз? А кроме того, автор несколько раз сталкивался с таким странным эффектом, когда функция API, задекларированная в модуле формы, либо вообще не вызывается, либо работает как-то не так. Так зачем лишние сложности, если есть обычные модули? 4. И самый убойный аргумент. ;) Очень часто большие проекты стартуют не с модуля формы, а с функции Main. Объявить такую функцию можно только в модуле. И только в этом случае она будет нормально работать:
Вернуться к содержанию.
Тем эта столь обширна и затрагивает так много областей программирования, что ей место не в кратеньком FAQ'е, а в обстоятельной книжке. Но я попробую совместить несовместимое, и надеюсь, гуру не будут в обиде, если я опущу частности и то, что мне показалось неважным. Что такое класс? Это совокупность методов, свойств и событий, которые образуют целостный объект. А теперь попроще. Объект - наручные часы. Методы предназначены для установки времени на часах, установки будильника и т.д. Свойства, в нашем случае, определяют цвет корпуса, вид индикатора и т.д. Звук будильника является событием и позволяет провести определенные действия (например, снять молоко с плиты) в заданное время. Чтобы получить доступ к свойствам, методам и событиям объекта (часов), необходимо создать указатель на него, или инстанс. Если класс называется Clock, то создание экземпляра класса (инстанса) будет выглядеть так:
При необходимости можно создать несколько экземпляров одного и того же класса,
и все эти экземпляры будут работать независимо друг от друга. Ну а теперь,
чтобы вызывать метод или обратится к свойству класса, пишем:
А теперь самое сложное: создание классов. Начнем с азов.1. Добавление модуля класса в проект. Добавить модуль класса (часто его называют классовым модулем) можно посредством меню Project|Add Class Module или же кнопки, показанной на рисунке. Далее, назовите Ваш новоиспеченный класс. Поскольку через данную статью красной нитью проходит пример с часами, то так и назовем первый классовый модуль: Clock. 2. Область видимости процедур, свойств, переменных: Private, Public. Очень часто, создавая переменные или процедуры приходится решать вопрос: можно ли будет их использовать вне модуля, или они необходимы только самому модулю. В первом случае такие процедуры или переменные объявляются с префиксом Public, а во втором случае с префиксом Private. Префикс Public является умолчательным и хотя его можно опускать, я рекомендую этого не делать. Добавьте в проект простой, не классовый, модуль и наберите в нем:
Создайте в том же модуле процедуру CheckVar и обратитесь из нее к этим
двум переменным:
Это удается без труда. А теперь, обратимся из модуля формы (он по умолчанию уже
входит в проект) к созданным переменным. Как видим, вторая переменная не
существует для всего мира ;) и доступна только в модуле, ее породившем.
Попробуйте самостоятельно создать публичную и приватную процедуры и обратится к
ним из модуля и из модуля формы.3. Методы. Методы это уже знакомые Вам процедуры (sub) и функции (function). Метод может иметь аргументы, а может не иметь их. Если метод построен на основе функции, то он способен возвращать значения. Создадим метод установки времени на наших часах и метод, возврщающий информацию о состоянии батарейки питания. Для этого в модуле класса напишем:
Создав инстанс класса (как было показано в начале статьи), обращаемся к
новоиспеченным методам:
4. Свойства.Условно говоря, свойство очень условно можно представить как пара состоящая из функции и процедуры с одним и тем же именем. При обращении к свойству вызывается функция, при изменении - процедура. Если отойти от условностей, то для создания свойств существует ключевое слово Properties с суффиксом Get для получения значения и с суффиксом Let или Set (для объектов) для установки значения. Вообще, свойство чем то похоже на объявленную публичную переменную. С тем лишь отличием, что изменение значения такой переменной нельзя отследить, как и нельзя отследить обращения к этой переменной. Свойства же позволяют это реализовать. И всетаки, зачем нужны свойства? Почему бы вместо них не обойтись знакомыми процедурами и функциями? Предположим, наш класс должен иметь возможность выдавать стоимость часов и позволять эту стоимость изменять. Реализовать это проще простого:
Тогда обращение к этой переменной извне выглядит так:
Поставим задачу. Пользователь не должен иметь возможности установить цену ниже
150 и выше 800 долларов. Переменная с этим справиться неспособна. Берем на
помощь процедуры и функции:
Можно так написать? Можно. Все будет работать, но возникает ощущение некоей
громоздкости, нерациональности:
И тут на помощь приходят свойства:
Обращение к свойству выглядит так:
Не правда, ли похоже на обращение к переменной?Последнее, что нужно знать о свойствах. Вы можете создавать свойство, состоящее только из Property Get или Property Let (Property Set). В первом случае свойство будет только для чтения, т.е. неподдающимся для изменения, а во втором случае вы сможете установить свойство, но не прочитать его. 5. События. События (Events, ивенты) позволяют строить асинхронные модели, когда объект формирует и выстреливает какое-либо сообщение. Например, Вы установили время срабатывания будильника для наших часов. В заданный час будильник сработает, но как объект об этом сообщит? Можно, конечно, завести флажок и взводить его, и при этом по таймеру извне класса постоянно проверять его. Но такой путь нерационален и ведет к лишним затратам. И тут на помощь приходят события. Итак, создадим новый ивент в нашем классе Clock:
Для того, чтобы иметь возможность получать ивенты, внесем некоторые изменения в
код создания экземпляра класса. Для этого воспользуемся новым ключевым словом
WithEvents:
Если теперь в окне модуля, где создавался инстанс, раскрыть левый комбобокс, то
в списке объектов окажется слово clk. Установив его, в списке ивентов правого
комбобокса найдем ивент Alarm:
Всякий раз, когда будет выстреливаться ивент Alarm, управление будет
передаваться на этот участок кода, в котором можно выводить окно или играть
подходящий wav файл.А теперь перейдем от теории к практике и поставим новую задачу. Предположим, Вы работаете в банке и Ваш работодатель заказал Вам написание управляющей программы для банкомата. Опустим все малозначащие детали и сформулируем требования к программе:
Создадим новый проект и назовем его CreditCard. Добавим к проекту класс CCard. Этот класс будет ведать работой с банком. Управлять классом будет форма, названная winCard. Подобное разделение на независмые блоки полезно тем, что изменяя интерфейс Вы не трогаете класс, ведающий обработкой данных. А в случае изменения способа обмена с банком можно легко заменить класс на другой, не трогая интерфейс, столь полюбившийся клиентам. ;) Может в крошечных программах это и не так важно, но в больших проектах несоблюдение этого простого правила способно неимоверно усложнить работу программисту. Ради небольших правок, он будет вынужден переписывать сотни строк кода. Поэтому, лучше с самого начала учиться писать переносимые программы, строить их из независимых друг от друга кубиков. Тогда изъятие или изменение одного кубика не приведет к развалу всего здания проекта. Для начала разберемся с классом. Он должен содержать метод Connect подключения к серверу банка и метод Disconnect отключения от сервера. Метод Connect должен возвращать True в случае успеха и False если соединение не прошло. Свойство Account возвращает сумму в банке, на счету клиента. Для изменения остатка на счету, служит уже другой метод Change. В случае успеха метод возвращает True и если транзакция пройти не может (со счета снимают больше, чем он содержит) - False. К интерфейсу нет особых требований. Он должен обеспечивать подключение и отключение клиента (2 кнопки), предоставлять клиенту информацию о состоянии его счета (поле Label) и позволять клиенту изменить сумму на счету (поле TextBox и кнопка). Вы можете изменить интерфейс как Вам заблагорассудится, но это не должно отразиться на работоспособности программы. А теперь, зная задачу, попробуйте самостоятельно ее выполнить. Для тех, кто не до конца понял объяснений данной статьи, работающий пример проекта находится в архиве: CreditCard. Попробуйте разобрать его, понять как он работает и устранить те глюки, которые я специально оставил. ;-) Вернуться к содержанию. C. Использование наиболее употребимых контролов VisualBasic.
Пример с описанием находится в архиве WinSock. Для работы проекта Ваш VB должен иметь компонент Microsoft WinSock Control. Загрузите проект WinSock.vbp из каталога WinSock. В проект входят две формы: клиент и сервер. Клиент соединяется с сервером используя протокол TCP/IP и отсылает ему число из верхнего текстбокса (сумма в USD). Сервер получает число, умножает его на число из своего текстбокса (курс валюты) и возвращает результат клиенту, который отображает его в нижнем текстбоксе (сумма в рублях). Код обильно комментирован, и надеюсь вопросов не вызовет. В качестве следующего шага, на одном компьютере загрузите проект Server.vbp из архива WinSock\Server, а на другом компьютере проект Client.vbp из каталога WinSock\Client. Если сеть настроена правильно, и вы верно указываете имя/адрес сервера, то пример заработает. Можно на разных компьютерах запускать и скомпайленные exe файлы, но в этом случае Вы не будете иметь возможности отследить в динамике работу примера. И о плохом. ;-) В примере опущен код, который отвечает за перехват ошибок, неизбежно возникающих при связи. Этот код Вы без труда напишете сами, используя ивент Error винсока. И второе. При пересылке значительных объемов информации, например файла на 100Кб, он будет разбиваться на части и приниматься винсоком кусочками. Поэтому, Вы должны проверять был ли получен весь файл или нужно продолжить его прием. Самый простой путь - перед пересылкой файла удаленному винсоку отсылать заголовочек, в котором указывать имя передаваемого файла, его размер, дату и т.д. Вернуться к содержанию. Функции Win32API.
Смотpите фyнкцию API SetWindowPos. Пpимеp использования данной фyнкции, для pазмещения окна OnTop пpедставлен в архиве TopMost. Вернуться к содержанию.
Смотpите фyнкцию API Shell_NotifyIcon. Поймите, чисто физически невозможно "засyнyть" пpогpаммy в тpей. Это тоже самое, как поместить ваш любимый меpседес-600 междy pамами оконного стекла! Гpамотно сфоpмyлиpованный вопpос звyчит так: "Как поместить ИКОHКУ в системный тpей (system tray)". Подробный пример находится в архиве TrayIcon. Там же лежит класс для работы с треем - TrayIcon.cls. Вернуться к содержанию.
Можно ручками, создав таблицу перевода. Сам так делал, сложностей нет. А можно воспользоваться готовыми АПИшными функциями OemToChar и CharToOem.
Peter Pan:
От себя лишь добавлю, что есть декларация для CharToOem выглялдит так:
Soleiman Mostamandy:
Вернуться к содержанию.
Для этого используются функции API ReleaseCapture и SendMessage. Пример на эту тему находится в архиве MoveWindow. Вернуться к содержанию.
Arkadiy Olovyannikov:
А можно использовать и SHGetFileInfo - она две иконки дает - большую и
маленькую.
Вернуться к содержанию.
Используя все тот же API. ;) Например, AllocConsole, ReadConsole и т.д. Пример находится в архиве Console. Вернуться к содержанию.
Лобовая атака с применением API функции SetMenuItemBitmaps не пройдет. Картинки в меню получаются иных цветов, нежели в исходной битмапе и это связано с особенностями реализации этой функции. Дабы избежать игры цвета, нужно с нуля, через АПИ создавать меню, что неудобно. Примеры, что были мне присланы, реализуют другой подход, который заключается в получении hDC (хендл контекста устройства) пункта меню и перерисовывании его на лету средствами АПИ. Этот путь позволяет использовать уже готовое меню, созданное в IDE, но имеет существенный недостаток - использование сабклассинга. В готовом EXE/DLL этот недостаток непринципиален, но на стадии отладки программы способен попортить немало крови падениями VB IDE. Дабы избежать этого, никогда не завершайте работу программы нажатием на кнопку End в IDE! Используйте кнопку [x] окна, в ивенте Form_[Query]Unload которого, находится код возвращающий указатель на старый обработчик. Примеры находятся в архивах BitmapMenu1 и BitmapMenu2. В обоих случаях реализуется примерно один и тот же механизм, но реализованный разными путями. Первый пример, несмотря на невзрачность, позволяет использовать иконки и битмапы любого размера, не только 16x16. Внешний вид второго примера более аккуратен, но без его переделки нельзя использовать битмапы, размер которых отличен от 16x16. Вернуться к содержанию.
Вопpос: почему после вывода окна меню из subj, пpи помощи PopupMenu, не могу никак сбpосить это окно без выбоpа элемента меню? Кто-нибудь с этим сталкивался?PRB: Menus for Notification Icons Don't Work Correctly Article ID: Q135788 SYMPTOMS When you display a context menu for a Notify Icon (see Shell_NotifyIcon), clicking anywhere besides the menu or the window that created the menu (if it is visible) doesn't cause the menu to disappear. When this behavior is corrected, the second time this menu is displayed, it displays and then immediately disappears. RESOLUTION To correct the first behavior, you need to make the current window the foreground window before calling TrackPopupMenu or TrackPopupMenuEx. The second problem is caused by a problem with TrackPopupMenu. It is necessary to force a task switch to the application that called TrackPopupMenu at some time in the near future. This can be accomplished by posting a benign message to the window or thread. The following code will take care of all of this:
От себя замечу, что класс TrayIcon в примере D2 лишен этого недостатка.
Вернуться к содержанию.
Arkadiy Olovyannikov: ИМХО, проще и красивее создавать регионы через Path. Hу что можно сделать через Create...Region? Эллипс? А вот как можно использовать Path:
Вернуться к содержанию.
Осуществить привязку программы проще всего к дате создания BIOS материнской платы. Адрес расположения даты в памяти: F000:FFF5. Чтобы считать дату из BIOS, воспользуйтесь нижеследующим кодом: Dmitry Sergunin:
Вернуться к содержанию.
Функция, которая реализует эту возможность - GetDesktopWindow. Полный код выглядит так. Это поместить в область деклараций модуля
Код, копирующий изображение экрана в окно. Размещается в форме. Не забудьте
свойство формы AutoRedraw установить в True.
Если необходимо изображение поместить в Picture, вместо Me.hDC укажите
Picture1.hDC.
Вернуться к содержанию.
Aleksandr Samsonov: The MultiMedia function provide several commands via the mciSendString API. Perhaps one of the most frequently requested is ejecting (and loading) a CD automatically from code. Using a single line call, this is easily achieved. Add the following code to a BAS module:
Открыть дверцу CD-Rom:
Закрыть дверцу CD-Rom:
Вернуться к содержанию.
Это делает функция SetSystemPowerState. Функция имеет 2 параметра, оба не задействованы в Windows 9X. В Win2000 первый параметр задает особый режим Hibernate, при котором материнская плата обесточивается, но на диммы, подается напряжение и их соедржимое рефрешится, что позволяет при включении мгновенно вернуться к прерванной работе. Материнская плата должна иметь поддержку этой возможности. Во всех предыдущих режимах hibernate, содержимое RAM записывалось на жесткий диск. Итак, декларацию прописываем в модуль:
А в нужный момент вызываем функцию:
Пробуждение осуществляется стандартными методами (мышь, клава, активность порта
и т.д.).
Вернуться к содержанию.
Использование внешних библиотек и дополнительных контролов.
Для выполнения этих функций нужно воспользоваться библиотекой DLPortIO.DLL, которая, в составе архива, находится здесь. Функции, реализованные в ней, работают под Win9X и WinNT. Архив содержит примерчик и необходимую DLL. А можно пример (без библиотеки) взять в архиве DLPortIO. Библиотеку нужно скопировать в системный каталог Windows. Обычно это C:\WINDOWS\SYSTEM. Вернуться к содержанию. Базы данных.
Alexander Trishin:
То есть Exclusive=True
и ReadOnly = True
|
helloworld.ru © 2001-2021 Все права защищены |
|
|