简体   繁体   中英

Python subprocess doesn't run until calling process finished

EDIT 1 - added more code I'm not sure that proc.communicate was needed, it was one of the suggestions I found from some other stackoverflow code.(Sorry I was tired last night and didn't think too much before asking the question.)

I should add that I am not an experienced coder (mechanical engineer) as you can probably tell from my code

In my Gui I have a button to call a subprocess

The subprocess (screenshot-cmd.exe) creates a png of a cropped screen shot but it won't actually produce the file until there is an error or if the button click event is over.

This makes me think that the subprocess is not actually run until the event is finished

I want to call the process several times after a single button press and move the files that it produces after each one is produced

if I use proc.wait(), the process hangs indefinitely.

How do I stop this?

# function to take a single image called 'fileName' and place it in directory 'dir'
def takeImage(dir,fileName):

    # calculate the view to capture to get the whole display window in.
    clientRect = win32gui.GetClientRect(win32gui.GetForegroundWindow())
    windowRect = win32gui.GetWindowRect(win32gui.GetForegroundWindow())
    print(windowRect)
    windowSize = [windowRect[2]-windowRect[0],windowRect[3]-windowRect[1]]
    print(windowSize)
    print(clientRect)

    diffSize = [windowSize[0] -clientRect[2], windowSize[1] - clientRect[3]]
    lrbBorder = diffSize[0]/2
    topBorder = diffSize[1] - lrbBorder

    print("sizeDiff = " + str(diffSize))
    windowName = win32gui.GetWindowText(win32gui.GetForegroundWindow())
    handleId = win32gui.GetForegroundWindow()


    leftMar = designLabel.GetPosition()[0] + lrbBorder
    topMar = designLabel.GetPosition()[1]  + topBorder + designLabel.GetSize()[1]
    rightMar = leftMar + scene.width
    bottMar = topMar+scene.height

    margins = [leftMar,topMar,rightMar,bottMar]

    print(margins)

    # now print the view.
    #command_line = r"screenshot-cmd -wt '" + windowName + "' -rc " + str(margins[0]) + " " + str(margins[1]) + " " + str(margins[2]) + " " + str(margins[3]) + " -o " + fileName

    command_line = r"screenshot-cmd -wt '" + windowName + "' -rc " + str(margins[0]) + " " + str(margins[1]) + " " + str(margins[2]) + " " + str(margins[3]) + " -o " + fileName

    print(command_line)
    args = shlex.split(command_line)
    proc = subprocess.Popen(args)
    proc.wait() 

    wx.Yield()


    if not os.path.isdir(dir):
        os.makedirs(dir)

    newPath = os.path.join(dir,fileName)

    if os.path.exists(newPath):
        os.remove(newPath)

    oldPath = os.path.join(os.getcwd(), fileName)
    print("Old Path: " + oldPath)
    print("Exists: " + str(os.path.exists(oldPath)))
    shutil.move(oldPath,newPath)

    return

#event called upon clicking 'takeTenImag' button
def takeTenImgE(evt):
    global designNo
    global workingDirectory
    global numDesigns
    fileNameRoot = "test_"
    fileExtention = ".png"

    # check there are at least 10 designs
    if numDesigns > 9 and os.path.exists(workingDirectory):
        # find directory path to put images in 
        dir = os.path.join(workingDirectory, "images")
        # for each design

        for x in range(10):
            print("design =" + str(designNo))
            fileName = fileNameRoot + str(designNo) + fileExtention
            print("------------------")
            print("for x = " + str(x) + " "  + fileName)
            #   create image and save
            print(dir)
            takeImage(dir,fileName)
            #move to next design

            wx.PostEvent(forwardDesign, wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, forwardDesign.GetId()) ) 
            wx.Yield()
            print("design =" + str(designNo))
return

takeTenImg = wx.Button(p, label='Take Ten Images', pos=(rb + visScaleText.GetSize()[0]+10,takeImg.GetPosition()[1]+5 +takeImg.GetSize()[1]), size = (100,30))
takeTenImg.Bind(wx.EVT_BUTTON, takeTenImgE)

https://code.google.com/p/screenshot-cmd/

Barnaby, you may be over-complicating your subprocess use. Popen is typically used for when you need to communicate with the process during the time it is running. From the sound of it, you don't need to do that, so might want to use a higher level function. See the docs on subprocess' various invocations, and perhaps try using the call method. You'll need shell=True , as detailed in SO questions such as this one .

I've found that the error is in my calling of subprocess.

I was using:

command_line = r"screenshot-cmd -wt '" + windowName + ...." 
args = shlex.split(command_line)
subprocess.call(args,shell=True)

changing this to:

command_line = r"screenshot-cmd -wt '" + windowName + ...." 
subprocess.call(command_line,shell=True)

solves the hang.

What is peculiar is that both options work when not inside a wx button click event(ie a python script launched from the command line), but only the second works when inside the wx button click event. If anyone could enlighten me why that would be most appreciated.

EDIT: upon further investigation, the hang is caused by trying to specify the active window in screenshot-cmd.

To solve this I find the position of the window using windowRect = win32gui.GetWindowRect(win32gui.GetForegroundWindow())

and then use screenshot-cmd without specifying a window.

This solves all issues although it is unclear why this causes problems

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM