Изображение Python Gif внутри графического интерфейса Tkinter. С помощью Pyinstaller, как его настроить? [Дубликат]

NullPointerException s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException. Они наиболее распространены, но другие способы перечислены на странице NullPointerException javadoc.

Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException, be:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

В первой строке внутри main я явно устанавливаю ссылку Object obj равной null. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.

(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)

66
задан arboreal shark 21 August 2014 в 09:39
поделиться

7 ответов

Новые версии PyInstaller больше не устанавливают переменную env, поэтому отличный ответ Shish не будет работать. Теперь путь устанавливается как sys._MEIPASS:

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)
95
ответ дан Community 18 August 2018 в 16:12
поделиться
  • 1
    Я использую pyinstaller 2 с python 2.7, и у меня нет _MEIPASS2 в envs, но sys._MEIPASS работает хорошо, поэтому +1. Я предлагаю: path = getattr(sys, '_MEIPASS', os.getcwd()) – kbec 28 February 2013 в 16:22
  • 2
    +1. Спасибо за это. Пытаясь использовать переменную среды _MEIPASS2 некоторое время, очевидно, я написал свой код, когда он все еще был переменной окружения, потому что я помню, как он работает. Внезапно, это прекратилось, когда я перекомпилировал недавно. – Favil Orbedios 21 June 2013 в 00:16
  • 3
    Я бы рекомендовал поймать AttributeError вместо более общего Exception. Я столкнулся с проблемами, когда мне не хватало импорт sys, а путь молча отключился до os.path.abspath. – Aaron 9 February 2016 в 02:00
  • 4
    Возможно, вы сможете решить мою проблему . – Phillip 10 December 2016 в 22:13
  • 5
    С PyInstaller 3.2 кажется, что установщик создает поддиректорию с именем файла (например, images/background.png попадает в images/background.png/background.png) (каталог с именем файла). Не уверен, что этот код учитывает это; Я добавил изменение, которое делает, но я все еще получаю крах при доступе к ресурсам. – ashes999 18 December 2016 в 05:41

Я обнаружил, что существующие ответы сбивают с толку, и потребовалось много времени, чтобы решить, где проблема. Вот компиляция всего, что я нашел.

Когда я запускаю свое приложение, я получаю сообщение об ошибке Failed to execute script foo (если foo.py является основным файлом). Чтобы устранить эту проблему, не запускайте PyInstaller с помощью --noconsole (или отредактируйте main.spec, чтобы изменить console=False => console=True). При этом запустите исполняемый файл из командной строки, и вы увидите сбой.

Первое, что нужно проверить, это то, что он правильно упаковывает ваши лишние файлы. Вы должны добавить кортежи, такие как ('x', 'x'), если вы хотите включить папку x.

После сбоя не нажимайте OK. Если вы находитесь в Windows, вы можете использовать Искать все . Найдите один из ваших файлов (например, sword.png). Вы должны найти временный путь, где он распаковал файлы (например, C:\Users\ashes999\AppData\Local\Temp\_MEI157682\images\sword.png). Вы можете просмотреть этот каталог и убедиться, что он включает все. Если вы не можете найти его таким образом, найдите что-то вроде main.exe.manifest (Windows) или python35.dll (если вы используете Python 3.5).

Если программа установки включает все, следующая вероятная Проблема - это ввод-вывод файлов: ваш код Python ищет в каталоге исполняемого файла вместо каталога temp для файлов.

Чтобы исправить это, любой из ответов на этот вопрос работает. Лично я нашел смесь из них всех, чтобы работать: сначала замените каталог в главном файле точки входа, а все остальное работает как есть:

if hasattr(sys, '_MEIPASS'): os.chdir(sys._MEIPASS)

0
ответ дан ashes999 18 August 2018 в 16:12
поделиться
  • 1
    Сожалею. Но изменение каталогов никогда не будет правильным ответом. Если пользователь предоставляет путь к приложению, он ожидает, что он будет относиться к текущему каталогу. Если вы измените это, это будет неправильно. – Jonathon Reinhart 5 September 2017 в 23:29

Вместо того, чтобы переписать весь мой код пути, как было предложено, я сменил рабочий каталог:

if getattr(sys, 'frozen', False):
    os.chdir(sys._MEIPASS)

Просто добавьте эти две строки в начале вашего кода, вы можете оставить остальные как есть.

5
ответ дан Bobsleigh 18 August 2018 в 16:12
поделиться
  • 1
    Нет. Хорошие приложения редко должны менять рабочий каталог. Есть лучшие способы. – Jonathon Reinhart 4 June 2017 в 10:08

Возможно, я пропустил шаг или сделал что-то не так, но методы, которые выше, не связывают файлы данных с PyInstaller в один файл exe. Позвольте мне поделиться шагами, которые я сделал.

  1. step: запишите один из вышеуказанных методов в ваш файл py с импортом модулей sys и os. Я попробовал их обоих. Последним является:
    def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
        base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
        return os.path.join(base_path, relative_path)
    
  2. step: напишите, pyi-makepec file.py , на консоль, чтобы создать файл file.spec.
  3. : Откройте файл file.spec с помощью Notepad ++, чтобы добавить файлы данных, как показано ниже:
    a = Analysis(['C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.py'],
                 pathex=['C:\\Users\\TCK\\Desktop\\Projeler'],
                 binaries=[],
                 datas=[],
                 hiddenimports=[],
                 hookspath=[],
                 runtime_hooks=[],
                 excludes=[],
                 win_no_prefer_redirects=False,
                 win_private_assemblies=False,
                 cipher=block_cipher)
    #Add the file like the below example
    a.datas += [('Converter-GUI.ico', 'C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico', 'DATA')]
    pyz = PYZ(a.pure, a.zipped_data,
         cipher=block_cipher)
    exe = EXE(pyz,
              a.scripts,
              exclude_binaries=True,
              name='Converter-GUI',
              debug=False,
              strip=False,
              upx=True,
              #Turn the console option False if you don't want to see the console while executing the program.
              console=False,
              #Add an icon to the program.
              icon='C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico')
    
    coll = COLLECT(exe,
                   a.binaries,
                   a.zipfiles,
                   a.datas,
                   strip=False,
                   upx=True,
                   name='Converter-GUI')
    
  4. step: я выполнил указанные шаги, а затем сохранил спецификационный файл. Наконец, он открыл консоль и написал pyinstaller file.spec (в моем случае, файл = конвертер-GUI).

Заключение: Есть еще несколько файлов в папке dist.

Примечание: я использую Python 3.5.

EDIT: Наконец, он работает с методом Джонатана Рейнхарта.

  1. : добавьте приведенные ниже коды в файл python с импортом sys и os.
    def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
        base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
        return os.path.join(base_path, relative_path)
    
  2. step: Вызвать вышеуказанную функцию с добавлением пути к вашему файлу:
    image_path = resource_path("Converter-GUI.ico")
    
  3. step: записать вышеперечисленную переменную, которая вызывает функцию, где ваши коды нуждаются в дорожка. В моем случае это:
        self.window.iconbitmap(image_path)
    
  4. step: откройте консоль в той же папке вашего файла python, напишите коды, как показано ниже:
        pyinstaller --onefile your_file.py
    
  5. step: откройте. spec файла файла python и добавьте массив a.datas и добавьте значок в класс exe, который был указан выше перед редактированием на 3-м шаге.
  6. step: Сохранить и выйти из файла пути , Перейдите в папку, в которую входят файл spec и py. Откройте снова окно консоли и введите следующую команду:
        pyinstaller your_file.spec
    

После 6 шага ваш один файл готов к использованию.

5
ответ дан dilde olupbiten 18 August 2018 в 16:12
поделиться
  • 1
    Спасибо @dilde! Не то, чтобы массив a.datas с шага 5 брал кортежи строк, см. pythonhosted.org/PyInstaller/spec-files.html#adding-data-files для справки. – Ian Campbell 5 September 2017 в 17:55
  • 2
    Извините, я не могу понять часть вашего сообщения, а я хочу из-за моего слабого английского. Эта часть «Не то, что a.datas ....» , вы хотели бы написать 'Обратите внимание, что a.datas ... & quot; что-то не так с тем, что я написал о добавлении строк в массив a.datas? – dilde olupbiten 5 September 2017 в 18:23
  • 3
    К сожалению! Это должно быть Обратите внимание, что ... ya, извините за опечатку. Ваши шаги отлично поработали для меня :), я не смог найти эту информацию в своей документации или в другом месте. – Ian Campbell 5 September 2017 в 18:27
  • 4
    О, я счастлив, это решило вашу проблему. :) – dilde olupbiten 5 September 2017 в 18:31

Все остальные ответы используют текущий рабочий каталог в случае, когда приложение не установлено PyInstalled (т. е. sys._MEIPASS не установлено). Это неправильно, так как это мешает вам запускать приложение из каталога, отличного от того, где находится ваш скрипт.

Лучшее решение:

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)
8
ответ дан Jonathon Reinhart 18 August 2018 в 16:12
поделиться
  • 1
    Спасибо, Jon, ваша функция помогла мне сегодня решить проблему. У меня просто вопрос. Почему некоторые пишут _MEIPASS2 вместо _MEIPASS? Когда я попытался добавить 2 раньше, это не сработало. – Ahmed AbdelKhalek 5 January 2018 в 22:39
  • 2
    Я думаю, что os.env['_MEIPASS2'] (с использованием среды ОС) был старым способом получения каталога. AFAIK sys._MEIPASS - единственный правильный метод. – Jonathon Reinhart 5 January 2018 в 22:50
  • 3

Незначительное изменение принятого ответа.

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)

    return os.path.join(os.path.abspath("."), relative_path)
2
ответ дан Krishna Balan 18 August 2018 в 16:12
поделиться
  • 1
    Использование текущего рабочего каталога в случае, когда _MEIPASS не задано, неверно. См. мой ответ . – Jonathon Reinhart 4 June 2017 в 10:09

pyinstaller распаковывает ваши данные во временную папку и сохраняет этот путь к каталогу в переменной среды _MEIPASS2. Чтобы получить директорию _MEIPASS2 в упакованном режиме и использовать локальный каталог в режиме распаковки (разработки), я использую это:

def resource_path(relative):
    return os.path.join(
        os.environ.get(
            "_MEIPASS2",
            os.path.abspath(".")
        ),
        relative
    )

Выход:

# in development
>>> resource_path("app_icon.ico")
"/home/shish/src/my_app/app_icon.ico"

# in production
>>> resource_path("app_icon.ico")
"/tmp/_MEI34121/app_icon.ico"
49
ответ дан Omar Einea 18 August 2018 в 16:12
поделиться
  • 1
    Как, когда и где можно использовать это? – gseattle 14 July 2012 в 16:02
  • 2
    Вы должны использовать этот скрипт в файле .py, который вы пытаетесь скомпилировать с помощью PyInstaller. Не помещайте этот фрагмент кода в файл .spec, который не будет работать. Получите доступ к своим файлам, заменив путь, который вы обычно набираете, resource_path("file_to_be_accessed.mp3"). Будьте осторожны, чтобы использовать максимальный ответ для текущей версии PyInstaller. – Exeleration-G 18 April 2013 в 11:07
  • 3
    Является ли этот ответ конкретным для использования опции --one-file? – fatuhoku 9 October 2013 в 13:53
  • 4
    Возможно, вы сможете решить мою проблему . – Phillip 10 December 2016 в 22:13
  • 5
    Использование текущего рабочего каталога в случае, когда _MEIPASS не задано, неверно. См. мой ответ . – Jonathon Reinhart 4 June 2017 в 10:08
Другие вопросы по тегам:

Похожие вопросы: