简体   繁体   English

Tkinter不保存按键之间的值?

[英]Tkinter not saving values between keypresses?

At least I think thats what's going on... 至少我认为那是怎么回事...

I am running two motors over a serial connection. 我正在通过串行连接运行两个电机。 The control values for Motor R range from 1 - 127, Motor L ranges from 128 to 255. 电动机R的控制值范围是1到127,电动机L的控制值范围是128到255。

I am using tkinter to capture arrow key presses, I then interpret that to feed to the motors, this works fine except I want to save the current state or the motor so I can know if I need to change the motor at the next keypress. 我正在使用tkinter捕获箭头按键,然后解释为将其馈送到电动机,除了我想保存当前状态或电动机之外,这工作正常,这样我就可以知道是否需要在下次按键时更换电动机。

It used to work until I added multi threading. 在添加多线程之前,它一直有效。

This is the code that's trying to save state: 这是试图保存状态的代码:

def save_cur_state(save_state):
    print'save_state'
    print save_state
    print'okay'
    if (save_state > 0 and save_state < 128):
        last_goodR(save_state)
    elif (save_state < 256 and save_state > 127):
        last_goodL(save_state)
    else:
        print'wtf?'

def last_goodR(n):
    global cur_stateR_save
    cur_stateR_save = n
    print 'RRRRRR'
    print cur_stateR

def last_goodL(n):
    global cur_stateL_save
    cur_stateL_save = n
    print'LLLL'
    print cur_stateL

def get_cur_state():
    global cur_stateR_save
    global cur_stateL_save
    print 'accessing saves'
    print cur_stateR_save
    print cur_stateL_save

    cur_stateR = cur_stateR_save
    cur_stateL = cur_stateL_save
    return(cur_stateL, cur_stateR)

Everything seems to run fine, my prints all give what they ought to. 一切似乎运行良好,我的印刷品都给出了应有的效果。 But then, when I press the key again, the "saved" values all default back to zero and I have no idea why. 但是,当我再次按下该键时,“已保存”的值都默认恢复为零,我也不知道为什么。 I've tried a billion different ways to work around it but I just can't get the values to stick. 我尝试了十亿种不同的方法来解决它,但我仍然无法坚持价值观。 Does anyone know why this might be the case or how I should work around it? 有谁知道为什么会这样,或者我应该如何解决? (My entire code is below in case you'd like to see it) Thank you!! (我的完整代码在下面,以防您想看)谢谢!!

import rospy
from std_msgs.msg import Int64
from Tkinter import *
import time
from serial import Serial
from multiprocessing import Process


#Defines
M1B = 1
M1S = 64
M1F = 127
M2B = 128
M2S = 192
M2F = 255

S = 0
F = 1
B = 2
L = 3
R = 4


#serialPort = Serial('/dev/ttyAMA0', 9600, timeout = 2)
cur_stateR = M1S
cur_stateL = M2S
next_stateR = M1S
next_state = M2S

main = Tk()


def kp(event):
    if event.keysym == 'Up' :
        direction_set(F)
    elif event.keysym =='Down' :
        direction_set(B)
    elif event.keysym =='Left' :
        direction_set(L)
    elif event.keysym =='Right' :
        direction_set(R)
    else :
        print'fooo'
        try:
            print'try'
            cur_stateR
            cur_stateL
        except NameError:
            print'except'

            cur_stateR = 0
            cur_stateL = 0
            last_goodR(0)
            last_goodL(0)


def direction_set(direction):
    if direction == F:
        next_stateR = M1F
        next_stateL = M2F
    elif direction == B:
        next_stateR = M1B
        next_stateL = M2B
    elif direction == R:
        next_stateR = M1B
        next_stateL = M2F
    elif direction == L:
        next_stateR = M1F
        next_stateL = M2B
    elif direction == S:
        next_stateR = M1S
        next_stateL = M2S
    else:
        next_stateR = M1S
        next_stateL = M2S
    update(next_stateR, next_stateL)

def update(next_stateR, next_stateL):
    if (cur_stateR != next_stateR):
        p1 = Process(target = motor1, args = (next_stateR,))
        p1.start()

    if (cur_stateL != next_stateL):
        p2 = Process(target = motor2, args = (next_stateL,))
        p2.start()


def motor1(next_stateR):
    #change the R motor
    print'start motor1'
    cur_stateR, cur_stateL = get_cur_state()
    if (cur_stateR != next_stateR):
        #first set to 64 
        cur_stateR = M1S
        refresh(cur_stateR)
        time.sleep(1)
        # then itterate to the desired stat
        if next_stateR == M1F:
            for x in range (M1S, M1F+1):
                cur_stateR = x
                time.sleep(.01)
                refresh(cur_stateR)
        elif next_stateR == M1B:
            for x in range (M1S, M1B-1, -1):
                cur_stateR = x
                time.sleep(.01)
                refresh(cur_stateR)

    save_cur_state(cur_stateR)
    print 'end motor1'

def motor2 (next_stateL):
    #change the L motor
    print 'start motor2'
    cur_stateR, cur_stateL = get_cur_state()
    if (cur_stateL != next_stateL):
        #first set to 64
        cur_stateL = M2S
        refresh(cur_stateL)
        time.sleep(1)
        # then itterate to the desired stat
        if next_stateL == M2F:
            for x in range (M2S, M2F+1):
                cur_stateL = x
                time.sleep(.01)
                refresh(cur_stateL)
        elif next_stateL == M2B:
            for x in range (M2S, M2B-1, -1):
                cur_stateL = x
                time.sleep(.01)
                refresh(cur_stateL)
    #print 'to save:'
    #print cur_stateR
    #print cur_stateL   
    save_cur_state(cur_stateL)

def refresh(update_state):
    #serialPort.write(chr(update_state))
    print update_state

def save_cur_state(save_state):
    print'save_state'
    print save_state
    print'okay'
    if (save_state > 0 and save_state < 128):
        last_goodR(save_state)
    elif (save_state < 256 and save_state > 127):
        last_goodL(save_state)
    else:
        print'wtf?'
''' try:
        print'try'
        cur_stateR
        cur_stateL
    except NameError:
        print'except'

        cur_stateR = 0
        cur_stateL = 0
        last_goodR(0)
        last_goodL(0)
    else:'''


def last_goodR(n):
    global cur_stateR_save
    cur_stateR_save = n
    print 'RRRRRR'
    print cur_stateR

def last_goodL(n):
    global cur_stateL_save
    cur_stateL_save = n
    print'LLLL'
    print cur_stateL

def get_cur_state():
    global cur_stateR_save
    global cur_stateL_save
    print 'saves acess'
    print cur_stateR_save
    print cur_stateL_save

    cur_stateR = cur_stateR_save
    cur_stateL = cur_stateL_save
    return(cur_stateL, cur_stateR)


main.bind_all('<KeyPress>', kp)


main.mainloop()

serialPort.close()

First off, before you try to do more with "threading", you should know that tkinter isn't threadsafe; 首先,在尝试使用“线程”做更多事情之前,您应该知道tkinter不是线程安全的。 GUI elements should not be accessed from anything but the thread that created them, any cross-thread usage is going to be unreliable at best, and guaranteed wrong the rest of the time. GUI元素只能从创建它们的线程中访问,任何跨线程的用法充其量都是不可靠的,并且在其余时间内保证不会出错。

Secondly, you're not actually engaged in threading. 其次,您实际上并未参与线程化。 You're using multiprocessing , which spawns new processes, and those processes do not not share memory (including stuff like global variables) with the process that spawned them except in very limited cases (eg multiprocessing.Array ). 您正在使用multiprocessing ,它会产生新的进程,并且这些进程不会与产生它们的进程共享内存(包括全局变量之类的东西),除非在非常有限的情况下(例如multiprocessing.Array )。 On UNIX-like systems, they're using fork , and as soon as the Process begins running, it has a copy-on-write view of what the original process has; 在类似UNIX的系统上,他们正在使用fork ,并且一旦Process开始运行,它就会具有原始进程拥有的写时复制视图。 it can read the same data from the moment of the fork , but if it changes it, it only changes its own copy, not the parent process's. 它可以从fork的那一刻开始读取相同的数据,但是如果更改它,它只会更改自己的副本,而不会更改父进程的副本。 The set_cur_state call in motor1 is setting the child process's copy of the values, but the original process's copy is unmodified. motor1set_cur_state调用正在设置子进程的值副本,但原始进程的副本未修改。

If you want to do work using threading (with threads, not processes), you can build on this simple example of how to do so . 如果要使用threading (使用线程而不是进程)进行工作,则可以在此简单示例的基础上进行操作

If you're using multiprocessing , a similar approach could be taken using a multiprocessing.Queue . 如果您使用multiprocessing ,类似的方法可以使用采取multiprocessing.Queue Alternatively, you could use a global multiprocessing.Pool , and instead of launching new Process es, you'd call apply_async on the pool when you need to dispatch work, change the function to accept state as arguments and return the new state, (instead of reading and writing global variables internally), and provide a callback function to apply_async that will be invoked with the return value. 或者,您可以使用全局multiprocessing.Pool ,而不是启动新的Process es, apply_async在需要分派工作时在池上调用apply_async ,将函数更改为接受状态作为参数并返回新状态,(而不是内部读取和写入全局变量),并为apply_async提供一个callback函数,该callback函数将使用返回值进行调用。 Note: From what I can tell, the callback will be invoked using a thread that communicates with the workers, not the main thread, so you still need to use the tricks from the example code to pass data back to widgets owned by the main thread. 注意:据我所知, callback将使用与工作程序通信的线程而不是主线程来调用,因此您仍然需要使用示例代码中的技巧将数据传递回主线程拥有的小部件。 。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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