Sử dụng global statement là không cần thiết trong hai trường hợp cần lưu ý.
- bạn muốn mã hóa một hộp thoại có thể được nhập khẩu để sử dụng với một giao diện chính
- bạn muốn mã hóa một hộp thoại có thể được nhập khẩu để sử dụng mà không một giao diện chính
mã một hộp thoại có thể được nhập khẩu để sử dụng với một giao diện chính
012.351.
Tránh tuyên bố chung có thể được thực hiện bằng cách chuyển từ điển & khi bạn tạo một thể hiện của hộp thoại. Từ điển & sau đó có thể được liên kết với lệnh của nút, bằng cách sử dụng lambda. Điều đó tạo ra một hàm ẩn danh sẽ thực hiện cuộc gọi hàm của bạn (với args) khi nhấn nút.
Bạn có thể tránh sự cần thiết phải vượt qua phụ huynh mỗi khi bạn tạo một thể hiện của hộp thoại bằng cách ràng buộc cha mẹ với một thuộc tính lớp (gốc trong ví dụ này).
Bạn có thể lưu các mục sau dưới dạng mbox.py
trong your_python_folder\Lib\site-packages
hoặc trong cùng thư mục với tệp GUI chính của bạn.
import tkinter
class Mbox(object):
root = None
def __init__(self, msg, dict_key=None):
"""
msg = <str> the message to be displayed
dict_key = <sequence> (dictionary, key) to associate with user input
(providing a sequence for dict_key creates an entry for user input)
"""
tki = tkinter
self.top = tki.Toplevel(Mbox.root)
frm = tki.Frame(self.top, borderwidth=4, relief='ridge')
frm.pack(fill='both', expand=True)
label = tki.Label(frm, text=msg)
label.pack(padx=4, pady=4)
caller_wants_an_entry = dict_key is not None
if caller_wants_an_entry:
self.entry = tki.Entry(frm)
self.entry.pack(pady=4)
b_submit = tki.Button(frm, text='Submit')
b_submit['command'] = lambda: self.entry_to_dict(dict_key)
b_submit.pack()
b_cancel = tki.Button(frm, text='Cancel')
b_cancel['command'] = self.top.destroy
b_cancel.pack(padx=4, pady=4)
def entry_to_dict(self, dict_key):
data = self.entry.get()
if data:
d, key = dict_key
d[key] = data
self.top.destroy()
Bạn có thể xem các ví dụ mà phân lớp mục cấp đầu và tkSimpleDialog (tkinter.simpledialog trong py3) tại effbot.
Cần lưu ý rằng ttk widgets có thể hoán đổi cho nhau với các tiện ích tkinter trong ví dụ này.
Để căn giữa chính xác hộp thoại đọc → this.
Ví dụ về sử dụng:
import tkinter
import mbox
root = tkinter.Tk()
Mbox = mbox.Mbox
Mbox.root = root
D = {'user':'Bob'}
b_login = tkinter.Button(root, text='Log in')
b_login['command'] = lambda: Mbox('Name?', (D, 'user'))
b_login.pack()
b_loggedin = tkinter.Button(root, text='Current User')
b_loggedin['command'] = lambda: Mbox(D['user'])
b_loggedin.pack()
root.mainloop()
mã một hộp thoại có thể được nhập khẩu để sử dụng mà không một giao diện chính
Tạo một module có chứa một lớp hộp thoại (MessageBox ở đây). Ngoài ra, bao gồm một hàm tạo ra một thể hiện của lớp đó, và cuối cùng trả về giá trị của nút được nhấn (hoặc dữ liệu từ một widget Entry).
Dưới đây là mô-đun hoàn chỉnh mà bạn có thể tùy chỉnh với sự trợ giúp của các tham chiếu sau: NMTech & Effbot.
Lưu đoạn mã sau như mbox.py
trong your_python_folder\Lib\site-packages
import tkinter
class MessageBox(object):
def __init__(self, msg, b1, b2, frame, t, entry):
root = self.root = tkinter.Tk()
root.title('Message')
self.msg = str(msg)
# ctrl+c to copy self.msg
root.bind('<Control-c>', func=self.to_clip)
# remove the outer frame if frame=False
if not frame: root.overrideredirect(True)
# default values for the buttons to return
self.b1_return = True
self.b2_return = False
# if b1 or b2 is a tuple unpack into the button text & return value
if isinstance(b1, tuple): b1, self.b1_return = b1
if isinstance(b2, tuple): b2, self.b2_return = b2
# main frame
frm_1 = tkinter.Frame(root)
frm_1.pack(ipadx=2, ipady=2)
# the message
message = tkinter.Label(frm_1, text=self.msg)
message.pack(padx=8, pady=8)
# if entry=True create and set focus
if entry:
self.entry = tkinter.Entry(frm_1)
self.entry.pack()
self.entry.focus_set()
# button frame
frm_2 = tkinter.Frame(frm_1)
frm_2.pack(padx=4, pady=4)
# buttons
btn_1 = tkinter.Button(frm_2, width=8, text=b1)
btn_1['command'] = self.b1_action
btn_1.pack(side='left')
if not entry: btn_1.focus_set()
btn_2 = tkinter.Button(frm_2, width=8, text=b2)
btn_2['command'] = self.b2_action
btn_2.pack(side='left')
# the enter button will trigger the focused button's action
btn_1.bind('<KeyPress-Return>', func=self.b1_action)
btn_2.bind('<KeyPress-Return>', func=self.b2_action)
# roughly center the box on screen
# for accuracy see: https://stackoverflow.com/a/10018670/1217270
root.update_idletasks()
xp = (root.winfo_screenwidth() // 2) - (root.winfo_width() // 2)
yp = (root.winfo_screenheight() // 2) - (root.winfo_height() // 2)
geom = (root.winfo_width(), root.winfo_height(), xp, yp)
root.geometry('{0}x{1}+{2}+{3}'.format(*geom))
# call self.close_mod when the close button is pressed
root.protocol("WM_DELETE_WINDOW", self.close_mod)
# a trick to activate the window (on windows 7)
root.deiconify()
# if t is specified: call time_out after t seconds
if t: root.after(int(t*1000), func=self.time_out)
def b1_action(self, event=None):
try: x = self.entry.get()
except AttributeError:
self.returning = self.b1_return
self.root.quit()
else:
if x:
self.returning = x
self.root.quit()
def b2_action(self, event=None):
self.returning = self.b2_return
self.root.quit()
# remove this function and the call to protocol
# then the close button will act normally
def close_mod(self):
pass
def time_out(self):
try: x = self.entry.get()
except AttributeError: self.returning = None
else: self.returning = x
finally: self.root.quit()
def to_clip(self, event=None):
self.root.clipboard_clear()
self.root.clipboard_append(self.msg)
và:
def mbox(msg, b1='OK', b2='Cancel', frame=True, t=False, entry=False):
"""Create an instance of MessageBox, and get data back from the user.
msg = string to be displayed
b1 = text for left button, or a tuple (<text for button>, <to return on press>)
b2 = text for right button, or a tuple (<text for button>, <to return on press>)
frame = include a standard outerframe: True or False
t = time in seconds (int or float) until the msgbox automatically closes
entry = include an entry widget that will have its contents returned: True or False
"""
msgbox = MessageBox(msg, b1, b2, frame, t, entry)
msgbox.root.mainloop()
# the function pauses here until the mainloop is quit
msgbox.root.destroy()
return msgbox.returning
Sau mbox tạo ra một thể hiện của MessageBox nó bắt đầu mainloop,
mà hiệu quả dừng chức năng có cho đến khi trục chính được thoát qua root.quit()
.
Chức năng mbox sau đó có thể truy cập msgbox.returning
và trả lại giá trị của nó.
Ví dụ:
user = {}
mbox('starting in 1 second...', t=1)
user['name'] = mbox('name?', entry=True)
if user['name']:
user['sex'] = mbox('male or female?', ('male', 'm'), ('female', 'f'))
mbox(user, frame=False)
Thật tuyệt. Thx mate. – Marcin
Làm cách nào để sử dụng mã thứ hai để giao diện người dùng chính không thể nhấp được trong khi mbox được gọi? – DRTauli
@DRTauli Cá nhân tôi sẽ ẩn cửa sổ nếu tôi không muốn mọi người tương tác với nó; bởi vì làm cho nó không phản hồi có thể khiến người dùng nghĩ chương trình bị đóng băng. Tuy nhiên, bạn có thể tạm thời tắt hầu hết các tiện ích. Tôi khuyên bạn nên hỏi điều này như một câu hỏi mới tổng quát; ý kiến là để làm rõ và gợi ý. –