• Login
Community
  • Login

PythonScript: How to interact with dialogue boxes?

Scheduled Pinned Locked Moved General Discussion
pythonpythonscriptpythonscript
6 Posts 2 Posters 1.7k Views
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • F
    Fuel DZN
    last edited by Fuel DZN Nov 10, 2023, 9:42 AM Nov 10, 2023, 9:41 AM

    I need to run a ‘Find in Files’ search for multiple directories, and need to search these directories very often. I want to automate this.

    All my scripts automate some very specific semi-complex operations, and are deeply tied to the PythonScript functions, so using a different software is not preferable.

    I can use this to start a search:

    notepad.menuCommand(MENUCOMMAND.SEARCH_FINDINFILES)
    

    But how can I change the directory, and click ‘find all’?

    Someone here found how to access search results using some menu scripting magic I don’t understand, so I was wondering if what I’m looking for could also be achieved via PythonScript.

    A 1 Reply Last reply Nov 10, 2023, 2:10 PM Reply Quote 0
    • A
      Alan Kilborn @Fuel DZN
      last edited by Alan Kilborn Nov 10, 2023, 2:11 PM Nov 10, 2023, 2:10 PM

      @Fuel-DZN

      need to run a ‘Find in Files’ search for multiple directories, and need to search these directories very often. I want to automate this.

      The “problem” with the desired approach you’ve discussed is in its hybridicity (probably not a real word). What I mean is, you want to script part of it, and let Notepad++ handle part of it – and that can cause things to get, well, complicated.

      Maybe it would be best to avoid trying to use Notepad++ 's search functions, and go with Python’s or PythonScript’s. For these cases, you wouldn’t get the search output in Notepad++ 's Search results window, though… don’t know if that is a key part of what you want. This route may be another opportunity for using the Little Dialog Wrapper, BTW.

      Another possibility for automation is Autohotkey , which I have no experience with (aside from knowing it exists), so I won’t go further with talking about it.

      But how can I change the directory, and click ‘find all’?

      Well, since you’ve asked a very specific question here, I can give you the answer to it (let me pull something together out of stuff I have), and you can then try it and see if you can work it into whatever bigger picture goal you have in mind.

      But, as I said, beyond that things may get “complicated” and you may hit a dead end, and we can’t solve every problem for you here. :-)

      1 Reply Last reply Reply Quote 2
      • A
        Alan Kilborn
        last edited by Alan Kilborn Nov 10, 2023, 2:52 PM Nov 10, 2023, 2:49 PM

        It turns out that the script HERE is a good framework for the current task. With just a few mods, it can become a demo for an automated press of the button that will do a find-in-files.

        I’ll do those mods and then post the new script here…

        F 1 Reply Last reply Nov 10, 2023, 4:17 PM Reply Quote 0
        • F
          Fuel DZN @Alan Kilborn
          last edited by Nov 10, 2023, 4:17 PM

          @Alan-Kilborn I actually found pywinauto can do what I wanted:

          from pywinauto.application import Application
          
          pattern = 'pattern'
          directory = 'directory'
          
          notepad.menuCommand(MENUCOMMAND.SEARCH_FINDINFILES)
          
          app = Application().connect(path=r"C:\Program Files\Notepad++\notepad++.exe")
          dialog = app.FindInFiles
          
          app.dialog.FindWhat_Edit.set_text(pattern)
          app.dialog.Directory_Edit.set_text(directory)
          app.dialog.FindAll.click()
          
          A 1 Reply Last reply Nov 15, 2023, 12:07 PM Reply Quote 4
          • A
            Alan Kilborn @Fuel DZN
            last edited by Alan Kilborn Nov 15, 2023, 1:51 PM Nov 15, 2023, 12:07 PM

            Note to other readers that pywinauto is not included as part of the standard PythonScript plugin. To use it, you’d need to have a standalone Python installed on your system, have pywinauto installed into that, and then tell the PythonScript plugin to prefer the standalone Python’s installed libraries.

            @Fuel-DZN

            Your script utilizing pywinauto is very clean looking indeed, but I’m wondering about what comes after what the script does. Is it purely a visual thing, i.e., the script runs and you visually scan the Search results panel…and that’s enough for you?

            My reason for asking is that a logical next step is to process in some manner via Python code the results of the search. And, while your script for accessing the Find in Files interface is nice, I tried some things using pywinauto to obtain the search results text, and after somewhat lengthy experimentation I didn’t see how to do it. It could be just my lack of experience with pywinauto…

            F 1 Reply Last reply Nov 17, 2023, 9:08 AM Reply Quote 4
            • F
              Fuel DZN @Alan Kilborn
              last edited by Nov 17, 2023, 9:08 AM

              @Alan-Kilborn said in PythonScript: How to interact with dialogue boxes?:

              That was my exact experience too. And even though inspect.exe shows the search result window, pywinauto still can’t find it.

              I instead opted to use this code made by someone here. With it I could create a script that suited my own uses, which I’ve now adapted it into something more general purpose below. It searches across multiple directories, reads the search results and allows you to open the files. (To anyone that uses it: make sure ‘Purge for every search’ is enabled in the search results context menu.)

              # encoding=utf-8
              from ctypes.wintypes import BOOL, HWND, LPARAM
              import ctypes
              import os.path
              import re
              import time
              
              from Npp import editor
              from pywinauto.application import Application
              
              
              console.clear()
              console.show()
              console.editor.setReadOnly(False)
              
              
              def get_search_results():
              
                  WNDENUMPROC = ctypes.WINFUNCTYPE(BOOL, HWND,LPARAM)
                  FindWindow = ctypes.windll.user32.FindWindowW
                  GetWindowText = ctypes.windll.user32.GetWindowTextW
                  GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
                  EnumChildWindows = ctypes.windll.user32.EnumChildWindows
                  GetClassName = ctypes.windll.user32.GetClassNameW
                  curr_class = ctypes.create_unicode_buffer(256)
              
                  search_results = ''
              
                  def foreach_window(hwnd, lParam):
                      global search_results
                      length = GetWindowTextLength(hwnd)
                      if length > 0:
                          buff = ctypes.create_unicode_buffer(length + 1)
                          GetWindowText(hwnd, buff, length + 1)
                          if buff.value.startswith('Search "'):
                              search_results = str(buff.value)
                              return False
                      return True
              
                  EnumChildWindows(FindWindow(u'Notepad++', None), WNDENUMPROC(foreach_window), 0)
              
              
              def open_files():
                  try:
                      file_list = re.findall(r'(C:\\.*)(?: \([0-9] hits?\))', search_results)
                  except:
                      console.editor.addStyledText(Cell('\nNo search results detected', [1]))
              
                  count = str(len(file_list))
                  if count == '0':
                      console.editor.addStyledText(Cell('\nNo files in results', [1]))
                      return
              
                  prompt = notepad.messageBox('Open all ' + count + ' files?', '', 1)
                  if prompt == 1:
                      for file in file_list:
                          if os.path.isfile(file):
                              notepad.open(file)
                          else:
                              console.editor.addStyledText(Cell('\nFiles/directory not found', [1]))
                              break
                      
                      app.wait_cpu_usage_lower(threshold=20, timeout=600) # wait until CPU usage is lower than 20%
              
              
              notepad.menuCommand(MENUCOMMAND.SEARCH_FINDINFILES)
              
              app = Application().connect(path=r"C:\Program Files\Notepad++\notepad++.exe")
              find_in_files = app.FindInFiles
              
              directories_list = 'list of directories'
              pattern = r'pattern'
              
              for directory in directories_list:
                  notepad.menuCommand(MENUCOMMAND.SEARCH_FINDINFILES)
                  app.find_in_files.FindWhat_Edit.set_text(pattern)
                  app.find_in_files.Directory_Edit.set_text(directory)
                  app.find_in_files.FindAll.click()
              
                  app.wait_cpu_usage_lower(threshold=20, timeout=600)
              
                  get_search_results()
                  open_files()
                  
                  time.sleep(0.1) # this is needed if the prompt is removed from open_files()
              
              1 Reply Last reply Reply Quote 2
              • A Alan Kilborn referenced this topic on Nov 26, 2023, 12:21 PM
              3 out of 6
              • First post
                3/6
                Last post
              The Community of users of the Notepad++ text editor.
              Powered by NodeBB | Contributors