简体   繁体   English

tkinter 和 pygame.midi 之间的冲突

[英]conflicts between tkinter and pygame.midi

I am attempting to write a Python 3 program which sets up a Gui with tkinter to display an image (in a label) and set a number of parameters via various widgets.我正在尝试编写一个 Python 3 程序,该程序使用 tkinter 设置 Gui 以显示图像(在标签中)并通过各种小部件设置许多参数。 (This part works fine.) (这部分工作正常。)

I want that Gui to stay on the screen while I go off and run the rest of the program which uses pygame.midi to input and output midi data.我希望 Gui 在我离开并运行使用 pygame.midi 输入和输出 midi 数据的程序的其余部分时留在屏幕上。 (It does not use pygame to present any screens.) (This part also works fine on its own.) (它不使用 pygame 来呈现任何屏幕。)(这部分本身也可以正常工作。)

From time to time, at the control of what happens in that part of the program I want to update the Gui and/or reset some of the parameters and then go back to the midi stuff.有时,在控制程序那部分发生的事情时,我想更新 Gui 和/或重置一些参数,然后返回到 MIDI 内容。 (In other words, I'm happy to have the gui lie dormant until I tell it to wake up.) It won't work. (换句话说,我很高兴让 gui lie 处于休眠状态,直到我告诉它醒来。)这行不通。

I've tried placing the mainloop() command at the end of the gui setup.我试过将 mainloop() 命令放在 gui 设置的末尾。 I've tried placing it at the very end of the program.我试过把它放在程序的最后。 neither works.两者都不起作用。 It looks to me as if the midi polling that pygame.midi does is not being allowed because both the gui and midi polling involves threads in conflict.在我看来,pygame.midi 进行的midi 轮询似乎是不被允许的,因为gui 和midi 轮询都涉及线程冲突。 Am I correct?我对么? Is there a simple solution?有简单的解决方案吗? Can you point me to where I might find it?你能指出我在哪里可以找到它吗?

Code added:添加的代码:


    #!/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()

The last code listing incorporates what I learned.最后一个代码清单包含了我学到的东西。 Basically I didn't understand the fact that the "variables" referred to in many postings as being updated were, in fact, tkinter vaiables (StringVar, BooleanVar, etc.).基本上我不明白在许多帖子中提到的“变量”被更新的事实,实际上是 tkinter 变量(StringVar、BooleanVar 等)。 So python variables needed to set tkinter variables.所以python变量需要设置tkinter变量。 I also thought that mainloop automatically looked for changes in tkinter variables and updated automatically.我还认为 mainloop 会自动查找 tkinter 变量中的更改并自动更新。 In other words, I didn't understand that I needed "trace" to be set for the variables I wanted to watch.换句话说,我不明白我需要为我想观察的变量设置“跟踪”。 After that, I needed to learn that "trace" doesn't update automatically, you have to use it to trigger an explicit "update".在那之后,我需要了解“跟踪”不会自动更新,您必须使用它来触发显式“更新”。 In my actual code (too long to post here) I am using tkinter variables "set" by midi events to change selections in a listbox (via "clear", "activate", "selection_set", and "see") and "update" images displayed in a label (which are linked to the index of the item selected).在我的实际代码(太长,无法在此处发布)中,我使用 tkinter 变量通过 MIDI 事件“设置”来更改列表框中的选择(通过“清除”、“激活”、“selection_set”和“查看”)和“更新” " 显示在标签中的图像(链接到所选项目的索引)。 As far as I can tell, nothing happens automatically.据我所知,没有任何事情会自动发生。

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

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