Как Page.FindText заставить искать все надписи, а не только первую

  • Автор темы Автор темы Cyrax
  • Дата начала Дата начала
Статус
Закрыто для дальнейших ответов.

Cyrax

Топикстартер
10 лет на форуме
Сообщения
588
Реакции
4
Метод Page.FindText(ИскомыйТекст, ЧувствительностьКрегистру) возвращает текстовый объект (shape), содержащий ИскомыйТекст. Каждый раз один и тот же. Но если текстовых объектов, содержащих ИскомыйТекст, несколько, как мне получить, скажем, 3 или 4 такой объект (shape) программно ?

P.S. Corel X3 SP1, WinXP SP3
 
Ответ: Как Page.FindText заставить искать все надписи, а не только первую

Вы бы Copy-Paste пользовались, метода Page.FindText не существует, а есть Page.TextFind.
В Вашем случае лучше пользоваться Text.Find в текстовых объектах
В образце кода перебираются текстовые объекты на странице и при наличии в них "SearchedText" красятся в красный цвет.
Код:
Sub tst()
  Set ss = ActivePage.FindShapes(, cdrTextShape)
  For Each s In ss
    If s.Text.Find("SearchedText", False) > 0 Then
      s.Fill.UniformColor.RGBAssign 255, 0, 0
    End If
  Next s
End Sub
Если Вам нужен 3-4-й объект с искомым текстом, то можете собрать их в ShapeRange и обращатся к ним по индексу.
 
Ответ: Как Page.FindText заставить искать все надписи, а не только первую

А не будет ли ручной перебор текста работать слишком долго ?
Текстовых объектов около 20000...
Тогда как Page.TextFind всё это одной командой выполняет.
 
Ответ: Как Page.FindText заставить искать все надписи, а не только первую

Вам кто-то запрещает скопировать код, запустить и замерить время? Или мне за Вас создавать тестовый файл с 20000 текстовых объектов?
 
Ответ: Как Page.FindText заставить искать все надписи, а не только первую

Методом ShapeRange.Add запихиваю все найденные объекты в глобальный findedShRange As New ShapeRange. Далее пользователь, скажем, удаляет один из таких объектов.
Каким образом определить, что i-й Shape был удалён, т.е. findedShRange(i) не существует ?
При обращении к любому свойству и при вызове любого метода findedShRange(i) или findedShRange.Item(i) макрос просто слетает. Логично, поскольку объекта не существует. Но в то же время функция IsEmpty для удалённых объектов возвращает не True, а False, как будто объект существует...

P.S. Значит, вопрос, поставленный в сабже, не имеет решения ?
 
Ответ: Как Page.FindText заставить искать все надписи, а не только первую

Да. Вопрос, поставленный в сабже ("Как Page.FindText заставить искать все надписи, а не только первую"), не имеет решения.
1) Не существует метода Page.FindText.
2) Если Вы имели в виду метод Page.TextFind, то он возвращает объект типа Shape, а не ShapeRange, а следовательно найдёт не все надписи, а только одну.
3) Проверка существования i-того объекта коллекции и существования удалённого объекта к сабжу отношения не имеет. Задавайте отдельный вопрос в отдельной теме. В следующий раз последует закрытие темы и бан от 3-х дней до недели.
 
Ответ: Как Page.FindText заставить искать все надписи, а не только первую

lev, к чему такие вызывающие реплики ? Лично к Вам претензий у меня нет. Но по поводу возникшей ситуации своё мнение выскажу. На многих форумах приходилось общаться с модераторами - и на юридических, и на медицинских, и на спортивных - лояльность и сдержанность отличает преобладающее их большинство. Если со стороны администрации нет давления, то на лицо "раздражающий" фактор. Если такой фактор - копипаст, то к инету подключен одни комп, а работаю я в Corel'е на другом компе, не связанном с первым сетью. Если дело в 20000 объектов, то вопрос был риторическим, побуждающим на рассмотрение способов решения поставленной задачи, исключающих необходимость пробежки макрокодом по всем текстовым объектам.
Что касается проверки существования i-того объекта, то формально "проверка существования i-того объекта коллекции" к сабжу не относится. Но вопрос об одновременной работе кода и действий пользователя (а именно в таком плане был поставлен вопрос) к сабжу отношение всё же имеет. Если же считать, что вопрос касается исключительно работы с коллекциями, то необходимо было бы полностью исключить возможность существования у автора сабжа мнения о том, что в результате определённых действий пользователя код в рассматриваемой ситуации может работать некорректно (не секрет, что Corel X3 имеет глюки, как связанные с макрокодом, так и нет).
Если же следовать Правилам строго формально и дословно, то к сабжу не имеет отношения не только последний вопрос, но и код поиска на основе Text.Find (Да и вообще всем вопросам кодирования на VB, связанным с синтаксисом, методами коллекций и прочими компонентами языка VB, в частности вопросам проверки существования i-го объекта, в этом случае не место на форуме CorelDRAW-Автоматизация.)

Ну а по сабжу - поиск на основе Text.Find для 20000 объектов на моей конфигурации работает 3 секунды, а при наличии выделения - 9 секунд. Завтра приведу код тройки макросов, которые во многих случаях обеспечат более удобную работу с поиском, нежели встроенная команда поиска текста.
 
Ответ: Как Page.FindText заставить искать все надписи, а не только первую

Завтра приведу код тройки макросов, которые во многих случаях обеспечат более удобную работу с поиском, нежели встроенная команда поиска текста.
Через другие встроеные команды? ))))

Но если текстовых объектов, содержащих ИскомыйТекст, несколько, как мне получить, скажем, 3 или 4 такой объект (shape) программно ?
Да хоть как )))) Как позволит совесть и знание языка. А вообще лучше всего работать с текстом именно через класс Text
 
Ответ: Как Page.FindText заставить искать все надписи, а не только первую

Двусторонний поиск с центрированием и масштабированием:
Код:
[SIZE=2]Const defaultTextToFind As String = "?"
Dim textToFind As String
Dim findedShRange As New ShapeRange
Dim findedShIndex As Long

Sub [B]Zoom[/B](magn As Double, relative As Boolean)
    Dim view As ActiveView
    Dim VPointX As Double
    Dim VPointY As Double
    
    Set view = Application.ActiveWindow.ActiveView
    VPointX = view.OriginX
    VPointY = view.OriginY
    
    If (relative) Then
        view.Zoom = view.Zoom * magn
    Else
        view.Zoom = magn
    End If
    If Not ActiveShape Is Nothing Then
        view.SetViewPoint ActiveShape.PositionX + ActiveShape.SizeWidth / 2, ActiveShape.PositionY - ActiveShape.SizeHeight / 2
    Else
        view.SetViewPoint VPointX, VPointY
    End If
End Sub

Sub [B]ZoomToTextSelected[/B]()
    Dim unit As cdrUnit
    Const rel As Double = 15
    
    unit = ActiveDocument.unit
    ActiveDocument.unit = cdrPoint
    Zoom (100 / rel) * (ActivePage.SizeHeight / ActiveShape.Text.Story.Size), False
    ActiveDocument.unit = unit
End Sub

Function [B]FindText[/B]() As Boolean
    Dim sh As shape
    Dim shRange As ShapeRange
    Dim selectedShRange As ShapeRange
            
    If (textToFind = "") Then
        textToFind = defaultTextToFind
    End If
    
    FindText = True
    textToFind = InputBox("Введите текст для поиска", "Поиск текста", textToFind)
    If Len(textToFind) = 0 Then
        findedShIndex = 0
        FindText = False
        Exit Function
    End If
    
    'На время выполнения поиска выделение снимается, т.к. поиск при наличии выделения втрое замедляется
    Set selectedShRange = ActiveSelectionRange
    ActiveSelectionRange.RemoveFromSelection
    
    findedShRange.RemoveAll
    Set shRange = ActivePage.FindShapes(, cdrTextShape)
    For Each sh In shRange
        If sh.Text.Find(textToFind, False) > 0 Then
            findedShRange.Add sh
        End If
    Next sh
    findedShIndex = 0
    If shRange.count > 0 Then findedShIndex = 1
    
    'Восстановление выделения по окончании поиска
    selectedShRange.CreateSelection
End Function

Sub [B]FindNPText[/B](dir)
    Dim singleMsgNeed As Boolean
    
    If (findedShIndex = 0) Then
        FindNewText
        Exit Sub
    End If
    
    singleMsgNeed = True
    If dir Then
        If findedShRange.count > 1 Then
            findedShIndex = findedShIndex + 1
            If (findedShIndex > findedShRange.count) Then findedShIndex = 1
            singleMsgNeed = False
        End If
    Else
        If findedShRange.count > 1 Then
            findedShIndex = findedShIndex - 1
            If (findedShIndex < 1) Then findedShIndex = findedShRange.count
            singleMsgNeed = False
        End If
    End If
    If singleMsgNeed Then
        MsgBox "Найден только один текстовый объект," + vbCrLf + "содержащий фрагмент '" + textToFind + "'."
    End If
    
    'выделение
    ActiveSelectionRange.RemoveFromSelection
    On Error GoTo DelMsg
        findedShRange(findedShIndex).Selected = True
    On Error GoTo 0
    
    'масштабирование
    ZoomToTextSelected
    
    Exit Sub
DelMsg: MsgBox findedShIndex & "-й текстовый объект," + vbCrLf + "содержащий фрагмент '" + textToFind + "', был удалён."
End Sub

Sub [COLOR=Blue]FindNewText[/COLOR]()
    Dim actualSearch As Boolean
    
    actualSearch = FindText
    If Not actualSearch Then Exit Sub
        
    If (findedShRange.count = 0) Then
        MsgBox "Текст '" + textToFind + "' не найден." + vbCrLf + "Возможно, искомый текст находится на невидимом слое."
        findedShIndex = 0
    Else
        MsgBox "Найдено текстовых объектов: " & findedShRange.count & vbCrLf + "Искомый фрагмент: '" + textToFind + "'."
        findedShIndex = 1
    End If
        
    'выделение
    ActiveSelectionRange.RemoveFromSelection
    findedShRange(1).Selected = True
        
    'масштабирование
    ZoomToTextSelected
End Sub

Sub [COLOR=Blue]FindNextText[/COLOR]()
    FindNPText (True)
End Sub

Sub [COLOR=Blue]FindPreviousText[/COLOR]()
    FindNPText (False)
End Sub
Выделенные синим цветом процедуры можно повесить на кнопки или клавиши...
 
Ответ: Как Page.FindText заставить искать все надписи, а не только первую


Не по теме:
Ситуация когда объект удалён, а ссылка на него осталась в коллекции может быть не только у текстоискателей. И где через пол-годика человеку наткнувшемуся на подобный вопрос искать ответ? В теме Page.FindText?
Я противник многостраничных всеобъемлющих тем типа "Все вопросы о Signa", "Всё о grep", "Preps 6"... В моих ветках, по мере моих сил, их не будет.
Кстати, за десяток раз когда я рекомендовал задать посторонний вопрос отдельной темой, только раз человек действительно заново задал его отдельно. Остальные то ли не хотели ответов, то ли в обиду ушли.

 
Статус
Закрыто для дальнейших ответов.