Python tkinter和pygame.midi之间的冲突

Python tkinter和pygame.midi之间的冲突,python,tkinter,pygame,midi,Python,Tkinter,Pygame,Midi,我正在尝试编写一个Python3程序,该程序使用tkinter设置Gui以显示图像(在标签中) 并通过各种小部件设置许多参数。(这部分很好用。) 我希望在我离开并运行使用pygame.midi的程序的其余部分时,Gui保持在屏幕上 输入和输出midi数据。(它不使用pygame显示任何屏幕。)(此部分在其上也可以正常工作 自己的。) 有时,在控制程序该部分中发生的情况时,我希望更新Gui和/或重置 一些参数,然后回到midi的东西。(换句话说,我很高兴gui处于休眠状态,直到 叫它醒来。)它不会

我正在尝试编写一个Python3程序,该程序使用tkinter设置Gui以显示图像(在标签中) 并通过各种小部件设置许多参数。(这部分很好用。)

我希望在我离开并运行使用pygame.midi的程序的其余部分时,Gui保持在屏幕上 输入和输出midi数据。(它不使用pygame显示任何屏幕。)(此部分在其上也可以正常工作 自己的。)

有时,在控制程序该部分中发生的情况时,我希望更新Gui和/或重置 一些参数,然后回到midi的东西。(换句话说,我很高兴gui处于休眠状态,直到 叫它醒来。)它不会工作的

我已经尝试将mainloop()命令放在gui设置的末尾。我试着把它放在节目的最后。 两者都不起作用。在我看来,pygame.midi所做的midi轮询是不允许的,因为gui和midi 轮询涉及冲突的线程。我说得对吗?有简单的解决办法吗?你能告诉我在哪里可以找到它吗

新增代码:


    #!/usr/local/bin/python3

from tkinter import Tk
from tkinter import ttk
from tkinter import Frame
from tkinter import E, W
from tkinter import StringVar

import sys
import os

import pygame.midi


def do_nothing(*args):
    labelbox.update()


def do_midi():
    global pygame_initialized, midi_out, midi_in, msgVar
    if not pygame_initialized:
        pygame.init()
        pygame.midi.init()  # Sets PortMidi timer to zero.
        midi_in = pygame.midi.Input(3, 4096)
        midi_out = pygame.midi.Output(2)
        pygame_initialized = True

    midi_out.write_short(176, 122, 00)  # turn off echo
    while True:
        if midi_in.poll():
            midi_event_list = midi_in.read(1)
            event = midi_event_list[0][0][0]

            if event == 248:  # timing event ignore
                continue

            if event > 159 or event < 128:  # non key-off or key-on midi events are passed through
                midi_out.write(midi_event_list)
                continue

            # From here on we are dealing only with key-on or key-off events

            key = midi_event_list[0][0][1]
            vel = midi_event_list[0][0][2]

            if key == 21:  # right now this is the only way back to the gui to Quit
                if vel != 0:
                    midi_out.write_short(176, 122, 127)  # Turn local control back on
                    return

            if vel != 0:  # only do this for key-on events
                msgVar.set(key)

            midi_out.write_short(event, key, vel)


def cleanup():
    global pygame_initialized, midi_out, midi_in
    root.destroy()
    if pygame_initialized:
        del midi_out
        del midi_in
        pygame.midi.quit()
    sys.exit()


if __name__ == '__main__':
    os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (0, 0)
    pygame_initialized = False
    global msgVar
    message = "Push the Play button!"

    root = Tk()

    msgVar = StringVar()
    msgVar.set(message)
    msgVar.trace("w", do_nothing)

    root.title("Testing midi")
    root.geometry("900x600+200+100")

    frame1 = Frame(root, width=900, height=600)
    frame1.grid(column=0, row=0)

    ttk.Button(frame1, text="Play", style='My.TButton', command=do_midi).grid(column=0, row=4, pady=(40, 0), sticky=W)
    labelbox = ttk.Label(frame1)
    labelbox.grid(column=1, row=4)
    labelbox.configure(textvariable=msgVar)


    ttk.Button(frame1, text="Quit", style='My.TButton', command=cleanup).grid(column=2, row=4, pady=(40, 0), sticky=E)

    root.mainloop()

#!/usr/local/bin/python3
从tkinter导入Tk
从tkinter导入ttk
从tkinter导入框架
从特金特进口东、西
从tkinter导入StringVar
导入系统
导入操作系统
导入pygame.midi
def不执行任何操作(*参数):
labelbox.update()
def do_midi():
全局pygame_已初始化、midi_已输出、midi_已输入、msgVar
如果未初始化pygame_:
pygame.init()
pygame.midi.init()#将PortMidi计时器设置为零。
midi_in=pygame.midi.Input(34096)
midi_out=pygame.midi.Output(2)
pygame_已初始化=真
midi输出。短写(17612200)#关闭回声
尽管如此:
如果midi_在.poll()中:
midi_事件_列表=midi_in.read(1)
事件=midi_事件列表[0][0][0]
如果事件==248:#定时事件忽略
持续
如果事件>159或事件<128:#通过非键关闭或键打开midi事件
midi_输出。写入(midi_事件列表)
持续
#从现在起,我们只处理钥匙打开或关闭事件
key=midi_事件_列表[0][0][1]
vel=midi_事件_列表[0][0][2]
如果key==21:#现在这是返回gui退出的唯一方法
如果水平!=0:
midi输出。短写(176122127)#重新打开本地控制
返回
如果水平!=0:#仅对按键打开事件执行此操作
msgVar.set(键)
midi输出。写短(事件、键、级别)
def cleanup():
全局pygame_初始化,midi_输出,midi_输入
root.destroy()
如果pygame_已初始化:
德尔米迪欧酒店
德尔米迪欧酒店
pygame.midi.quit()
sys.exit()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
操作系统环境['SDL\U视频窗口位置]=%d,%d%(0,0)
pygame_已初始化=False
全球msgVar
message=“按下播放按钮!”
root=Tk()
msgVar=StringVar()
msgVar.set(消息)
msgVar.trace(“w”,不做任何事情)
root.title(“测试midi”)
根部几何形状(“900x600+200+100”)
框架1=框架(根,宽度=900,高度=600)
frame1.grid(列=0,行=0)
ttk.Button(frame1,text=“Play”,style='My.TButton',command=do_midi).grid(column=0,row=4,pady=(40,0),sticky=W)
labelbox=ttk.Label(frame1)
labelbox.grid(列=1,行=4)
labelbox.configure(textvariable=msgVar)
ttk.Button(frame1,text=“Quit”,style='My.TButton',command=cleanup).grid(column=2,row=4,pady=(40,0),sticky=E)
root.mainloop()

最后一个代码清单包含了我学到的内容。基本上,我不理解这样一个事实,即许多帖子中提到的被更新的“变量”实际上是tkinter变量(StringVar、BooleanVar等)。所以python变量需要设置tkinter变量。我还认为mainloop会自动查找tkinter变量中的更改并自动更新。换句话说,我不明白我需要为我想要观察的变量设置“跟踪”。之后,我需要了解“跟踪”不会自动更新,您必须使用它来触发显式的“更新”。
在我的实际代码(太长,无法在此发布)中,我使用midi事件设置的tkinter变量来更改列表框中的选择(通过“清除”、“激活”、“选择集”和“查看”)和标签中显示的“更新”图像(链接到所选项目的索引)。据我所知,没有任何事情是自动发生的。

也许你可以在事件循环和midi循环周围发布一些代码。@Kingsley:我很乐意,尽管有很多,而且正如我所说,各个部分都可以工作。我希望,通过更笼统地阐述这个问题,我不会分散对基本问题的注意力。我应该补充一点,我有一个版本的程序,工作得很好。它将tkinter和pygame部分分开(当我运行pygame midi时使用pygame图形,当我关闭midi时使用tkinter)。我试图找到一个更优雅的解决方案——同时也想了解更多关于tkinter和pygame、midi的关系。如果我没有收到其他回复,我会发布一些代码。我应该补充一点,我是在Debian Jessie下的Raspberry Pi上运行该软件的。下面是一个简单的示例。它将所有midi内容转换为一个函数,并通过“返回”返回gui。当它运行该功能时,gui是不可访问的,但它会跟踪任何单击,并在重新获得控制时应用它们。例如,在弹奏键盘时按“Play”5次,它将根据5次返回来存储它们。(这可能是地球上除我之外的所有人都知道的。)重要更新:我已将原始代码示例替换为扩展版本,该版本尝试传达标签的StringVar更新。这是可行的,只是它总是一个