首页 文章

Python线程在函数调用时没有正确执行(Kivy)

提问于
浏览
0

我已经绑定了一个函数调用Kivy按钮,它构建并启动两个线程 . 我正在使用Kivy标签来表明我确实正在进入函数'my_function()'并一直走到最后 . 似乎线程没有正确构建 .

两个螺纹各自旨在转动步进电机 . 我已经测试了这些电机并且它们可以正常工作,但是当我尝试将代码放在一个函数中并对变量应用“self”时,按钮按下没有任何反应,除了最后的标签被更新 .

蟒蛇:

import kivy
kivy.require('1.9.1')

from kivy.app import App
from kivy.uix.screenmanager import Screenmanager, Screen
from kivy.properties import StringProperty
from Adafruit_MotorHAT import Adafruit_MotorHAT, Adafruit_DCMotor, Adafruit_StepperMotor
import threading
import random
import time
import atexit

class ScreenManager(ScreenManager):
    pass

class StartMenu(Screen):
    pass

这是经过验证的真实代码:

class MyScreen(Screen):
    entered = StringProperty("Not Entered")

    # create a default object, no changes to I2C address or frequency
    mh = Adafruit_MotorHAT()

    # create empty threads (these will hold the stepper 1 and 2 threads)
    st1 = Threading.thread()
    st2 = Threading.thread()

    # recommended for auto-disabling motors on shutdown!
    def turnOffMotors(mh):
        mh.getMotor(1).run(Adafruit_MotorHAT.RELEASE)
        mh.getMotor(2).run(Adafruit_MotorHAT.RELEASE)
        mh.getMotor(3).run(Adafruit_MotorHAT.RELEASE)
        mh.getMotor(4).run(Adafruit_MotorHAT.RELEASE)

    atexit.register(turnOffMotors(mh))

    myStepper1 = mh.getStepper(200, 1)      # 200 steps/rev, motor port #1
    myStepper2 = mh.getStepper(200, 2)      # 200 steps/rev, motor port #1
    myStepper1.setSpeed(60)                 # 30 RPM
    myStepper2.setSpeed(60)                 # 30 RPM


    stepstyles = [Adafruit_MotorHAT.SINGLE, Adafruit_MotorHAT.DOUBLE, Adafruit_MotorHAT.INTERLEAVE, Adafruit_MotorHAT.MICROSTEP]

    def stepper_worker(stepper, numsteps, direction, style):
        stepper.step(numsteps, direction, style)

将代码放在my_function()中并应用'self';线程不再有效 . 重复第二个线程的代码 . 我想强调一下,当代码不在函数内部而不使用“self”时,此代码可以正常工作:

def my_function(self, *args):
        if (True):
            time.sleep(0.005)
            if not self.st1.isAlive():
                randomdir = random.randint(0, 1)
                if (randomdir == 0):
                    dir = Adafruit_MotorHAT.FORWARD
                else:
                    dir = Adafruit_MotorHAT.BACKWARD

                randomsteps = random.randint(10,50)
                self.st1 = threading.Thread(target=self.stepper_worker, args=(self.myStepper1, randomsteps, dir, self.stepstyles[random.randint(0,3)],))
                self.st1.start()
                self.entered = "Entered"

Build :

class MyApp(App):
    def build(self):
        return ScreenManager()

if __name__ == "__main__":
    MyApp().run()

Kivy:my.kv

我遗漏了一些不必要的细节,比如布局和小部件大小 .

#:kivy 1.9.1

<ScreenManager>:
    StartMenu:
    MyScreen:

<StartMenu>:
    name: 'StartMenu'
    Button:
        on_release:
            root.manager.current = 'MyScreen'

<MyScreen>:
    name: 'MyScreen'
    Label:
        text: root.entered
    Button:
        on_release:
            root.my_function()

谢谢你的时间!

1 回答

  • 0

    您将stepper_worker定义为MyScreen下的方法,因此它将获得的第一个参数是MyScreen的实例 .

    在您的示例中,您应该将其定义为函数或首先添加self参数 . 我假设您的线程无法启动,因为您发送了太多参数

    # len(args) == 4 so you have too many parameters (the first is fixed to "self")
    self.st1 = threading.Thread(target=self.stepper_worker, args=(self.myStepper1, randomsteps, dir, self.stepstyles[random.randint(0,3)],))
    

    可能的解决方法如上所述:

    #added self...
    def stepper_worker(self, stepper, numsteps, direction, style):
        stepper.step(numsteps, direction, style)
    

    我希望这将有所帮助 . 还看看你是否真的需要在MyScreen下定义这些方法......

    另请注意,如果线程想要访问kivy UI,则需要通过调用Clock来实现(因此您将拥有线程安全性)

相关问题