Загрузки рисунка в Microsoft Visio и показать окно пользователю


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

Цель кодекса

Загрузки рисунка в Microsoft Visio с помощью VBA и показать окно пользователю.

Шаги

  • Прикрепить к установленным Visio экземпляра (GetObject). Или, если таковой отсутствует, запуск новой версии Visio экземпляра (CreateObject).

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

  • Загрузить файл Визио

  • Предотвратить экран для Visio обновления, чтобы избежать мерцания экрана, вызванного моим следующим кодом

  • Синхронизация некоторых данных. Все будет сделано с рисунка, не важно здесь

  • Определить нужное окно программы. Загрузка файла Visio может вызвать несколько окон, что чертеж открывается сразу, но есть один особый, который я хочу показать

  • Окно активировать нужные в Visio

  • Максимально нужное окно программы. Прикрепленный экземпляра Visio может быть в не-полноэкранном режиме, но я хочу развернуто

  • Возобновить экрана в Visio обновления

Вопросы

  1. Как бы вы назвали 'главным' процедура, в моем примере OpenVisioDrawing? Как видите, там также является вспомогательной процедурой имени LoadVisioDrawing, который конфликтует немного с OpenVisioDrawing. Но имен OpenVisioDrawing более сложным, как AssureVisioInstanceLoadDrawingAndShowItToTheUser не очень приятно.

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

  2. Или вы могли бы решить эту проблему именования, рефакторинг мой подход?

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

Модуль TestVisioInterface

Option Compare Database
Option Explicit

Sub Test()
    With New VisioInterface
        .OpenVisioDrawing "C:\myVisioFile.vsd", "Custom drawing title"
    End With
End Sub

Класс VisioInterface

Option Compare Database
Option Explicit

Private Const VISIO_CLASS_ID As String = "Visio.Application"

Public Sub OpenVisioDrawing(ByVal filename As String, someData As String)
    Dim app As Object
    Set app = GetVisioInstance()

    ActivateVisioInstance app

    Dim drawing As Object
    Set drawing = LoadVisioDrawing(app, filename)

    VisioScreenUpdating app, False

    SyncVisioDrawing drawing, someData

    Dim window As Object
    Set window = DetermineDesiredVisioWindow(app, drawing)

    ActivateVisioWindow window

    MaximizeVisioWindow window

    VisioScreenUpdating app, True
End Sub

Private Function GetVisioInstance() As Object
    If VisioInstanceExist() Then
        Set GetVisioInstance = AttachVisioInstance()
    Else
        Set GetVisioInstance = StartVisioInstance()
    End If
End Function

Private Function VisioInstanceExist() As Boolean
    On Error Resume Next
    Dim visioApp As Object
    Set visioApp = GetObject(, VISIO_CLASS_ID)
    VisioInstanceExist = Not visioApp Is Nothing
End Function

Private Function AttachVisioInstance() As Object
    Set AttachVisioInstance = GetObject(, VISIO_CLASS_ID)
End Function

Private Function StartVisioInstance() As Object
    Set StartVisioInstance = CreateObject(VISIO_CLASS_ID)
End Function

Private Sub ActivateVisioInstance(ByRef app As Object)
    AppActivate app.window.Caption
End Sub

Private Function LoadVisioDrawing(ByRef app As Object, ByVal filename As String) As Object
    Const visOpenRW = &H20
    Set LoadVisioDrawing = app.Documents.OpenEx(filename, visOpenRW)
End Function

Private Sub SyncVisioDrawing(ByRef drawing As Object, ByVal someData As String)
    drawing.Title = someData
End Sub

Private Function DetermineDesiredVisioWindow(ByRef app As Object, ByRef drawing As Object) As Object
    Dim window As Object
    For Each window In app.Windows
        If window.Document Is drawing Then
            Set DetermineDesiredVisioWindow = window
            If window.Caption Like "*:2 *" Then
                Set DetermineDesiredVisioWindow = window
                Exit Function
            End If
        End If
    Next
End Function

Private Sub ActivateVisioWindow(ByRef window As Object)
    window.Activate
End Sub

Private Sub MaximizeVisioWindow(ByRef window As Object)
    Const visWSMaximized = &H40000000
    window.WindowState = visWSMaximized
End Sub

Private Sub VisioScreenUpdating(ByRef app As Object, ByVal allow As Boolean)
    app.ScreenUpdating = allow
End Sub


196
1
задан 18 февраля 2018 в 10:02 Источник Поделиться
Комментарии
2 ответа

Именования

Хотя VisioInterface делает интерфейс в Visio, это не интерфейс. Это вы добавить больше функциональности к классу, я бы назвал его VisioDocument

Я согласен с @Raystafarian, когда дело доходит до именования процедур. Все в этот класс относится к Visio. Добавление Visio для названия всех процедур, это просто беспорядок.

Я согласен с @Raystafarian, когда дело доходит до именования visWSMaximized и visOpenRW. Эти значения могут иметь постоянные значения, но они на самом деле перечислений. Рассмотрите возможность добавления перечисления руководителя класса. Сделать их открытыми, если вы собираетесь использовать их в параметр общественного порядка, в противном случае сделать их частными.

' https://msdn.microsoft.com/en-us/library/aa342166(v=office.12).aspx
Public Enum VisWindowStates
visWSActive = &H4000000
visWSMaximized = &H40000000
visWSMinimized = &H20000000
End Enum

Поток Программа

Класс является несколько неуклюжим. Он должен некоторым полям , чтобы привести его вместе. Документ и, возможно, даже окна поле будет делать все процедуры гель лучше. Например, вы обе загрузить и открыть процедуру, но активировать использует AppActivate для активации окна , а не непосредственно ссылающихся на него.

Нет четкой отправной точки для использования класса. Рассмотрим написание какой-то инициировать или инициализации процедуры. Я бы заменил LoadVisioDrawing с Init(Path as String).

Вы должны рассмотреть возможность использования GetObject(PATH) установить прямую ссылку на файл, если он уже открыт. Например: Set Document = GetObject("C:\myVisioFile.vsd") либо установить ссылку на myVisioFile файл или выдаст ошибку.

Не изобретайте колесо - модель кода уже существующих моделей

Я пытаюсь модель мои занятия после применения, объекты и процедуры, которые они будут взаимодействовать с или передразнивать. Рассмотреть свойство screenupdating, в Excel и Visio свойство screenupdating - это свойство, которое займет перечисление. Когда я должен был написать свойство screenupdating процедуру в модуль класса, угадай, что я пишу это как свойство, которое принимает перечисление.

Разве Визио загрузить документ или открывает документ? Он открывает один конечно. Каждый, кто знаком с любой из моделей приложений Microsoft знает об этом. Если они видят OpenDocument они сразу понимают, что процедура, которую должен делать. С другой стороны, когда я видел LoadVisioDrawing, я должен был понять смысл как "нагрузка" и "рисунок". Потому что я никогда не использовал Visio и нет доступа к нему, мне пришлось исследовать ВСД , чтобы определить, что это был документ Visio формат. Это может быть выгодно использовать более общий документ имя.

Моделирование код после существующих моделей сделает ваш код более понятным для других и легче ассимилироваться, если у вас есть, чтобы изменить его вниз по дороге. Знание дает понимание и обучение гораздо проще задачи.

VisioDocument - VisioInterface Рефакторингу

Далее следует набросок о том, как я хотел бы написать класс. Я не мог проверить его, потому что я не установлен Visio, но я уверен, что это не будет трудно получить его и работает.

Option Explicit
Public Enum VisWindowStates
visWSActive = &H4000000
visWSMaximized = &H40000000
visWSMinimized = &H20000000
End Enum

Public mVisioApp As Object
Public mDocument As Object
Public mWindow As Object
Private mScreenUpdating As Boolean
Private mWindowState As XlWindowState
Private mPath As String

Public Function Init(Optional PATH As String) As Boolean
Const VISIO_CLASS_ID As String = "Visio.Application"
Dim doc As Object
mPath = PATH
If Len(mPath) <> 0 Then
If Len(Dir(mPath)) = 0 Then
MsgBox "File Not Found"
Exit Function
End If
End If

On Error Resume Next
Set mDocument = GetObject(mPath)
On Error GoTo 0

If mDocument Is Nothing Then
Set mVisioApp = CreateObject(VISIO_CLASS_ID)
If Len(mPath) <> 0 Then
Set mDocument = mVisioApp.mDocuments.Open(mPath)
Else
Set mDocument = mVisioApp.mDocuments.Add
End If
Else
Set mVisioApp = mDocument.Application
End If
Init = True
End Function

Public Property Get ScreenUpdating() As Boolean
ScreenUpdating = mScreenUpdating
End Property

Public Property Let ScreenUpdating(ByVal ScreenUpdating As Boolean)
mScreenUpdating = ScreenUpdating
End Property

Public Property Get WindowState() As Variant
WindowState = mWindow.WindowState
End Property

Public Property Let WindowState(ByVal WindowState As VisWindowStates)
mWindow.WindowState = WindowState
End Property

Public Sub setWindow()
Set mWindow = mVisioApp.Windows(mDocument.Title)
End Sub

Журнал Изменений


  • VisWindowStates добавлена поддержка рефакторинг WindowState собственность

  • Инит изменены, чтобы добавить новый документ, когда нет пути, указанному

2
ответ дан 21 февраля 2018 в 08:02 Источник Поделиться

Некоторые простые наблюдения именования


Private Function VisioInstanceExist() As Boolean
On Error Resume Next
Dim visioApp As Object
Set visioApp = GetObject(, VISIO_CLASS_ID)
VisioInstanceExist = Not visioApp Is Nothing
End Function

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

Кроме того, я не вижу способа, что экземпляр программы может существовать на тот момент, это первое, что вы делаете, и вы ничего не определено.

Я бы ООНрефакторинг это

Private Function GetVisioInstance() As Object
Dim visioApp As Object
On Error Resume Next
Set visioApp = GetObject(, VISIO_CLASS_ID)
If visioApp Is Nothing Then
GetVisioInstance = StartVisioInstance
Else
Set GetVisioInstance = visioApp()
End If
End Function


См. обновление внизу.

Это действительно не слишком плохо функционировать, и это исключает 3 других. Ваш звонок на проверку ошибок.

Давайте рассмотрим, какие процедуры у нас осталось (не учитывать, что это в Excel, это не должно волновать)
создан в RubberDuck-ВБА

enter image description here

Подожди! Нет .Initialize() функция. Может быть, вы можете сделать все творения и получать во время инициализации?

В противном случае -



  • АктивацииДля VisioЭкземпляр

  • АктивироватьVisio ВОкне

  • DetermineDesiredVisio ВОкне

  • ЗагрузитьVisio ДляРисования

  • УвеличитьVisio ВОкне

  • ОткрытьVisio ДляРисования

  • СинхронизацияВ VisioЧертеж

  • ВизиоСвойство Screenupdating


Теперь, я признаю, что я не в Visio эксперт, но разве это не выполняется в Visio? Или, если это не так, это Class есть в Visio в его названии.

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


  • ActivateInstance

  • ActivateWindow

  • DetermineDesiredWindow

  • LoadDrawing

  • MaximizeWindow

  • OpenDrawing

  • SyncDrawing

  • Свойство screenupdating

Хм, это лучше. Мне не нравится, что ScreenUpdating функция есть уже Application.ScreenUpdating. Кажется, может это просто логическое свойство , чтобы Let и Get? Я только видим, что изменения свойств и снова.


Private Sub ActivateVisioInstance(ByRef app As Object)
AppActivate app.window.Caption
End Sub

Здесь вы используете AppActivate заявление, но вы завернули его в ActivateInstance метод. И вы используете заголовок , который является собственностью Window (для Visio объект, а не переменная). Но я не вижу, где вы используете это свойство, я не знаю, что за надпись будет. Кажется, что ваш ActivateInstance процедура является менее эффективным и/или яснее, чем если бы вы просто использовали AppActivate заявление в первую очередь. Если вы собираетесь, чтобы обернуть его во что-нибудь, использовать это! Вы даже не взяв подпись аргумент!


SyncVisioDrawing drawing, someData
Private Sub SyncVisioDrawing(ByRef drawing As Object, ByVal someData As String)
drawing.Title = someData
End Sub

Вы передаете объект в порядок, чтобы задать его заголовок, который вы также прохождения процедуры? так это SetDrawingTitle? С помощью этой процедуры не требуется. Если это так, назовите его лучше, взять другой аргумент, может превратить его в функцию, чтобы получить звание, а еще лучше - сделать это свойство класса.

Одна вещь, вы спрашивали о OpenVisioDrawing путают с LoadVisioDrawing. Да, это не великий именования, ты прав. Что OpenVisioDrawing делаешь?


  1. Проверка и создание экземпляра программы

  2. Загрузка чертежа в Visio

  3. Фиксируя взгляд Visio на то, что вам нужно

Это много вещей, и много из тех вещей, которые берутся из Другие уже процедур (что здорово!). Я бы сказал, что саб будет управлять всеми процедурами Visio или быть интерфейс в Visio (это имя класса, верно?).


Правил Именования Переменных


Dim app As Object
Dim drawing As Object
Dim window As Object
Dim visioApp As Object
Const VISIO_CLASS_ID As String = "Visio.Application"
Const visOpenRW = &H20
Const visWSMaximized = &H40000000

Ваша первая константа UPPER_SNAKEY_CASE а остальные два-нет. Они не дают видах , поэтому они являются вариантами. Какие они должны быть? Струны я должен взять на себя. Так что делать из них ниточки.

Кроме того, каковы эти ценности? &H20 и &H40000000 - шестигранный нотации? Чего? Символы ASCII? Эти имена констант должны по крайней мере сказать мне, что они должны быть! В противном случае


Const visOpenRW = &H20
Set LoadVisioDrawing = app.Documents.OpenEx(filename, visOpenRW)

Я понятия не имею, что делать. Я не знаю навскидку, что .OpenEx параметры (потому что я не эксперт в Visio). Давайте выясним.

Что? Эти флаги и целое число? И visOpenRW уже является постоянным для нее. Ладно, теперь гораздо больше, что имеет смысл, а если есть уже постоянный, просто использовать его как флаг, нет необходимости, чтобы сказать мне, что есть постоянное, видимо, целое число, что идет в качестве аргумента (флаг) в выражение. Я знаю больше, просто


Set LoadVisioDrawing = app.Documents.OpenEx(filename, visOpenRW)

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

Переменная app я бы назвал туманными. Я вижу вы использовали visioApp как и большинство ваших функций говорит "Визио" - почему бы просто не использовать visioApp или visioInstance или что-то подобное как имя переменной? Что будет убедиться, что я знаю, что мы в Visio.

Вы также имя переменной совпадает с именем объекта Visio - окна. Это может показаться непонятным, но это ваш выбор


Sub OpenVisioDrawing(ByVal filename As String, someData As String)
Private Function StartVisioInstance() As Object
Sub ActivateVisioInstance(ByRef app As Object)
Function LoadVisioDrawing(ByRef app As Object, ByVal filename As String) As Object
Sub SyncVisioDrawing(ByRef drawing As Object, ByVal someData As String)
Function DetermineDesiredVisioWindow(ByRef app As Object, ByRef drawing As Object) As Object
Sub ActivateVisioWindow(ByRef window As Object)
Sub MaximizeVisioWindow(ByRef window As Object)
Sub VisioScreenUpdating(ByRef app As Object, ByVal allow As Boolean)

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

Я вижу много из ByRef в есть, и несколько, которые неявно ByRef потому что у них не было места ByVal. Почему вы отправляете все в качестве эталона? Вы отправляете Objects ByRef в Functions что вернуться Objects.


Класс

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


Re: прочее

Я побежал от выхода 2016 образец vxd и в Visio окном не переставал мигать в панели задач для нового экземпляра программы. Если он уже был открыт, нет мигания.

Моргание начинается


Set LoadVisioDrawing = app.Documents.OpenEx(filename, visOpenRW)

Itried движется ActivateVisioInstance после LoadVisioDrawing но все равно, он мигает. У меня нет решения для этого, я просто нытик и выявляя проблемы :(

Шагая через код, хотя, я до сих пор не понимаю, как VisioInstanceExist может быть True без тебя называя, по сути AttachVisioInstance.

Я был неправ с моим примером новой версии этой функции. Она должна быть

Private Function GetVisioInstance() As Object
On Error GoTo NewInstance
Set GetVisioInstance = GetObject(, VISIO_CLASS_ID)
Exit Function
NewInstance:
Set GetVisioInstance = CreateObject(VISIO_CLASS_ID)
End Function

Это моя вина, извините. Точки, хотя все еще остается.

OpenVisioDrawing должны быть названы лучше, но насколько для нее название, я могу только давать советы. VisioHandler, VisioInterfacing, VisioController, что-то более широкое.

Ре: Класс

Если я переместить все из класса на улицу тестовый модуль и просто

Sub Test()
OpenVisioDrawing "C:\Users\Ray\myVisioFile.vsd", "Custom drawing title"
End Sub

Это работает точно так же, как если бы это в классе. По сути своей app это ваш объект, а не класс. И экземпляр Visio-это объект. Я имею в виду, почему именно этот класс, если вы не используете какие-либо специальные свойства? Я не говорю, что это не должно быть классом, я говорю, что думаю о том, почему это класс, и что его класс может сделать для вас по-другому, чем если бы вы просто придерживаться его в модуль.

Sub Test()
Dim visioHandler As Object
Set visioHandler = New VisioInterface
With visioHandler
.OpenVisioDrawing "C:\Users\Ray\myVisioFile.vsd", "Custom drawing title"
End With
End Sub

Правильно, теперь у нас есть экземпляр класса, объект за пределы класса. Что мы можем сделать с этим?

Допустим, в вашем классе вы положили в

Private windowTitle As String
Public Property Get Title() As String
Title = windowTitle
End Property
Public Property Let Title(ByVal newTitle As String)
windowTitle = newTitle
End Property

Теперь у вас есть то, что вы можете использовать за пределами класса.

Sub Test()
Const PATH As String = "C:\Users\Ray\myVisioFile.vsd"
Dim visioHandler As Object
Set visioHandler = New VisioInterface
'Let .Title
visioHandler.Title = "My Title"
'Get .Title
MsgBox visioHandler.Title
'Get .Title
visioHandler.OpenVisioDrawing PATH, visioHandler.Title
End Sub

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

1
ответ дан 19 февраля 2018 в 09:02 Источник Поделиться