Community
    • Login

    PythonScript: How to interact with dialogue boxes?

    Scheduled Pinned Locked Moved General Discussion
    pythonpythonscriptpythonscript
    6 Posts 2 Posters 1.3k 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.
    • Fuel DZNF
      Fuel DZN
      last edited by Fuel DZN

      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.

      Alan KilbornA 1 Reply Last reply Reply Quote 0
      • Alan KilbornA
        Alan Kilborn @Fuel DZN
        last edited by Alan Kilborn

        @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
        • Alan KilbornA
          Alan Kilborn
          last edited by Alan Kilborn

          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…

          Fuel DZNF 1 Reply Last reply Reply Quote 0
          • Fuel DZNF
            Fuel DZN @Alan Kilborn
            last edited by

            @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()
            
            Alan KilbornA 1 Reply Last reply Reply Quote 4
            • Alan KilbornA
              Alan Kilborn @Fuel DZN
              last edited by Alan Kilborn

              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…

              Fuel DZNF 1 Reply Last reply Reply Quote 4
              • Fuel DZNF
                Fuel DZN @Alan Kilborn
                last edited by

                @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
                • Alan KilbornA Alan Kilborn referenced this topic on
                • First post
                  Last post
                The Community of users of the Notepad++ text editor.
                Powered by NodeBB | Contributors