Visual Basic, .NET, ASP, VBScript
 

   
 
Описание для автора не найдено
 
     
   
 
Об авторе. Программист, сотрудник Центра Высоких Технологий (http://www.htc-cs.com/)

Меню "Инструменты" (Tools) делают для того, чтобы из нашей программы было легко вызвать какие-то другие утилиты, предназначенные для решения задач того же круга. Удобно, если это меню будет настраиваемым (customizeable). Попытаюсь рассказать про один из вариантов реализации такого меню.

Задачи, которые мы должны решить:

  • Вызов программы с заданными аргументами
  • Хранение набора инструментов в памяти
  • Составление меню Tools
  • Команда Tools|Customize Tools
  • Сохранение набора инструментов
  • Это действительно отдельные задачи - в том смысле, что они слабо зависят друг от друга. Ниже я покажу как я решал эти задачи в своей программе.

    Вызов программы с заданными аргументами

    Наиболее общий способ запуска программы под Win32 - это API-функция CreateProcess. Но нам нет нужды опускаться на столь низкий уровень. Можно было бы воспользоваться WinExec - это тоже вызов WinAPI, но с гораздо меньшим числом аргументов. Для наших нужд вполне достаточно VB-функции Shell - по сути, обертки над WinExec.

    Приведу пример процедуры, запускающей программу с заданными аргументами:

    
    Sub RunProgram(ByVal sPath As String, ByVal sArguments As String)
      If sPath = "" Then
        MsgBox "Executable path is empty.", vbExclamation
        Exit Sub
      End If
    
      If sArguments <> "" Then sPath = sPath & " " & sArguments
    
      Dim okFailed As Boolean, sDesc As String
      On Error Resume Next
      Shell sPath, vbNormalFocus
      okFailed = (Err <> 0)
      If okFailed Then sDesc = Err.Description
      On Error GoTo 0
      Err.Clear
    
      If okFailed Then _
        MsgBox "Cannot run the program (""" & sDesc & """).",_
          vbExclamation
    End Sub
    

    Хранение набора инструментов в памяти

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

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

    
    Public Type TToolDesc
      Name As String
      Path As String
      Arguments As String
    End Type
    
    Public Tools() As TToolDesc
    Public ToolsCount As Integer
    
    В такой реализации добавление нового элемента выглядит так:
    
      ToolsCount = ToolsCount + 1
      ReDim Preserve Tools(1 To ToolsCount)
      Tools(ToolsCount).Name = sName
      Tools(ToolsCount).Path = sPath
      Tools(ToolsCount).Arguments = sArgs
    
    Удаление элемента с номером iDeleted:
    
      Dim i As Integer
      For i = iDeleted To ToolsCount - 1
        Tools(i) = Tools(i + 1)
      Next i
      ToolsCount = ToolsCount - 1
      If ToolsCount > 0 Then _
        ReDim Preserve Tools(1 To ToolsCount)
    
    Примечание. Использование коллекции в данном случае невозможно, т.к. поместить составной тип в коллекцию не получится. Вместо составного типа можно сделать отдельный класс, но добавлять в проект новый класс только для объединения трех строк в структуру - это показалось мне излишним. Вместо переменной ToolsCount можно было бы использовать функции получения границ массива (LBound, UBound), но они приводят к ошибке в случае если массив пуст.

    Составление меню Tools

    Прежде всего - как должно выглядеть меню Tools? Мне кажется, примерно так. Сначала идут инструменты, причем каждый пункт называется так как это задано пользователем. Потом - разделитель (separator), затем - неизменяемые пункты, например - Options или Customize Tools.

    Нам нужен код, который будет заполнять меню Tools именами инструментов из массива Tools. Этот код нужно вызывать в двух местах - при старте программы и после закрытия диалога Tools Customize.

    Опять же, можно найти несколько вариантов реализации. Для себя я решил использовать т.н. control array. Признаком того, что какой либо элемент формы (control) входит в control array является непустое свойство Index. Преимущество использования control array для нас в том, что в него легко добавлять новые элементы (в нашем случае - пункты меню) оператором Load. Меню в моей программе выглядит так:

    
      Name                Index  Caption
      cmdToolsCmd         0      ""
      cmdToolsSep1               "-"
      cmdToolsCustomize          "Customize Tools..."
      cmdCustomizeToolbar        "Customize Toolbar..."
      cmdToolsSep2               "-"
      cmdOptions                 "&Options"
    
    Процедура заполнения меню выглядит так:
    
    Sub FillToolsMenu()
     'Remove all menu items
      Dim nCount As Integer
      nCount = 0
      On Error GoTo EndRemove
       While True
         nCount = nCount + 1
         Unload cmdToolsCmd(nCount)
       Wend
    EndRemove:
      On Error GoTo 0
    
      cmdToolsCmd(0).Visible = (ToolsCount > 0)
      cmdToolsSep1.Visible = (ToolsCount > 0)
    
      Dim i As Integer
      For i = 1 To ToolsCount
        If i > 1 Then Load cmdToolsCmd(i - 1)
        cmdToolsCmd(i - 1).Caption = Tools(i).name
      Next i
    End Sub
    
    Примечание. При удалении элементов control array я пользуюсь тем, что при удалении единственного элемента массива возникает ошибка: в control array должен быть хотя бы один элемент. Если массив инструментов пуст - скрываем как этот единственный элемент, так и следующий за ним разделитель.

    Команда Tools|Customize Tools

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

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

    Сохранение набора инструментов

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

    Параметры для своих программ я сохраняю в реестре. Поэтому мой код для сохранения инструментов выглядит так:

    
      sRegKey = AppRegistryKey & "Tools"
      RegistryDelete HKEY_CURRENT_USER, sRegKey
      Dim i As Integer, sRegTool As String
      For i = 1 To ToolsCount
        sRegTool = sRegKey & "\" & CStr(i)
        RegistrySet HKEY_CURRENT_USER, sRegTool
        RegistrySet HKEY_CURRENT_USER, sRegTool, "Name",_
            REG_SZ, Tools(i).name
        RegistrySet HKEY_CURRENT_USER, sRegTool, "Path",_
            REG_SZ, Tools(i).Path
        RegistrySet HKEY_CURRENT_USER, sRegTool, "Arguments", _
            REG_SZ, Tools(i).Arguments
      Next i
    
    Соответственно, загрузка набора инструментов в память выглядит так:
    
      sRegKey = AppRegistryKey & "Tools"
      ToolsCount = 0
      Dim Keys As Variant, sRegTool As String, i As Integer
      RegistryKeys HKEY_CURRENT_USER, sRegKey, Keys
      If IsArray(Keys) Then
        Debug.Assert (LBound(Keys) = 0)  'Zero-based array is returned
        ToolsCount = UBound(Keys) + 1
        ReDim Tools(1 To ToolsCount)
        For i = 0 To UBound(Keys)
          sRegTool = sRegKey & "\" & Keys(i)
          RegistryGet HKEY_CURRENT_USER, sRegTool, "Name",_
              REG_SZ, Tools(i + 1).name
          RegistryGet HKEY_CURRENT_USER, sRegTool, "Path",_
              REG_SZ, Tools(i + 1).Path
          RegistryGet HKEY_CURRENT_USER, sRegTool, "Arguments", _
              REG_SZ, Tools(i + 1).Arguments
        Next i
      End If
    
    Примечание. Стандартные средства VB для работы с реестром слишком примитивны. С другой стороны, использовать напрямую API-функции неудобно из-за большого объема дополнительной работы. Поэтому мной были написаны обертки (wrapper) над API-вызовами. Думаю, их применение понятно из контекста.
     
         

       
       
         
      VBNet рекомендует