首页 > 解决方案 > 为什么我的执行 MySQL 查询的函数在使用 ttk.combobox 的 postcommand 调用时会出错

问题描述

我有这个程序连接到 phpmyadmin MySQL 数据库。它有一个组合框,只要单击下拉箭头,我就想更新其值。我使用组合框的 postcommand 参数来调用执行查询并更新值的函数。这是我的代码简化:

from mysql.connector import connect, Error
from tkinter import *
from tkinter import ttk

root = Tk()
root.title('Program')
root.geometry('600x600+100+100')

def load_combobox(conn, cbox):
    query = 'SELECT nama_sopir FROM sopir'
    with conn.cursor() as cursor:
        cursor.execute(query)
        result = cursor.fetchall()
        cbox.config(values=result)

try:
    with connect(
        host = 'localhost',
        user = 'root',
        password = '',
        database = 'sinar_express_database'
    ) as conn:
        frame1 = Frame(root)
        frame1.pack(fill='both', expand=1)

        # I want to call the function on postcommand. This calls the function but an error occurs
        sopir_cbox = ttk.Combobox(frame1, state='readonly', postcommand=lambda : load_combobox(conn, sopir_cbox))
        sopir_cbox.pack()
except Error as e:
    print(e)

root.mainloop()

这会产生一个错误:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Winston\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "d:\Documents\Usaha Papa Mama\Program Uang Jalan\Baru\stackoverflow.py", line 27, in <lambda>
    sopir_cbox = ttk.Combobox(frame1, state='readonly', postcommand=lambda : load_combobox(conn, sopir_cbox))
  File "d:\Documents\Usaha Papa Mama\Program Uang Jalan\Baru\stackoverflow.py", line 11, in load_combobox
    with conn.cursor() as cursor:
  File "C:\Users\Winston\AppData\Local\Programs\Python\Python37\lib\site-packages\mysql\connector\connection.py", line 1025, in cursor
    raise errors.OperationalError("MySQL Connection not available.")
mysql.connector.errors.OperationalError: MySQL Connection not available

我试过单独调用该函数,如下所示,它可以工作!但是,我想在每次单击下拉列表时更新值,而不仅仅是一次。

        sopir_cbox = ttk.Combobox(frame1, state='readonly')
        load_combobox(conn, sopir_cbox)

我对编程还是很陌生,因此非常感谢任何帮助或建议。

标签: pythonmysqltkinter

解决方案


GUI框架不像input()等待你的决定那样工作。Combobox(和其他小部件)不会等待您的决定。它只通知tkinter它必须在窗口中显示的内容 - 并且代码移动到下一行 -mainloop()显示窗口。

所以你在它退出后看到窗口with connect(),当你选择选项时,代码已经在外面with connect()。你必须在with connect()里面使用load_comobox

from mysql.connector import connect, Error
from tkinter import *
from tkinter import ttk

# --- functions ---

def load_combobox():
    try:
        with connect(
                host = 'localhost',
                user = 'root',
                password = '',
                database = 'sinar_express_database'
            ) as conn:
            query = 'SELECT nama_sopir FROM sopir'
            with conn.cursor() as cursor:
                cursor.execute(query)
                result = cursor.fetchall()
                sopir_cbox.config(values=result)
    except Error as e:
        print(e)

# --- main ---

root = Tk()
root.title('Program')
root.geometry('600x600+100+100')

frame1 = Frame(root)
frame1.pack(fill='both', expand=1)

# I want to call the function on postcommand. This calls the function but an error occurs
sopir_cbox = ttk.Combobox(frame1, state='readonly', postcommand=load_combobox)
sopir_cbox.pack()

root.mainloop()

或者你必须把mailoop()里面with connect()

with connect(
    host = 'localhost',
    user = 'root',
    password = '',
    database = 'sinar_express_database'
) as conn:
    frame1 = Frame(root)
    frame1.pack(fill='both', expand=1)

    # I want to call the function on postcommand. This calls the function but an error occurs
    sopir_cbox = ttk.Combobox(frame1, state='readonly', postcommand=lambda : load_combobox(conn, sopir_cbox))
    sopir_cbox.pack()

    root.mainloop()
except Error as e:
    print(e)

但在这里我看到了一个问题——你不能sopir_cbox在里面使用,ttk.Combobox(...)因为它还没有退出。代码首先执行ttk.Combobox(...),然后它创建变量sopir_cbox = ...,但您需要sopir_cbox在尚未创建的ttk.Combobox(...)时候。sopir_cbox = ...您必须分两步完成

sopir_cbox = ttk.Combobox(frame1, state='readonly')
sopir_cbox["postcommand"] = lambda : load_combobox(conn, sopir_cbox)

推荐阅读