如何防止按钮动作在Kivy中发生过快?

2024-09-30 00:28:51 发布

您现在位置:Python中文网/ 问答频道 /正文

嘿,伙计们,我对Kivy大概有10分钟的新鲜感,随意地染上了Python色。你知道吗

我试图创建一个按钮,调用我编写的bash脚本来启动radio接收器(rtlsdr)。单独调用它会导致GUI冻结,所以我决定使用线程。这工作得很好,但后来我发现我无法停止我的进程(rtl\u fm)-这是我需要做的事情,以便调用另一个频率。你知道吗

我决定使用Kivy中的on_presson_release方法来停止我所有的无线电进程,并尝试启动一个新的频率线程-理论上工作得很好,但是kill进程花费的时间太长,我认为它在有机会启动之前就杀死了我的on_release进程。我得按两次按钮。(将两个os.system进程放在一个线程中没有帮助,使用threading库中的Timer方法也没有帮助)这就是我设置它的方式-我可能不需要killRadio()中的线程,但我正在抓住救命稻草(事先很抱歉):

(使用subprocess.call也不起作用)

主电源.kv

FloatLayout:
    size_hint: 1, 1
    Label:
            markup: True
            text: '[size=25]This app is for testing purposes.[/size]'
            pos: 0, 0

    MDRaisedButton:
            text: "106.9"
            font_size: 25
            on_press: app.killRadio()
            on_release: app.tuneRadio("106.9M")
            pos: 20, 255
            size_hint: .3, .3

    MDRaisedButton:
            text: "93.3"
            font_size: 25
            on_press: app.killRadio()
            on_release: app.tuneRadio("93.3M")
            pos: 305, 255
            size_hint: .3, .3

主.py

def killRadio(obj):
    de = Thread(target = lambda: os.system("kill -9 $(ps -ef | grep rtl_fm | grep -v grep | awk '{print $2}')"))
    try:
       de.start() 
    except:
        print ("can't kill")

def tuneRadio(obj, station):
    th = Thread(target = lambda: os.system('radio ' + station))
    # time.sleep(.3)
    th.start()

电台狂欢节

#!/bin/sh

if [ "$1" = "stop" ] #thought this would kill the script - it just frees the cmd line
then
    echo "Stopping Radio Playback"
    exit 0
fi
if [ "$#" -gt 0  ]
then
    echo "playing {$1}"
    rtl_fm -f $1 -M wbfm -g 42 -s 200000 -r 192000 - | aplay -D hw:1,0 -c 2 -r 48000 -f S32_LE
else
    exit 0
fi

使用Clock.schedule_once并添加延迟似乎会冻结GUI,因此当按下另一个按钮时,我无法测试它是否工作。对不起,上面的代码是一个绝望的尝试一切-我只是想一个按钮,以杀死收音机,如果它的开启,并呼吁另一个频率。你知道吗

我厌倦了阅读Kivy和Python文档-有人看到遗漏了什么吗?我肯定我做错了什么。。。你知道吗

谢谢

编辑

def control_radio(self, *args):
    global radio
    radio_lock = threading.Lock()  # a mutex for the radio control
    if radio_lock.acquire(False):  # make sure other threads silently fail
        print("aquired")
        print(args)
        if radio and radio.poll() is None:  # kill the radio process if running
            print("radio and poll")
            radio.kill()  # use radio.terminate() for a milder version
        if args[0] == "tune":  # start the new radio process if requested
            print("tuning")
            radio = subprocess.Popen(["radio", args[1]])
        radio_lock.release()  # release the lock

我将@zwer控制函数修改为以下内容,以使它在我的主类中工作。你知道吗


Tags: thelockappsizereleaseif进程on
1条回答
网友
1楼 · 发布于 2024-09-30 00:28:51

首先,您应该真正使用^{},这样您就可以真正控制您的进程,而不必依赖脆弱的外部命令,最基本的方法是:

import subprocess

radio = None  # a reference to hold our radio process

def kill_radio(obj):
    if radio and radio.poll() is None:
        radio.kill()  # use radio.terminate() for a milder version

def tune_radio(obj, station):
    global radio
    if radio and radio.poll() is None:
        radio.kill()  # use radio.terminate() for a milder version
    radio = subprocess.Popen(["radio", station])

旁注:我会将整个.sh脚本转换为Python,以便更快地执行和更容易地控制,而不会有孤立进程的危险。

现在,问题是^{}^{}都是阻塞方法,因此在进程分别启动和终止之前,函数不会返回。你可以使用fire和forget线程,就像你尝试的那样,但是你会在轮到你的时候运行很多线程(加上你必须处理排队),所以你需要决定当用户发出太多命令时应该怎么做-在进程启动/终止之前禁用他们的控件可能是最好的,否则你的应用程序会代表用户进行假设。你知道吗

这完全取决于你如何布置你的控件和应用程序GUI,tho,所以我建议的唯一的其他选择(除了排队命令)就是忽略对底层无线电的调用,不管是调谐还是终止,而它已经开始/正在终止。比如:

import subprocess
import threading

radio = None  # a reference to radio
radio_lock = threading.Lock()  # a mutex for the radio control

def control_radio(command, *args):
    global radio
    if radio_lock.acquire(False):  # make sure other threads silently fail
        if radio and radio.poll() is None:  # kill the radio process if running
            radio.kill()  # use radio.terminate() for a milder version
        if command == "tune":  # start the new radio process if requested
            radio = subprocess.Popen(["radio", args[0]])
        radio_lock.release()  # release the lock

def kill_radio(obj):
    threading.Thread(target=control_radio, args=("kill", )).start()

def tune_radio(obj, station):
    threading.Thread(target=control_radio, args=("tune", station)).start()

我仍然不鼓励这样的使用,因为如果你强行关闭你的应用程序或者你不等待radio kill的执行,它可能会以一个操作过程结束。在退出应用程序时,至少要添加一个阻塞if radio and radio.poll() is None: radio.terminate()调用,以确保生成的子进程被终止。你知道吗

相关问题 更多 >

    热门问题