简体   繁体   中英

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. (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. (It does not use pygame to present any screens.) (This part also works fine on its own.)

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. (In other words, I'm happy to have the gui lie dormant until I tell it to wake up.) It won't work.

I've tried placing the mainloop() command at the end of the gui setup. 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. 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.). So python variables needed to set tkinter variables. I also thought that mainloop automatically looked for changes in tkinter variables and updated automatically. 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). As far as I can tell, nothing happens automatically.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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