Python Pyinstaller EXE将仅从CMD运行,单击EXE不会';行不通

Python Pyinstaller EXE将仅从CMD运行,单击EXE不会';行不通,python,tkinter,exe,pyinstaller,packaging,Python,Tkinter,Exe,Pyinstaller,Packaging,我为我的一个朋友编写了一个简单的python程序,它使用了tkinter和SMTPlib。 我使用pyinstaller为程序生成一个.exe,但当我双击.exe时,我的CMD终端将在屏幕上闪烁一秒钟,然后消失。当我将同一个.exe拖动到我的CMD终端并按enter键时,程序运行时不会出现任何问题,程序的每个功能都正常工作 我正在附加我创建的.spec文件pyinstaller,我根本没有修改它。我真的觉得它应该可以工作,如果我从CMD调用它,它100%可以工作,唯一的问题是当我双击.exe时。

我为我的一个朋友编写了一个简单的python程序,它使用了
tkinter
SMTPlib
。 我使用
pyinstaller
为程序生成一个.exe,但当我双击.exe时,我的CMD终端将在屏幕上闪烁一秒钟,然后消失。当我将同一个.exe拖动到我的CMD终端并按enter键时,程序运行时不会出现任何问题,程序的每个功能都正常工作

我正在附加我创建的.spec文件
pyinstaller
,我根本没有修改它。我真的觉得它应该可以工作,如果我从CMD调用它,它100%可以工作,唯一的问题是当我双击.exe时。非常令人沮丧

我已经在网上看到过好几次同样的问题,但我所看到的解决方案并没有对我有所帮助。任何帮助都将不胜感激

编辑:按照下面的建议,我能够让程序运行。我必须更改.spec文件,特别是
datas
字段,才能使其正常工作。但是,我现在遇到了一个问题,即.txt文件将加载到哪里,但在编辑它们时,所做的编辑并没有按应有的方式保存。在我修复原始问题之前,所有编辑都已保存,当时我只能从CMD运行程序。我将整个脚本发布在下面:

编辑II:我没有将文件置于“w”模式,这就是为什么我没有得到任何文本文件的输出。现在一切都好了

我的规范文件:

block_cipher = None


a = Analysis(['test.py'],
             pathex=['C:\\Users\\wiley\\PycharmProjects\\EmailBot\\email_bot2'],
             binaries=[],
             datas=[('students1.txt', '.'),('students2.txt','.')],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='test',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=False )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='test')
my main.py文件:

from tkinter import *
from tkinter import ttk
import re
import email_data
import smtplib
import os

__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))

student_view = None
email_string = ''


def display_email():
    def save_and_close():
        preview_window.destroy()

    preview_window = Toplevel()
    preview_window.title("Preview")
    preview_window.geometry('-680+300')
    preview_window.grab_set()
    preview_window.lift(root)

    preview_frame = ttk.Frame(preview_window, padding=10)
    preview = Text(preview_frame)
    close_button = Button(preview_frame, text='Close', command=save_and_close)

    preview_frame.grid()
    preview.grid(column=0, row=0, sticky='NSEW')
    close_button.grid(column=0, row=1, sticky='NSEW')

    preview.insert(END, email_string)


def format_email():
    global email_string
    email_string = email_data.email_string_raw.format(this_lab_name=t1.get(), zoom_date_time=t2.get(),
                                                      zoom_link=t3.get(),
                                                      zoom_ID=t4.get(),
                                                      zoom_passcode=t5.get(), this_lab_supplemental=t6.get(),
                                                      this_lab_consisting=t7.get(),
                                                      this_lab_due=t8.get(), file_name_tag=t9.get(),
                                                      last_lab_reminder=t10.get(),
                                                      last_lab_due=t11.get(),
                                                      last_lab_supplemental=t12.get(), last_file_name_tag=t13.get())
    view_email_button['state'] = 'normal'
    send_button['state'] = 'normal'


def send_email():
    global p, z, email_string, emails1, emails2

    def send_email_final():
        smtp_obj = smtplib.SMTP('smtp.office365.com', port=587)
        smtp_obj.starttls()
        email = email_input.get()
        password = email_pass_input.get()
        smtp_obj.login(email, password)

        from_address = email_input.get()

        msg = "Subject: CHML101: Weekly Instructional Email" + '\n\n' + email_string
        to_address_list = []
        if p.get() == 1:
            data = open(os.path.join(__location__, 'students1.txt'))
            emails = data.read()
            to_address_list = emails.split('\n')
            print(to_address_list.__str__())
        elif p.get() == 2:
            data = open(os.path.join(__location__, 'students2.txt'))
            emails = data.read()
            to_address_list = emails.split('\n')
            print(to_address_list.__str__())

        print(msg)
        smtp_obj.sendmail(from_address, to_address_list, msg)

    def confirm_normal():
        confirm_check['state'] = 'normal'

    def send_normal():
        if z.get() == 1:
            send_email_button['state'] = 'normal'
        else:
            send_email_button['state'] = 'disabled'

    send_email_window = Toplevel()
    send_email_window.title("Send Email")
    send_email_window.geometry('400x175-680+300')
    send_email_window.grab_set()
    send_email_window.lift(root)

    send_frame = ttk.Frame(send_email_window)
    email_label = Label(send_frame, text='Enter your email address:')
    pass_label = Label(send_frame, text='Enter your email password:')
    email_input = Entry(send_frame)
    email_pass_input = Entry(send_frame, show='*')
    class_label1 = Label(send_frame, text='Email class 1:')
    class_label2 = Label(send_frame, text='Email class 2:')
    class_radio1 = Radiobutton(send_frame, var=p, value=1, command=confirm_normal)
    class_radio2 = Radiobutton(send_frame, var=p, value=2, command=confirm_normal)
    confirm_label = Label(send_frame, text='Confirm selection:')
    confirm_check = Checkbutton(send_frame, state='disabled', variable=z, command=send_normal)
    send_email_button = Button(send_frame, text='Send Email', state='disabled', command=send_email_final)

    send_frame.grid(column=0, row=0, sticky='NSEW')
    email_label.grid(column=0, row=0, columnspan=2)
    pass_label.grid(column=2, row=0, columnspan=2)
    email_input.grid(column=0, row=1, columnspan=2)
    email_pass_input.grid(column=2, row=1, columnspan=2)
    class_label1.grid(column=0, row=2)
    class_label2.grid(column=2, row=2)
    class_radio1.grid(column=1, row=2)
    class_radio2.grid(column=3, row=2)
    confirm_label.grid(column=1, row=3)
    confirm_check.grid(column=2, row=3)
    send_email_button.grid(columnspan=2, column=1, row=4)


def class_list_view():
    global emails1, emails2, v, student_view

    def update_txt():
        items = student_view.get(0, 'end')
        if v.get() == 2:
            data1 = open(os.path.join(__location__, 'students2.txt'), mode='w')
            first = True
            for item in items:
                if first:
                    data1.write(item)
                    first = False
                else:
                    data1.write('\n' + item)
            data1.close()
        if v.get() == 1:
            data1 = open(os.path.join(__location__, 'students1.txt'), mode='w')
            first = True
            for item in items:
                if first:
                    data1.write(item)
                    first = False
                else:
                    data1.write('\n' + item)
            data1.close()

    def check_email():
        email = add_student_entry.get()
        if re.match(r'\w+@\w+.\w+', email) is not None:
            add_student()
            add_student_label['text'] = 'Add new student Email:'
            update_txt()
        else:
            add_student_label['text'] = 'EMAIL FORMAT INVALID'

    def delete_student():
        student_view.delete('active')
        update_txt()

    def add_student():
        if v.get() == 2:
            emails2_curr = emails2.get()
            emails2_curr = list(emails2_curr)
            emails2_curr.append(add_student_entry.get())
            emails2.set(emails2_curr)
            add_student_entry.delete(0, 'end')
        if v.get() == 1:
            emails1_curr = emails1.get()
            emails1_curr = list(emails1_curr)
            emails1_curr.append(add_student_entry.get())
            emails1.set(emails1_curr)
            add_student_entry.delete(0, 'end')

    def assign_class():
        if v.get() == 2:
            student_view['listvariable'] = emails2
        elif v.get() == 1:
            student_view['listvariable'] = emails1

    class_list = Toplevel()
    class_list.title("View/Edit Class Lists")
    class_list.geometry('400x200-680+300')
    class_list.grab_set()
    class_list.lift(root)

    student_frame = ttk.Frame(class_list)
    student_view = Listbox(student_frame, height=10, width=30)
    class1 = Radiobutton(student_frame, text='Class 1', var=v, value=1, command=assign_class)
    class2 = Radiobutton(student_frame, text='Class 2', var=v, value=2, command=assign_class)
    add_student_label = Label(student_frame, text='Add new student Email:')
    add_student_entry = Entry(student_frame, width=30)
    add_student_button = Button(student_frame, text='Add', command=check_email)
    delete_student_button = Button(student_frame, text='Delete', command=delete_student)

    add_student_entry.grid(column=2, row=1, sticky=N)
    add_student_label.grid(column=2, row=0, sticky=(N, E, W))
    add_student_button.grid(column=2, row=2)
    delete_student_button.grid(column=2, row=3)
    student_frame.grid(column=0, row=0, sticky=(N, S, E, W))
    student_view.grid(column=3, row=0, columnspan=3, rowspan=8, sticky=(N, W, S, E))
    class1.grid(column=3, row=8)
    class2.grid(column=4, row=8)


root = Tk()
root.title("Dr. Emailio Robotus")
root.geometry('600x700-670+120')
root.minsize(400, 500)

v = IntVar()
p = IntVar()
z = IntVar()

t1 = StringVar()
t2 = StringVar()
t3 = StringVar()
t4 = StringVar()
t5 = StringVar()
t6 = StringVar()
t7 = StringVar()
t8 = StringVar()
t9 = StringVar()
t10 = StringVar()
t11 = StringVar()
t12 = StringVar()
t13 = StringVar()

# data = open('students1.txt', encoding='utf-8')
data = open(os.path.join(__location__, 'students1.txt'))
emails = data.read()
emails1 = emails.split('\n')
emails1 = Variable(value=emails1)
data.close()

data = open(os.path.join(__location__, 'students2.txt'))
emails = data.read()
emails2 = emails.split('\n')
emails2 = Variable(value=emails2)
data.close()

mainframe = ttk.Frame(root, padding="5", borderwidth=5, relief='solid')

this_lab_name = ttk.Entry(mainframe, width=50, background='grey', textvariable=t1)
this_lab_name_label = Label(mainframe, text='This week\'s lab name:')

zoom_date_time = ttk.Entry(mainframe, width=50, background='grey', textvariable=t2)
zoom_date_time_label = Label(mainframe, text='This week\'s Zoom meeting (date/time):')

zoom_link = ttk.Entry(mainframe, width=50, background='grey', textvariable=t3)
zoom_link_label = Label(mainframe, text='This week\'s Zoom link:')

zoom_ID = ttk.Entry(mainframe, width=50, background='grey', textvariable=t4)
zoom_ID_label = Label(mainframe, text='This week\'s Zoom meeting ID:')

zoom_passcode = ttk.Entry(mainframe, width=50, background='grey', textvariable=t5)
zoom_passcode_label = Label(mainframe, text='This week\'s Zoom meeting passcode:')

this_lab_supplemental = ttk.Entry(mainframe, width=50, background='grey', textvariable=t6)
this_lab_supplemental_label = Label(mainframe, text='This week\'s lab\'s supplemental questions:')

this_lab_consisting = ttk.Entry(mainframe, width=50, background='grey', textvariable=t7)
this_lab_consisting_label = Label(mainframe, text='This week\'s lab should be consisting of:')

this_lab_due = ttk.Entry(mainframe, width=50, background='grey', textvariable=t8)
this_lab_due_label = Label(mainframe, text='This week\'s lab is due (date/time):')

file_name_tag = ttk.Entry(mainframe, width=50, background='grey', textvariable=t9)
file_name_tag_label = Label(mainframe, text='This week\'s lab naming format (Aspirin/Hess):')

last_lab_reminder = ttk.Entry(mainframe, width=50, background='grey', textvariable=t10)
last_lab_reminder_label = Label(mainframe, text='Last week\'s lab name:')

last_lab_due = ttk.Entry(mainframe, width=50, background='grey', textvariable=t11)
last_lab_due_label = Label(mainframe, text='Last week\'s lab is due (date/time):')

last_lab_supplemental = ttk.Entry(mainframe, width=50, background='grey', textvariable=t12)
last_lab_supplemental_label = Label(mainframe, text='Last week\'s lab\'s supplemental questions:')

last_file_name_tag = ttk.Entry(mainframe, width=50, background='grey', textvariable=t13)
last_file_name_tag_label = Label(mainframe, text='Last week\'s lab naming format (Aspirin/Hess):')

compile_button = Button(mainframe, text='Compile Email', command=format_email, width=25)
view_email_button = Button(mainframe, text='View Email', state='disabled', command=display_email, width=25)

classes_button = Button(mainframe, text='View/Modify Class List', command=class_list_view, width=18)

send_button = Button(mainframe, text='Send Email...', width=18, state='disabled', command=send_email)

mainframe.grid(column=0, row=0, sticky=(N, S, E, W))

this_lab_name.grid(column=1, row=0, sticky=E, padx=3, pady=3)
this_lab_name_label.grid(column=0, row=0, sticky=W, padx=3, pady=3)

zoom_date_time.grid(column=1, row=1, sticky=E, padx=3, pady=3)
zoom_date_time_label.grid(column=0, row=1, sticky=W, padx=3, pady=3)

zoom_link.grid(column=1, row=2, sticky=E, padx=3, pady=3)
zoom_link_label.grid(column=0, row=2, sticky=W, padx=3, pady=3)

zoom_ID.grid(column=1, row=3, sticky=E, padx=3, pady=3)
zoom_ID_label.grid(column=0, row=3, sticky=W, padx=3, pady=3)

zoom_passcode.grid(column=1, row=4, sticky=E, padx=3, pady=3)
zoom_passcode_label.grid(column=0, row=4, sticky=W, padx=3, pady=3)

this_lab_supplemental.grid(column=1, row=5, sticky=E, padx=3, pady=3)
this_lab_supplemental_label.grid(column=0, row=5, sticky=W, padx=3, pady=3)

this_lab_consisting.grid(column=1, row=6, sticky=E, padx=3, pady=3)
this_lab_consisting_label.grid(column=0, row=6, sticky=W, padx=3, pady=3)

this_lab_due.grid(column=1, row=7, sticky=E, padx=3, pady=3)
this_lab_due_label.grid(column=0, row=7, sticky=W, padx=3, pady=3)

file_name_tag.grid(column=1, row=8, sticky=E, padx=3, pady=3)
file_name_tag_label.grid(column=0, row=8, sticky=W, padx=3, pady=3)

last_lab_reminder.grid(column=1, row=9, sticky=E, padx=3, pady=3)
last_lab_reminder_label.grid(column=0, row=9, sticky=W, padx=3, pady=3)

last_lab_due.grid(column=1, row=10, sticky=E, padx=3, pady=3)
last_lab_due_label.grid(column=0, row=10, sticky=W, padx=3, pady=3)

last_lab_supplemental.grid(column=1, row=11, sticky=E, padx=3, pady=3)
last_lab_supplemental_label.grid(column=0, row=11, sticky=W, padx=3, pady=3)

last_file_name_tag.grid(column=1, row=12, sticky=E, padx=3, pady=3)
last_file_name_tag_label.grid(column=0, row=12, sticky=W, padx=3, pady=3)

compile_button.grid(column=0, row=13, columnspan=2, padx=3, pady=3)
view_email_button.grid(column=0, row=14, columnspan=2, padx=3, pady=3)
classes_button.grid(row=15, column=0, columnspan=2, padx=3, pady=3)
send_button.grid(row=16, column=0, columnspan=2, padx=3, pady=3)

root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
# mainframe.rowconfigure(0, weight=1)
# mainframe.columnconfigure(0, weight=1)
# mainframe.rowconfigure(0, weight=1)
# mainframe.columnconfigure(0, weight=1)


if __name__ == '__main__':
    root.mainloop()

请尝试下面的
spec
文件。我刚刚将属性
console=True
更改为
console=False
请注意,现在需要运行
pyinstaller main.spec
而不是
pyinstaller main.py

如果您不想使用此规范文件,而只想从脚本执行此操作,请在运行
pyinstaller main.py
时在命令中添加
--noconsole
--windowed

例如
pyinstaller main.py--noconsole

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None


a = Analysis(['__main__.py'],
             pathex=['C:\\Users\\wiley\\PycharmProjects\\EmailBot\\email_bot'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='__main__',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=False)
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='__main__')

请尝试下面的
spec
文件。我刚刚将属性
console=True
更改为
console=False
请注意,现在需要运行
pyinstaller main.spec
而不是
pyinstaller main.py

如果您不想使用此规范文件,而只想从脚本执行此操作,请在运行
pyinstaller main.py
时在命令中添加
--noconsole
--windowed

例如
pyinstaller main.py--noconsole

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None


a = Analysis(['__main__.py'],
             pathex=['C:\\Users\\wiley\\PycharmProjects\\EmailBot\\email_bot'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='__main__',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=False)
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='__main__')

按照给出的建议,我能够让程序运行。我必须更改.spec文件,特别是数据字段,以使其正常工作


然而,我当时遇到了一个问题,即.txt文件将加载到程序中,但编辑它们后,编辑内容没有按应有的方式保存。解决方案:我没有将文件置于“w”模式,这就是为什么我没有得到任何文本文件的输出。现在一切都好了!谢谢大家的帮助。我已经更新了上面的文件,以反映最终的工作版本

按照给出的建议,我能够让程序运行。我必须更改.spec文件,特别是数据字段,以使其正常工作


然而,我当时遇到了一个问题,即.txt文件将加载到程序中,但编辑它们后,编辑内容没有按应有的方式保存。解决方案:我没有将文件置于“w”模式,这就是为什么我没有得到任何文本文件的输出。现在一切都好了!谢谢大家的帮助。我已更新了上述文件,以反映最终工作版本

感谢您的快速响应。我使用了您上面提供的spec文件,现在当我运行.exe时,我会看到一个小弹出窗口,上面显示:“检测到致命错误:无法执行脚本main”。但是,当我从CMD行运行.exe时,程序仍然运行良好。我在这里为您编写了替代说明。。因为SO对注释有字符限制。我会把它添加到我的答案中,如果它有效的话。我遵循了所有的说明,在CMD中一切都很好。但是,我在尝试运行dist文件夹中的.exe时仍然会遇到相同的错误:“检测到致命错误:无法执行脚本main”只有当我的CMD与我的所有文件位于同一文件夹(用于生成.exe的文件夹)中时,我才能运行dist.exe。如果我尝试在build文件夹中运行.exe,我会得到一个弹出窗口,上面显示“检测到致命错误:加载Python DLL时出错…LoadLibrary:找不到指定的模块”@wileyrivers现在我无法解释为什么它不起作用。如果你能提供脚本,我会看看是否能创建一个独立的。如果我能够,这个问题可能与
pyi
安装或
setuptools
有关。在上面@acw1668的评论之后,我能够使它正常工作,我刚刚在快速响应的输出储蓄方面遇到了问题。我使用了您上面提供的spec文件,现在当我运行.exe时,我会看到一个小弹出窗口,上面显示:“检测到致命错误:无法执行脚本main”。但是,当我从CMD行运行.exe时,程序仍然运行良好。我在这里为您编写了替代说明。。因为SO对注释有字符限制。我会把它添加到我的答案中,如果它有效的话。我遵循了所有的说明,在CMD中一切都很好。但是,我在尝试运行dist文件夹中的.exe时仍然会遇到相同的错误:“检测到致命错误:无法执行脚本main”只有当我的CMD与我的所有文件位于同一文件夹(用于生成.exe的文件夹)中时,我才能运行dist.exe。如果我尝试在build文件夹中运行.exe,我会得到一个弹出窗口,上面显示“检测到致命错误:加载Python DLL时出错…LoadLibrary:找不到指定的模块”@wileyrivers现在我无法解释为什么它不起作用。如果你能提供脚本,我会看看是否能创建一个独立的。如果我不能