Приложение-конфигуратор добавлено в проект
This commit is contained in:
parent
2fc1bc5fe1
commit
52137c1a9c
39
Tools/Configapp/FeeshkaConfig v2.spec
Normal file
39
Tools/Configapp/FeeshkaConfig v2.spec
Normal file
@ -0,0 +1,39 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['main.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='FeeshkaConfig v2',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=['C:\\Users\\Programmer\\Desktop\\Fishka_config\\chipCatana.ico'],
|
||||
)
|
||||
BIN
Tools/Configapp/__pycache__/config.cpython-310.pyc
Normal file
BIN
Tools/Configapp/__pycache__/config.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Tools/Configapp/app.ico
Normal file
BIN
Tools/Configapp/app.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 73 KiB |
5079
Tools/Configapp/build/FeeshkaConfig v2/Analysis-00.toc
Normal file
5079
Tools/Configapp/build/FeeshkaConfig v2/Analysis-00.toc
Normal file
File diff suppressed because it is too large
Load Diff
3162
Tools/Configapp/build/FeeshkaConfig v2/EXE-00.toc
Normal file
3162
Tools/Configapp/build/FeeshkaConfig v2/EXE-00.toc
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Tools/Configapp/build/FeeshkaConfig v2/FeeshkaConfig v2.pkg
Normal file
BIN
Tools/Configapp/build/FeeshkaConfig v2/FeeshkaConfig v2.pkg
Normal file
Binary file not shown.
3140
Tools/Configapp/build/FeeshkaConfig v2/PKG-00.toc
Normal file
3140
Tools/Configapp/build/FeeshkaConfig v2/PKG-00.toc
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Tools/Configapp/build/FeeshkaConfig v2/PYZ-00.pyz
Normal file
BIN
Tools/Configapp/build/FeeshkaConfig v2/PYZ-00.pyz
Normal file
Binary file not shown.
1511
Tools/Configapp/build/FeeshkaConfig v2/PYZ-00.toc
Normal file
1511
Tools/Configapp/build/FeeshkaConfig v2/PYZ-00.toc
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Tools/Configapp/build/FeeshkaConfig v2/base_library.zip
Normal file
BIN
Tools/Configapp/build/FeeshkaConfig v2/base_library.zip
Normal file
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 139 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Tools/Configapp/build/FeeshkaConfig v2/localpycs/struct.pyc
Normal file
BIN
Tools/Configapp/build/FeeshkaConfig v2/localpycs/struct.pyc
Normal file
Binary file not shown.
167
Tools/Configapp/build/FeeshkaConfig v2/warn-FeeshkaConfig v2.txt
Normal file
167
Tools/Configapp/build/FeeshkaConfig v2/warn-FeeshkaConfig v2.txt
Normal file
@ -0,0 +1,167 @@
|
||||
|
||||
This file lists modules PyInstaller was not able to find. This does not
|
||||
necessarily mean this module is required for running your program. Python and
|
||||
Python 3rd-party packages include a lot of conditional or optional modules. For
|
||||
example the module 'ntpath' only exists on Windows, whereas the module
|
||||
'posixpath' only exists on Posix systems.
|
||||
|
||||
Types if import:
|
||||
* top-level: imported at the top-level - look at these first
|
||||
* conditional: imported within an if-statement
|
||||
* delayed: imported within a function
|
||||
* optional: imported within a try-except-statement
|
||||
|
||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||
tracking down the missing module yourself. Thanks!
|
||||
|
||||
missing module named pwd - imported by shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional), posixpath (delayed, conditional), http.server (delayed, optional), webbrowser (delayed), netrc (delayed, conditional), getpass (delayed)
|
||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional)
|
||||
missing module named _posixsubprocess - imported by subprocess (optional), multiprocessing.util (delayed)
|
||||
missing module named fcntl - imported by subprocess (optional)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named pep517 - imported by importlib.metadata (delayed)
|
||||
missing module named org - imported by pickle (optional)
|
||||
missing module named posix - imported by shutil (conditional), importlib._bootstrap_external (conditional), os (conditional, optional)
|
||||
missing module named resource - imported by posix (top-level)
|
||||
missing module named 'org.python' - imported by copy (optional), xml.sax (delayed, conditional)
|
||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named termios - imported by tty (top-level), getpass (optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional), xml.sax._exceptions (conditional)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named pyimod02_importers - imported by C:\Users\Programmer\AppData\Local\Programs\Python\Python310\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
|
||||
missing module named annotationlib - imported by typing_extensions (conditional)
|
||||
missing module named _dummy_thread - imported by numpy.core.arrayprint (optional)
|
||||
missing module named psutil - imported by numpy.testing._private.utils (delayed, optional)
|
||||
missing module named win32evtlog - imported by logging.handlers (delayed, optional)
|
||||
missing module named win32evtlogutil - imported by logging.handlers (delayed, optional)
|
||||
missing module named startup - imported by pyreadline3.keysyms.common (conditional), pyreadline3.keysyms.keysyms (conditional)
|
||||
missing module named sets - imported by pyreadline3.keysyms.common (optional)
|
||||
missing module named System - imported by pyreadline3.clipboard.ironpython_clipboard (top-level), pyreadline3.keysyms.ironpython_keysyms (top-level), pyreadline3.console.ironpython_console (top-level), pyreadline3.rlmain (conditional)
|
||||
missing module named console - imported by pyreadline3.console.ansi (conditional)
|
||||
missing module named clr - imported by pyreadline3.clipboard.ironpython_clipboard (top-level), pyreadline3.console.ironpython_console (top-level)
|
||||
missing module named IronPythonConsole - imported by pyreadline3.console.ironpython_console (top-level)
|
||||
missing module named numpy.core.result_type - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.float_ - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.number - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.object_ - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.max - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.all - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.errstate - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.bool_ - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.inf - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.isnan - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.array2string - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.imag - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.real - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.iscomplexobj - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.signbit - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.isscalar - imported by numpy.core (delayed), numpy.testing._private.utils (delayed), numpy.lib.polynomial (top-level)
|
||||
missing module named win32pdh - imported by numpy.testing._private.utils (delayed, conditional)
|
||||
missing module named numpy.core.array - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.isnat - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.ndarray - imported by numpy.core (top-level), numpy.testing._private.utils (top-level), numpy.lib.utils (top-level)
|
||||
missing module named numpy.core.array_repr - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.arange - imported by numpy.core (top-level), numpy.testing._private.utils (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.empty - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.float32 - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.intp - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named java - imported by platform (delayed)
|
||||
missing module named _winreg - imported by platform (delayed, optional)
|
||||
missing module named numpy.core.linspace - imported by numpy.core (top-level), numpy.lib.index_tricks (top-level)
|
||||
missing module named numpy.core.iinfo - imported by numpy.core (top-level), numpy.lib.twodim_base (top-level)
|
||||
missing module named numpy.core.transpose - imported by numpy.core (top-level), numpy.lib.function_base (top-level)
|
||||
missing module named numpy.uint - imported by numpy (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.core.asarray - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.utils (top-level), numpy.fft._pocketfft (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.integer - imported by numpy.core (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.sqrt - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.conjugate - imported by numpy.core (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.swapaxes - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.zeros - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.reciprocal - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.sort - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.argsort - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.sign - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.count_nonzero - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.divide - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.matmul - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.asanyarray - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.atleast_2d - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.prod - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.amax - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.amin - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.moveaxis - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.geterrobj - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.finfo - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.isfinite - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.sum - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.multiply - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.add - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.dot - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.Inf - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.newaxis - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.complexfloating - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.inexact - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.cdouble - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.csingle - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.double - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.single - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.intc - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.empty_like - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named pyodide_js - imported by threadpoolctl (delayed, optional)
|
||||
missing module named numpy.core.ufunc - imported by numpy.core (top-level), numpy.lib.utils (top-level)
|
||||
missing module named numpy.core.ones - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.hstack - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.atleast_1d - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.atleast_3d - imported by numpy.core (top-level), numpy.lib.shape_base (top-level)
|
||||
missing module named numpy.core.vstack - imported by numpy.core (top-level), numpy.lib.shape_base (top-level)
|
||||
missing module named pickle5 - imported by numpy.compat.py3k (optional)
|
||||
missing module named numpy.eye - imported by numpy (delayed), numpy.core.numeric (delayed)
|
||||
missing module named numpy.recarray - imported by numpy (top-level), numpy.lib.recfunctions (top-level), numpy.ma.mrecords (top-level)
|
||||
missing module named numpy.expand_dims - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.array - imported by numpy (top-level), numpy.ma.core (top-level), numpy.ma.extras (top-level), numpy.ma.mrecords (top-level)
|
||||
missing module named numpy.iscomplexobj - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.amin - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.amax - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.isinf - imported by numpy (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.isnan - imported by numpy (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.isfinite - imported by numpy (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.float64 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.float32 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.uint64 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._philox (top-level), numpy.random._sfc64 (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.uint32 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._generator (top-level), numpy.random._mt19937 (top-level)
|
||||
missing module named numpy.uint16 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.uint8 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int64 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int32 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int16 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int8 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.bytes_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.str_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.void - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.object_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.datetime64 - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.timedelta64 - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.number - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.complexfloating - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.floating - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.integer - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.unsignedinteger - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.bool_ - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ma.core (top-level), numpy.ma.mrecords (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.generic - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.dtype - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.array_api._typing (top-level), numpy.ma.mrecords (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._philox (top-level), numpy.random._sfc64 (top-level), numpy.random._generator (top-level), numpy.random._mt19937 (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.ndarray - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ma.core (top-level), numpy.ma.extras (top-level), numpy.lib.recfunctions (top-level), numpy.ma.mrecords (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._philox (top-level), numpy.random._sfc64 (top-level), numpy.random._generator (top-level), numpy.random._mt19937 (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.ufunc - imported by numpy (top-level), numpy._typing (top-level), numpy.testing.overrides (top-level)
|
||||
missing module named numpy.histogramdd - imported by numpy (delayed), numpy.lib.twodim_base (delayed)
|
||||
missing module named numpy._distributor_init_local - imported by numpy (optional), numpy._distributor_init (optional)
|
||||
missing module named numpy._typing._ufunc - imported by numpy._typing (conditional)
|
||||
missing module named olefile - imported by PIL.FpxImagePlugin (top-level), PIL.MicImagePlugin (top-level)
|
||||
missing module named defusedxml - imported by PIL.Image (optional)
|
||||
21559
Tools/Configapp/build/FeeshkaConfig v2/xref-FeeshkaConfig v2.html
Normal file
21559
Tools/Configapp/build/FeeshkaConfig v2/xref-FeeshkaConfig v2.html
Normal file
File diff suppressed because it is too large
Load Diff
5081
Tools/Configapp/build/main/Analysis-00.toc
Normal file
5081
Tools/Configapp/build/main/Analysis-00.toc
Normal file
File diff suppressed because it is too large
Load Diff
3154
Tools/Configapp/build/main/EXE-00.toc
Normal file
3154
Tools/Configapp/build/main/EXE-00.toc
Normal file
File diff suppressed because it is too large
Load Diff
3132
Tools/Configapp/build/main/PKG-00.toc
Normal file
3132
Tools/Configapp/build/main/PKG-00.toc
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Tools/Configapp/build/main/PYZ-00.pyz
Normal file
BIN
Tools/Configapp/build/main/PYZ-00.pyz
Normal file
Binary file not shown.
1513
Tools/Configapp/build/main/PYZ-00.toc
Normal file
1513
Tools/Configapp/build/main/PYZ-00.toc
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Tools/Configapp/build/main/base_library.zip
Normal file
BIN
Tools/Configapp/build/main/base_library.zip
Normal file
Binary file not shown.
BIN
Tools/Configapp/build/main/localpycs/pyimod01_archive.pyc
Normal file
BIN
Tools/Configapp/build/main/localpycs/pyimod01_archive.pyc
Normal file
Binary file not shown.
BIN
Tools/Configapp/build/main/localpycs/pyimod02_importers.pyc
Normal file
BIN
Tools/Configapp/build/main/localpycs/pyimod02_importers.pyc
Normal file
Binary file not shown.
BIN
Tools/Configapp/build/main/localpycs/pyimod03_ctypes.pyc
Normal file
BIN
Tools/Configapp/build/main/localpycs/pyimod03_ctypes.pyc
Normal file
Binary file not shown.
BIN
Tools/Configapp/build/main/localpycs/pyimod04_pywin32.pyc
Normal file
BIN
Tools/Configapp/build/main/localpycs/pyimod04_pywin32.pyc
Normal file
Binary file not shown.
BIN
Tools/Configapp/build/main/localpycs/struct.pyc
Normal file
BIN
Tools/Configapp/build/main/localpycs/struct.pyc
Normal file
Binary file not shown.
BIN
Tools/Configapp/build/main/main.pkg
Normal file
BIN
Tools/Configapp/build/main/main.pkg
Normal file
Binary file not shown.
167
Tools/Configapp/build/main/warn-main.txt
Normal file
167
Tools/Configapp/build/main/warn-main.txt
Normal file
@ -0,0 +1,167 @@
|
||||
|
||||
This file lists modules PyInstaller was not able to find. This does not
|
||||
necessarily mean this module is required for running your program. Python and
|
||||
Python 3rd-party packages include a lot of conditional or optional modules. For
|
||||
example the module 'ntpath' only exists on Windows, whereas the module
|
||||
'posixpath' only exists on Posix systems.
|
||||
|
||||
Types if import:
|
||||
* top-level: imported at the top-level - look at these first
|
||||
* conditional: imported within an if-statement
|
||||
* delayed: imported within a function
|
||||
* optional: imported within a try-except-statement
|
||||
|
||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||
tracking down the missing module yourself. Thanks!
|
||||
|
||||
missing module named pwd - imported by posixpath (delayed, conditional), subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), http.server (delayed, optional), webbrowser (delayed), netrc (delayed, conditional), getpass (delayed)
|
||||
missing module named grp - imported by subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional)
|
||||
missing module named _posixsubprocess - imported by subprocess (optional), multiprocessing.util (delayed)
|
||||
missing module named fcntl - imported by subprocess (optional)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named pep517 - imported by importlib.metadata (delayed)
|
||||
missing module named org - imported by pickle (optional)
|
||||
missing module named posix - imported by os (conditional, optional), shutil (conditional), importlib._bootstrap_external (conditional)
|
||||
missing module named resource - imported by posix (top-level)
|
||||
missing module named 'org.python' - imported by copy (optional), xml.sax (delayed, conditional)
|
||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named termios - imported by tty (top-level), getpass (optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional), xml.sax._exceptions (conditional)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named pyimod02_importers - imported by C:\Users\Programmer\AppData\Local\Programs\Python\Python310\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
|
||||
missing module named annotationlib - imported by typing_extensions (conditional)
|
||||
missing module named _dummy_thread - imported by numpy.core.arrayprint (optional)
|
||||
missing module named psutil - imported by numpy.testing._private.utils (delayed, optional)
|
||||
missing module named win32evtlog - imported by logging.handlers (delayed, optional)
|
||||
missing module named win32evtlogutil - imported by logging.handlers (delayed, optional)
|
||||
missing module named startup - imported by pyreadline3.keysyms.common (conditional), pyreadline3.keysyms.keysyms (conditional)
|
||||
missing module named sets - imported by pyreadline3.keysyms.common (optional)
|
||||
missing module named System - imported by pyreadline3.clipboard.ironpython_clipboard (top-level), pyreadline3.keysyms.ironpython_keysyms (top-level), pyreadline3.console.ironpython_console (top-level), pyreadline3.rlmain (conditional)
|
||||
missing module named console - imported by pyreadline3.console.ansi (conditional)
|
||||
missing module named clr - imported by pyreadline3.clipboard.ironpython_clipboard (top-level), pyreadline3.console.ironpython_console (top-level)
|
||||
missing module named IronPythonConsole - imported by pyreadline3.console.ironpython_console (top-level)
|
||||
missing module named numpy.core.result_type - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.float_ - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.number - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.object_ - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.max - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.all - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.errstate - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.bool_ - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.inf - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.isnan - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.array2string - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.imag - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.real - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.iscomplexobj - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.signbit - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.isscalar - imported by numpy.core (delayed), numpy.testing._private.utils (delayed), numpy.lib.polynomial (top-level)
|
||||
missing module named win32pdh - imported by numpy.testing._private.utils (delayed, conditional)
|
||||
missing module named numpy.core.array - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.isnat - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.ndarray - imported by numpy.core (top-level), numpy.testing._private.utils (top-level), numpy.lib.utils (top-level)
|
||||
missing module named numpy.core.array_repr - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.arange - imported by numpy.core (top-level), numpy.testing._private.utils (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.empty - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.float32 - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.intp - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named java - imported by platform (delayed)
|
||||
missing module named _winreg - imported by platform (delayed, optional)
|
||||
missing module named numpy.core.linspace - imported by numpy.core (top-level), numpy.lib.index_tricks (top-level)
|
||||
missing module named numpy.core.iinfo - imported by numpy.core (top-level), numpy.lib.twodim_base (top-level)
|
||||
missing module named numpy.core.transpose - imported by numpy.core (top-level), numpy.lib.function_base (top-level)
|
||||
missing module named numpy.uint - imported by numpy (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.core.asarray - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.utils (top-level), numpy.fft._pocketfft (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.integer - imported by numpy.core (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.sqrt - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.conjugate - imported by numpy.core (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.swapaxes - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.zeros - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.reciprocal - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.sort - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.argsort - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.sign - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.count_nonzero - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.divide - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.matmul - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.asanyarray - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.atleast_2d - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.prod - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.amax - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.amin - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.moveaxis - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.geterrobj - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.finfo - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.isfinite - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.sum - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.multiply - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.add - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.dot - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.Inf - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.newaxis - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.complexfloating - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.inexact - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.cdouble - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.csingle - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.double - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.single - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.intc - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.empty_like - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named pyodide_js - imported by threadpoolctl (delayed, optional)
|
||||
missing module named numpy.core.ufunc - imported by numpy.core (top-level), numpy.lib.utils (top-level)
|
||||
missing module named numpy.core.ones - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.hstack - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.atleast_1d - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.atleast_3d - imported by numpy.core (top-level), numpy.lib.shape_base (top-level)
|
||||
missing module named numpy.core.vstack - imported by numpy.core (top-level), numpy.lib.shape_base (top-level)
|
||||
missing module named pickle5 - imported by numpy.compat.py3k (optional)
|
||||
missing module named numpy.eye - imported by numpy (delayed), numpy.core.numeric (delayed)
|
||||
missing module named numpy.recarray - imported by numpy (top-level), numpy.lib.recfunctions (top-level), numpy.ma.mrecords (top-level)
|
||||
missing module named numpy.expand_dims - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.array - imported by numpy (top-level), numpy.ma.core (top-level), numpy.ma.extras (top-level), numpy.ma.mrecords (top-level)
|
||||
missing module named numpy.iscomplexobj - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.amin - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.amax - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.isinf - imported by numpy (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.isnan - imported by numpy (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.isfinite - imported by numpy (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.float64 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.float32 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.uint64 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._philox (top-level), numpy.random._sfc64 (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.uint32 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._generator (top-level), numpy.random._mt19937 (top-level)
|
||||
missing module named numpy.uint16 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.uint8 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int64 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int32 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int16 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int8 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.bytes_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.str_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.void - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.object_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.datetime64 - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.timedelta64 - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.number - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.complexfloating - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.floating - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.integer - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.unsignedinteger - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.bool_ - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ma.core (top-level), numpy.ma.mrecords (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.generic - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.dtype - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.array_api._typing (top-level), numpy.ma.mrecords (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._philox (top-level), numpy.random._sfc64 (top-level), numpy.random._generator (top-level), numpy.random._mt19937 (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.ndarray - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ma.core (top-level), numpy.ma.extras (top-level), numpy.lib.recfunctions (top-level), numpy.ma.mrecords (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._philox (top-level), numpy.random._sfc64 (top-level), numpy.random._generator (top-level), numpy.random._mt19937 (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.ufunc - imported by numpy (top-level), numpy._typing (top-level), numpy.testing.overrides (top-level)
|
||||
missing module named numpy.histogramdd - imported by numpy (delayed), numpy.lib.twodim_base (delayed)
|
||||
missing module named numpy._distributor_init_local - imported by numpy (optional), numpy._distributor_init (optional)
|
||||
missing module named numpy._typing._ufunc - imported by numpy._typing (conditional)
|
||||
missing module named olefile - imported by PIL.FpxImagePlugin (top-level), PIL.MicImagePlugin (top-level)
|
||||
missing module named defusedxml - imported by PIL.Image (optional)
|
||||
21591
Tools/Configapp/build/main/xref-main.html
Normal file
21591
Tools/Configapp/build/main/xref-main.html
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Tools/Configapp/chipCatana.ico
Normal file
BIN
Tools/Configapp/chipCatana.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
17
Tools/Configapp/config.py
Normal file
17
Tools/Configapp/config.py
Normal file
@ -0,0 +1,17 @@
|
||||
# config.py
|
||||
from pathlib import Path
|
||||
|
||||
# Длины блоков серийного номера: А999/D15112025/V999/N999 -> 4 / 9 / 4 / 4
|
||||
SEGMENT_LENGTHS = [4, 9, 4, 4]
|
||||
|
||||
# Пути к файлам
|
||||
DOCUMENTS_PATH = Path.home() / "Documents" / "C4"
|
||||
SERIAL_FILE = DOCUMENTS_PATH / "serialdata.dat"
|
||||
|
||||
# Стили приложения
|
||||
APP_STYLE = {
|
||||
'title_font': ("Segoe UI", 12, "bold"),
|
||||
'entry_font': ("Consolas", 14),
|
||||
'label_font': ("Segoe UI", 10),
|
||||
'padding': {'padx': 20, 'pady': 10}
|
||||
}
|
||||
BIN
Tools/Configapp/dist/Cofigurator 31.8.exe
vendored
Normal file
BIN
Tools/Configapp/dist/Cofigurator 31.8.exe
vendored
Normal file
Binary file not shown.
286
Tools/Configapp/main.py
Normal file
286
Tools/Configapp/main.py
Normal file
@ -0,0 +1,286 @@
|
||||
# main.py
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Добавляем текущую директорию в путь Python
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# Импортируем наши модули
|
||||
try:
|
||||
from modules.serial_writer import SerialWriterTab
|
||||
from modules.bots_module import BotsCountTab
|
||||
from modules.light_module import LightModuleTab
|
||||
from modules.electronics_module import ElectronicsModuleTab
|
||||
from modules.server_module import ServerModuleTab
|
||||
except ImportError as e:
|
||||
print(f"Ошибка импорта модуля: {e}")
|
||||
print("Проверьте, что файлы модулей существуют в папке modules/")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class ConfiguratorApp:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.root.title("🎮 Конфигуратор игры 'Фишка'")
|
||||
self.root.geometry("1100x800") # Немного увеличим размер
|
||||
|
||||
# Центрируем окно
|
||||
self.center_window()
|
||||
|
||||
# Создаем стиль для вкладок
|
||||
self.style = ttk.Style()
|
||||
self.style.theme_use('clam')
|
||||
|
||||
# Настраиваем стиль вкладок
|
||||
self.style.configure('TNotebook', background='#f0f0f0')
|
||||
self.style.configure('TNotebook.Tab',
|
||||
padding=[20, 8],
|
||||
font=('Arial', 11, 'bold'),
|
||||
foreground='#333333')
|
||||
|
||||
# Стиль для активной вкладки
|
||||
self.style.map('TNotebook.Tab',
|
||||
background=[('selected', '#2196F3'), ('!selected', '#E0E0E0')],
|
||||
foreground=[('selected', 'white'), ('!selected', '#666666')])
|
||||
|
||||
# Создаем главный контейнер
|
||||
self.main_container = ttk.Frame(root)
|
||||
self.main_container.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
|
||||
|
||||
# Создаем Notebook для вкладок
|
||||
self.notebook = ttk.Notebook(self.main_container)
|
||||
self.notebook.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# Словари для хранения вкладок и модулей
|
||||
self.tabs = {}
|
||||
self.modules = {}
|
||||
|
||||
# Инициализируем вкладки
|
||||
self.init_tabs()
|
||||
|
||||
# Загрузка сохраненных данных при запуске
|
||||
self.load_saved_data()
|
||||
|
||||
def center_window(self):
|
||||
"""Центрировать окно на экране"""
|
||||
self.root.update_idletasks()
|
||||
width = 1100
|
||||
height = 800
|
||||
screen_width = self.root.winfo_screenwidth()
|
||||
screen_height = self.root.winfo_screenheight()
|
||||
|
||||
x = (screen_width - width) // 2
|
||||
y = (screen_height - height) // 2
|
||||
|
||||
self.root.geometry(f'{width}x{height}+{x}+{y}')
|
||||
|
||||
def init_tabs(self):
|
||||
"""Инициализация вкладок с модулями"""
|
||||
print("🔧 Инициализация модулей...")
|
||||
|
||||
# 1. Серийный номер (первая вкладка)
|
||||
self.add_module_tab("serial", "📋 СЕРИЙНЫЙ НОМЕР", SerialWriterTab)
|
||||
|
||||
# 2. Количество ботов (вторая вкладка)
|
||||
# self.add_module_tab("bots", "🤖 КОЛИЧЕСТВО БОТОВ", BotsCountTab)
|
||||
|
||||
# 3. Настройка подсветки (третья вкладка)
|
||||
self.add_module_tab("light", "💡 ПОДСВЕТКА", LightModuleTab)
|
||||
|
||||
self.add_module_tab("electronics", "⚡ ЭЛЕКТРОНИКА", ElectronicsModuleTab)
|
||||
|
||||
self.add_module_tab("server", "🌐 ВЕБ-СЕРВЕР", ServerModuleTab)
|
||||
|
||||
print(f"✅ Загружено модулей: {len(self.modules)}")
|
||||
|
||||
# Устанавливаем первую вкладку активной
|
||||
if self.tabs:
|
||||
self.notebook.select(0)
|
||||
|
||||
def add_module_tab(self, module_id, tab_name, module_class):
|
||||
"""
|
||||
Добавить вкладку с модулем
|
||||
|
||||
Args:
|
||||
module_id: Уникальный идентификатор модуля
|
||||
tab_name: Название вкладки
|
||||
module_class: Класс модуля
|
||||
"""
|
||||
print(f" ⏳ Загрузка модуля: {module_id}")
|
||||
|
||||
try:
|
||||
# Создаем фрейм для вкладки
|
||||
tab_frame = ttk.Frame(self.notebook)
|
||||
|
||||
# Добавляем фрейм в notebook
|
||||
self.notebook.add(tab_frame, text=tab_name)
|
||||
|
||||
# Создаем экземпляр модуля
|
||||
module_instance = module_class(tab_frame)
|
||||
|
||||
# Сохраняем модуль
|
||||
self.modules[module_id] = module_instance
|
||||
self.tabs[tab_name] = {
|
||||
'frame': tab_frame,
|
||||
'module': module_instance,
|
||||
'type': 'module'
|
||||
}
|
||||
|
||||
print(f" ✅ Модуль '{module_id}' загружен успешно")
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ Ошибка загрузки модуля '{module_id}': {e}")
|
||||
|
||||
# Создаем фрейм с ошибкой
|
||||
tab_frame = ttk.Frame(self.notebook)
|
||||
self.notebook.add(tab_frame, text=f"❌ {tab_name}")
|
||||
|
||||
error_frame = ttk.Frame(tab_frame, padding=50)
|
||||
error_frame.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
ttk.Label(
|
||||
error_frame,
|
||||
text=f"Ошибка загрузки модуля:\n{str(e)}",
|
||||
font=('Arial', 12),
|
||||
foreground='red',
|
||||
justify=tk.CENTER
|
||||
).pack(expand=True)
|
||||
|
||||
self.tabs[tab_name] = {
|
||||
'frame': tab_frame,
|
||||
'error': str(e),
|
||||
'type': 'error'
|
||||
}
|
||||
|
||||
def load_saved_data(self):
|
||||
"""Загрузить сохраненные данные при запуске"""
|
||||
try:
|
||||
# Загружаем серийный номер
|
||||
if 'serial' in self.modules:
|
||||
if hasattr(self.modules['serial'], 'load_serial_from_file'):
|
||||
loaded = self.modules['serial'].load_serial_from_file()
|
||||
if loaded:
|
||||
print("✓ Серийный номер загружен из файла")
|
||||
|
||||
# Загружаем настройки подсветки
|
||||
if 'light' in self.modules:
|
||||
if hasattr(self.modules['light'], 'check_light_version'):
|
||||
version = self.modules['light'].check_light_version()
|
||||
if version:
|
||||
print(f"✓ Версия подсветки загружена: {version}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Ошибка загрузки данных: {e}")
|
||||
|
||||
def save_all(self):
|
||||
"""Сохранить все данные из всех модулей"""
|
||||
saved_modules = []
|
||||
errors = []
|
||||
|
||||
# Сохраняем данные из всех модулей
|
||||
for module_id, module in self.modules.items():
|
||||
try:
|
||||
if hasattr(module, 'save_serial'):
|
||||
module.save_serial()
|
||||
saved_modules.append("Серийный номер")
|
||||
|
||||
elif hasattr(module, 'save_bots_amount'):
|
||||
module.save_bots_amount()
|
||||
saved_modules.append("Количество ботов")
|
||||
|
||||
elif hasattr(module, 'save_light_config'):
|
||||
module.save_light_config()
|
||||
saved_modules.append("Подсветка")
|
||||
elif hasattr(module, 'save_electro_config'):
|
||||
module.save_electro_config()
|
||||
saved_modules.append("Электроника")
|
||||
elif hasattr(module, 'save_server_config'):
|
||||
module.save_server_config()
|
||||
saved_modules.append("Веб-сервер")
|
||||
|
||||
except Exception as e:
|
||||
errors.append(f"{module_id}: {str(e)[:50]}...")
|
||||
|
||||
# Показываем результат
|
||||
if saved_modules:
|
||||
if errors:
|
||||
message = (
|
||||
f"✅ Успешно сохранено:\n"
|
||||
f"{', '.join(saved_modules)}\n\n"
|
||||
f"❌ Ошибки:\n"
|
||||
f"{chr(10).join(errors)}"
|
||||
)
|
||||
messagebox.showwarning("Сохранение с ошибками", message)
|
||||
else:
|
||||
message = f"✅ Все настройки успешно сохранены!\n\nСохранено: {', '.join(saved_modules)}"
|
||||
messagebox.showinfo("Сохранение завершено", message)
|
||||
else:
|
||||
if errors:
|
||||
message = f"❌ Не удалось сохранить данные:\n\n{chr(10).join(errors)}"
|
||||
messagebox.showerror("Ошибка сохранения", message)
|
||||
else:
|
||||
messagebox.showinfo("Сохранение", "Нет данных для сохранения.")
|
||||
|
||||
def refresh_all(self):
|
||||
"""Обновить все модули"""
|
||||
for module_id, module in self.modules.items():
|
||||
try:
|
||||
if hasattr(module, 'update_status'):
|
||||
module.update_status()
|
||||
elif hasattr(module, 'check_light_version'):
|
||||
module.check_light_version()
|
||||
except Exception as e:
|
||||
print(f"Ошибка обновления модуля {module_id}: {e}")
|
||||
|
||||
print("✓ Все модули обновлены")
|
||||
|
||||
def check_all_modules(self):
|
||||
"""Проверить все модули"""
|
||||
results = []
|
||||
|
||||
for module_id, module in self.modules.items():
|
||||
try:
|
||||
if module_id == 'serial':
|
||||
serial = module.get_serial_number()
|
||||
if serial:
|
||||
results.append(f"✅ Серийный номер: {serial}")
|
||||
else:
|
||||
results.append("⚠️ Серийный номер: не заполнен")
|
||||
|
||||
elif module_id == 'bots':
|
||||
bots = module.get_bots_count()
|
||||
results.append(f"✅ Количество ботов: {bots}")
|
||||
|
||||
elif module_id == 'light':
|
||||
version = module.get_current_version()
|
||||
if version:
|
||||
results.append(f"✅ Версия подсветки: {version}")
|
||||
else:
|
||||
results.append("⚠️ Подсветка: не настроена")
|
||||
elif module_id == 'electronics':
|
||||
version = module.get_current_version()
|
||||
if version:
|
||||
results.append(f"✅ Версия электроники: {version}")
|
||||
else:
|
||||
results.append("⚠️ Электроника: не настроена")
|
||||
|
||||
except Exception as e:
|
||||
results.append(f"❌ {module_id}: ошибка - {str(e)[:50]}")
|
||||
|
||||
if results:
|
||||
message = "🔍 Результаты проверки всех модулей:\n\n" + "\n".join(results)
|
||||
messagebox.showinfo("Проверка настроек", message)
|
||||
else:
|
||||
messagebox.showinfo("Проверка настроек", "Нет загруженных модулей для проверки.")
|
||||
|
||||
|
||||
def main():
|
||||
root = tk.Tk()
|
||||
app = ConfiguratorApp(root)
|
||||
root.mainloop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
38
Tools/Configapp/main.spec
Normal file
38
Tools/Configapp/main.spec
Normal file
@ -0,0 +1,38 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['main.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='main',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
2
Tools/Configapp/modules/__init__.py
Normal file
2
Tools/Configapp/modules/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# modules/__init__.py
|
||||
# Этот файл нужен для того, чтобы Python считал папку modules пакетом
|
||||
BIN
Tools/Configapp/modules/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
Tools/Configapp/modules/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Tools/Configapp/modules/__pycache__/bots_module.cpython-310.pyc
Normal file
BIN
Tools/Configapp/modules/__pycache__/bots_module.cpython-310.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
Tools/Configapp/modules/__pycache__/light_module.cpython-310.pyc
Normal file
BIN
Tools/Configapp/modules/__pycache__/light_module.cpython-310.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
406
Tools/Configapp/modules/bots_module.py
Normal file
406
Tools/Configapp/modules/bots_module.py
Normal file
@ -0,0 +1,406 @@
|
||||
# modules/bots_module.py
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
import hashlib
|
||||
import os
|
||||
import uuid
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class BotsCountTab:
|
||||
"""
|
||||
Класс для создания вкладки настройки количества ботов.
|
||||
"""
|
||||
|
||||
def __init__(self, parent_frame):
|
||||
"""
|
||||
Инициализация компонента вкладки.
|
||||
|
||||
Args:
|
||||
parent_frame: Родительский фрейм, куда будет помещен интерфейс
|
||||
"""
|
||||
self.parent = parent_frame
|
||||
|
||||
# Путь для сохранения файла
|
||||
self.save_dir = Path.home() / "Documents" / "C4"
|
||||
self.file_path = self.save_dir / "BotsAmount.rr"
|
||||
|
||||
# Переменные
|
||||
self.bots_var = tk.IntVar(value=1)
|
||||
self.mac_address = self.get_mac_address()
|
||||
self.loading_from_file = False # Флаг загрузки из файла
|
||||
|
||||
# Создаем основной контейнер для вкладки
|
||||
self.container = ttk.Frame(parent_frame, padding=20)
|
||||
self.container.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
self._build_ui()
|
||||
|
||||
# Загружаем настройки из файла при старте (только один раз)
|
||||
self.load_from_file()
|
||||
self.update_status()
|
||||
|
||||
def get_mac_address(self):
|
||||
"""Получаем MAC-адрес компьютера"""
|
||||
try:
|
||||
# Получаем MAC-адрес
|
||||
mac = ':'.join(re.findall('..', '%012x' % uuid.getnode()))
|
||||
return mac.upper()
|
||||
except:
|
||||
return "00:00:00:00:00:00"
|
||||
|
||||
def _build_ui(self):
|
||||
"""Построение интерфейса вкладки"""
|
||||
|
||||
# Заголовок вкладки
|
||||
title_frame = ttk.Frame(self.container)
|
||||
title_frame.pack(fill=tk.X, pady=(0, 20))
|
||||
|
||||
title_label = ttk.Label(
|
||||
title_frame,
|
||||
text='Настройка количества ботов',
|
||||
font=("Segoe UI", 12, "bold")
|
||||
)
|
||||
title_label.pack()
|
||||
|
||||
# Разделитель
|
||||
ttk.Separator(self.container, orient="horizontal").pack(
|
||||
fill=tk.X, pady=(0, 20)
|
||||
)
|
||||
|
||||
# Основной контент
|
||||
content_frame = ttk.Frame(self.container)
|
||||
content_frame.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# Левая панель - выбор количества
|
||||
left_panel = ttk.LabelFrame(content_frame, text="Выбор количества", padding=15)
|
||||
left_panel.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10))
|
||||
|
||||
ttk.Label(left_panel, text="Выберите количество ботов:",
|
||||
font=("Arial", 10)).pack(pady=(0, 10))
|
||||
|
||||
# Фрейм для радиокнопок
|
||||
self.radio_frame = ttk.Frame(left_panel)
|
||||
self.radio_frame.pack(pady=5)
|
||||
|
||||
# Создаем радиокнопки для выбора количества ботов
|
||||
self.radio_buttons = []
|
||||
for i in range(1, 6):
|
||||
rb = tk.Radiobutton(
|
||||
self.radio_frame,
|
||||
text=f"{i} бот{'ов' if i > 1 else ''}",
|
||||
variable=self.bots_var,
|
||||
value=i,
|
||||
font=("Arial", 10),
|
||||
command=self._on_bots_change
|
||||
)
|
||||
rb.pack(anchor=tk.W, pady=3)
|
||||
self.radio_buttons.append(rb)
|
||||
|
||||
# Кнопки управления
|
||||
button_frame = ttk.Frame(left_panel)
|
||||
button_frame.pack(pady=20)
|
||||
|
||||
ttk.Button(
|
||||
button_frame,
|
||||
text="Сохранить настройки",
|
||||
command=self._save_config,
|
||||
width=20
|
||||
).pack(pady=5)
|
||||
|
||||
# Правая панель - информация и статус
|
||||
right_panel = ttk.LabelFrame(content_frame, text="Информация", padding=15)
|
||||
right_panel.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(10, 0))
|
||||
|
||||
# MAC-адрес
|
||||
mac_frame = ttk.Frame(right_panel)
|
||||
mac_frame.pack(fill=tk.X, pady=(0, 15))
|
||||
|
||||
ttk.Label(mac_frame, text="MAC-адрес:",
|
||||
font=("Arial", 9, "bold")).pack(anchor=tk.W)
|
||||
self.mac_label = ttk.Label(
|
||||
mac_frame,
|
||||
text=self.mac_address,
|
||||
font=("Consolas", 9),
|
||||
foreground="blue"
|
||||
)
|
||||
self.mac_label.pack(anchor=tk.W, pady=(2, 0))
|
||||
|
||||
# Путь к файлу
|
||||
path_frame = ttk.Frame(right_panel)
|
||||
path_frame.pack(fill=tk.X, pady=(0, 15))
|
||||
|
||||
ttk.Label(path_frame, text="Файл для сохранения:",
|
||||
font=("Arial", 9, "bold")).pack(anchor=tk.W)
|
||||
self.path_label = ttk.Label(
|
||||
path_frame,
|
||||
text=str(self.file_path),
|
||||
font=("Consolas", 8),
|
||||
wraplength=250
|
||||
)
|
||||
self.path_label.pack(anchor=tk.W, pady=(2, 0))
|
||||
|
||||
# Статус
|
||||
status_frame = ttk.Frame(right_panel)
|
||||
status_frame.pack(fill=tk.X, pady=(0, 15))
|
||||
|
||||
ttk.Label(status_frame, text="Текущий статус:",
|
||||
font=("Arial", 9, "bold")).pack(anchor=tk.W)
|
||||
self.status_label = ttk.Label(
|
||||
status_frame,
|
||||
text="Не сохранено",
|
||||
font=("Arial", 10),
|
||||
foreground="red"
|
||||
)
|
||||
self.status_label.pack(anchor=tk.W, pady=(2, 0))
|
||||
|
||||
# Количество ботов из файла
|
||||
bots_frame = ttk.Frame(right_panel)
|
||||
bots_frame.pack(fill=tk.X)
|
||||
|
||||
ttk.Label(bots_frame, text="Количество ботов в файле:",
|
||||
font=("Arial", 9, "bold")).pack(anchor=tk.W)
|
||||
self.bots_file_label = ttk.Label(
|
||||
bots_frame,
|
||||
text="не определено",
|
||||
font=("Arial", 10),
|
||||
foreground="orange"
|
||||
)
|
||||
self.bots_file_label.pack(anchor=tk.W, pady=(2, 0))
|
||||
|
||||
def _on_bots_change(self):
|
||||
"""Обработчик изменения выбранного количества ботов"""
|
||||
# Не обновляем статус при изменении пользователем
|
||||
# Просто сбрасываем флаг загрузки из файла
|
||||
if not self.loading_from_file:
|
||||
# Обновляем только статус файла
|
||||
if self.file_path.exists():
|
||||
self.status_label.config(text="Файл будет перезаписан", foreground="orange")
|
||||
else:
|
||||
self.status_label.config(text="Файл будет создан", foreground="blue")
|
||||
|
||||
def load_from_file(self):
|
||||
"""Загрузить настройки из файла при старте"""
|
||||
self.loading_from_file = True # Устанавливаем флаг загрузки
|
||||
|
||||
if not self.file_path.exists():
|
||||
self.bots_file_label.config(
|
||||
text="файл не найден",
|
||||
foreground="red"
|
||||
)
|
||||
self.loading_from_file = False
|
||||
return None
|
||||
|
||||
try:
|
||||
with open(self.file_path, 'r', encoding='utf-8') as f:
|
||||
file_hash = f.read().strip()
|
||||
|
||||
if len(file_hash) != 64: # SHA-256 hash length
|
||||
self.bots_file_label.config(
|
||||
text="неверный формат хэша",
|
||||
foreground="red"
|
||||
)
|
||||
self.loading_from_file = False
|
||||
return None
|
||||
|
||||
# Пробуем подобрать количество ботов от 1 до 5
|
||||
found_bots = None
|
||||
for bots in range(1, 6):
|
||||
data = str(bots) + "RR_SuPeR" + self.mac_address
|
||||
calculated_hash = hashlib.sha256(data.encode()).hexdigest()
|
||||
|
||||
if calculated_hash == file_hash:
|
||||
found_bots = bots
|
||||
break
|
||||
|
||||
if found_bots:
|
||||
# Устанавливаем значение из файла
|
||||
self.bots_var.set(found_bots)
|
||||
self.bots_file_label.config(
|
||||
text=f"{found_bots} бот{'ов' if found_bots > 1 else ''}",
|
||||
foreground="green"
|
||||
)
|
||||
self.status_label.config(
|
||||
text="✓ Загружено из файла",
|
||||
foreground="green"
|
||||
)
|
||||
self.loading_from_file = False
|
||||
return found_bots
|
||||
else:
|
||||
# Если хэш не совпал ни с одним вариантом
|
||||
self.bots_file_label.config(
|
||||
text="не совпадает с MAC-адресом",
|
||||
foreground="red"
|
||||
)
|
||||
self.status_label.config(
|
||||
text="Файл есть, но не совпадает",
|
||||
foreground="orange"
|
||||
)
|
||||
self.loading_from_file = False
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
self.bots_file_label.config(
|
||||
text=f"ошибка чтения",
|
||||
foreground="red"
|
||||
)
|
||||
self.status_label.config(
|
||||
text=f"Ошибка чтения файла",
|
||||
foreground="red"
|
||||
)
|
||||
self.loading_from_file = False
|
||||
return None
|
||||
|
||||
def update_status(self):
|
||||
"""Обновить статус (только для отображения, без изменения выбора)"""
|
||||
# Проверяем существование файла
|
||||
if self.file_path.exists():
|
||||
# Читаем хэш из файла для сравнения
|
||||
try:
|
||||
with open(self.file_path, 'r', encoding='utf-8') as f:
|
||||
file_hash = f.read().strip()
|
||||
|
||||
# Вычисляем хэш для текущего выбора
|
||||
current_bots = self.bots_var.get()
|
||||
data = str(current_bots) + "RR_SuPeR" + self.mac_address
|
||||
current_hash = hashlib.sha256(data.encode()).hexdigest()
|
||||
|
||||
# Сравниваем
|
||||
if current_hash == file_hash:
|
||||
self.status_label.config(
|
||||
text="✓ Совпадает с файлом",
|
||||
foreground="green"
|
||||
)
|
||||
else:
|
||||
self.status_label.config(
|
||||
text="Отличается от файла",
|
||||
foreground="orange"
|
||||
)
|
||||
|
||||
except Exception:
|
||||
self.status_label.config(
|
||||
text="✓ Файл существует",
|
||||
foreground="green"
|
||||
)
|
||||
else:
|
||||
self.status_label.config(
|
||||
text="Файл не найден",
|
||||
foreground="red"
|
||||
)
|
||||
|
||||
def check_existing_file(self):
|
||||
"""Проверить существующий файл и показать информацию (для диалога)"""
|
||||
if self.file_path.exists():
|
||||
try:
|
||||
with open(self.file_path, 'r', encoding='utf-8') as f:
|
||||
hash_content = f.read().strip()
|
||||
|
||||
# Рассчитываем количество ботов из файла
|
||||
bots_count = None
|
||||
for bots in range(1, 6):
|
||||
data = str(bots) + "RR_SuPeR" + self.mac_address
|
||||
calculated_hash = hashlib.sha256(data.encode()).hexdigest()
|
||||
if calculated_hash == hash_content:
|
||||
bots_count = bots
|
||||
break
|
||||
|
||||
# Показываем диалог с информацией
|
||||
if bots_count:
|
||||
info_text = (
|
||||
f"В файле сохранено: {bots_count} бот{'ов' if bots_count > 1 else ''}\n"
|
||||
f"Текущий выбор: {self.bots_var.get()} бот{'ов' if self.bots_var.get() > 1 else ''}\n\n"
|
||||
)
|
||||
|
||||
if bots_count == self.bots_var.get():
|
||||
info_text += "Текущий выбор совпадает с сохраненным в файле."
|
||||
result = messagebox.showinfo(
|
||||
"Информация о файле",
|
||||
info_text
|
||||
)
|
||||
else:
|
||||
info_text += "Текущий выбор отличается от сохраненного в файле.\nХотите перезаписать файл?"
|
||||
result = messagebox.askyesno(
|
||||
"Файл существует",
|
||||
info_text
|
||||
)
|
||||
return result
|
||||
else:
|
||||
messagebox.showinfo(
|
||||
"Информация о файле",
|
||||
f"Файл существует, но количество ботов не определено.\n"
|
||||
f"(хэш не совпадает с текущим MAC-адресом)"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
messagebox.showerror("Ошибка", f"Не удалось прочитать файл:\n{str(e)}")
|
||||
|
||||
return True # По умолчанию разрешаем сохранение
|
||||
|
||||
def _save_config(self):
|
||||
"""Сохраняет количество ботов в файл с хешированием"""
|
||||
# Проверяем существующий файл
|
||||
if self.file_path.exists():
|
||||
result = self.check_existing_file()
|
||||
if not result:
|
||||
return # Пользователь отказался от перезаписи
|
||||
|
||||
try:
|
||||
# Получаем выбранное значение
|
||||
bots = self.bots_var.get()
|
||||
|
||||
if not 1 <= bots <= 5:
|
||||
messagebox.showerror("Ошибка", "Выберите количество ботов от 1 до 5")
|
||||
return
|
||||
|
||||
# Создаем хэш количества ботов с солью и MAC-адресом
|
||||
data = str(bots) + "RR_SuPeR" + self.mac_address
|
||||
hash_result = hashlib.sha256(data.encode()).hexdigest()
|
||||
|
||||
# Создаем директорию, если она не существует
|
||||
self.save_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Сохраняем в файл
|
||||
with open(self.file_path, "w", encoding="utf-8") as f:
|
||||
f.write(hash_result)
|
||||
|
||||
# Обновляем статус
|
||||
self.update_status()
|
||||
|
||||
# Обновляем метку файла
|
||||
self.bots_file_label.config(
|
||||
text=f"{bots} бот{'ов' if bots > 1 else ''}",
|
||||
foreground="green"
|
||||
)
|
||||
|
||||
# Показываем результат
|
||||
messagebox.showinfo(
|
||||
"Сохранено",
|
||||
f"Количество ботов: {bots}\n\n"
|
||||
f"Файл сохранен: {self.file_path}"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
messagebox.showerror("Ошибка", f"Не удалось сохранить файл:\n{str(e)}")
|
||||
|
||||
def get_bots_count(self):
|
||||
"""Получить текущее количество ботов (для использования другими модулями)"""
|
||||
return self.bots_var.get()
|
||||
|
||||
def get_hash_info(self):
|
||||
"""Получить информацию о хэше (для использования другими модулями)"""
|
||||
bots = self.bots_var.get()
|
||||
data = str(bots) + "RR_SuPeR" + self.mac_address
|
||||
hash_result = hashlib.sha256(data.encode()).hexdigest()
|
||||
|
||||
return {
|
||||
'bots': bots,
|
||||
'mac': self.mac_address,
|
||||
'hash': hash_result,
|
||||
'file_path': str(self.file_path),
|
||||
'data_string': data
|
||||
}
|
||||
|
||||
def save_bots_amount(self):
|
||||
"""Сохранить количество ботов (интерфейсный метод для main)"""
|
||||
self._save_config()
|
||||
647
Tools/Configapp/modules/electronics_module.py
Normal file
647
Tools/Configapp/modules/electronics_module.py
Normal file
@ -0,0 +1,647 @@
|
||||
# modules/electronics_module.py
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import os
|
||||
from PIL import Image, ImageTk
|
||||
|
||||
# Добавляем родительскую директорию в путь для импорта
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
try:
|
||||
# Пытаемся импортировать из config.py
|
||||
import config
|
||||
DOCUMENTS_PATH = config.DOCUMENTS_PATH
|
||||
APP_STYLE = config.APP_STYLE
|
||||
except ImportError:
|
||||
# Локальные значения по умолчанию
|
||||
DOCUMENTS_PATH = Path.home() / "Documents" / "C4"
|
||||
APP_STYLE = {
|
||||
'title_font': ("Segoe UI", 12, "bold"),
|
||||
'entry_font': ("Consolas", 14),
|
||||
'label_font': ("Segoe UI", 10),
|
||||
'padding': {'padx': 20, 'pady': 10}
|
||||
}
|
||||
|
||||
# Путь к файлам конфигурации электроники
|
||||
ELECTRO_FILE = DOCUMENTS_PATH / "elektro_version.rr"
|
||||
HOPPER_SENSOR_FILE = DOCUMENTS_PATH / "HopperSensor.rr"
|
||||
|
||||
class ElectronicsModuleTab:
|
||||
"""
|
||||
Класс для создания вкладки конфигурации подключения электроники.
|
||||
"""
|
||||
|
||||
def __init__(self, parent_frame):
|
||||
"""
|
||||
Инициализация компонента вкладки.
|
||||
|
||||
Args:
|
||||
parent_frame: Родительский фрейм, куда будет помещен интерфейс
|
||||
"""
|
||||
self.parent = parent_frame
|
||||
self.current_version = None
|
||||
self.current_sensor_type = None
|
||||
self.image_cache = {} # Кэш загруженных изображений
|
||||
|
||||
# Создаем основной контейнер для вкладки
|
||||
self.container = ttk.Frame(parent_frame, padding=20)
|
||||
self.container.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
self._build_ui()
|
||||
|
||||
# Загружаем сохраненные настройки при запуске
|
||||
self.load_saved_settings()
|
||||
|
||||
def _build_ui(self):
|
||||
"""Построение интерфейса вкладки"""
|
||||
|
||||
# Заголовок вкладки
|
||||
title_frame = ttk.Frame(self.container)
|
||||
title_frame.pack(fill=tk.X, pady=(0, 20))
|
||||
|
||||
title_label = ttk.Label(
|
||||
title_frame,
|
||||
text='Конфигурация подключения электроники',
|
||||
font=APP_STYLE['title_font']
|
||||
)
|
||||
title_label.pack()
|
||||
|
||||
# Разделитель
|
||||
ttk.Separator(self.container, orient="horizontal").pack(
|
||||
fill=tk.X, pady=(0, 20)
|
||||
)
|
||||
|
||||
# Фрейм для выбора версии электроники
|
||||
selector_frame = ttk.LabelFrame(
|
||||
self.container,
|
||||
text="Выбор версии электроники",
|
||||
padding=20
|
||||
)
|
||||
selector_frame.pack(fill=tk.X, pady=(0, 20))
|
||||
|
||||
# Описание
|
||||
desc_label = ttk.Label(
|
||||
selector_frame,
|
||||
text="Выберите версию электроники, установленной в аппарате:",
|
||||
font=APP_STYLE['label_font'],
|
||||
wraplength=600
|
||||
)
|
||||
desc_label.pack(anchor=tk.W, pady=(0, 20))
|
||||
|
||||
# Переменная для хранения выбранной версии
|
||||
self.version_var = tk.StringVar()
|
||||
|
||||
# Фрейм для вариантов версий электроники
|
||||
versions_frame = ttk.Frame(selector_frame)
|
||||
versions_frame.pack(fill=tk.X, pady=(0, 20))
|
||||
|
||||
# Вариант 1
|
||||
version1_frame = ttk.Frame(versions_frame)
|
||||
version1_frame.pack(fill=tk.X, pady=(0, 10))
|
||||
|
||||
version1_radio = ttk.Radiobutton(
|
||||
version1_frame,
|
||||
text="Версия 1.0 (старая)",
|
||||
variable=self.version_var,
|
||||
value="1",
|
||||
command=self._on_version_change
|
||||
)
|
||||
version1_radio.pack(side=tk.LEFT, anchor=tk.W)
|
||||
|
||||
# Кнопка просмотра схемы для версии 1
|
||||
view1_btn = ttk.Button(
|
||||
version1_frame,
|
||||
text="Посмотреть схему",
|
||||
command=lambda: self._show_scheme("1"),
|
||||
width=30
|
||||
)
|
||||
view1_btn.pack(side=tk.LEFT, padx=(20, 0))
|
||||
|
||||
|
||||
# Вариант 2
|
||||
version2_frame = ttk.Frame(versions_frame)
|
||||
version2_frame.pack(fill=tk.X, pady=(0, 10))
|
||||
|
||||
version2_radio = ttk.Radiobutton(
|
||||
version2_frame,
|
||||
text="Версия 2.0 (новая)",
|
||||
variable=self.version_var,
|
||||
value="2",
|
||||
command=self._on_version_change
|
||||
)
|
||||
version2_radio.pack(side=tk.LEFT, anchor=tk.W)
|
||||
|
||||
# Кнопка просмотра схемы для версии 2
|
||||
view2_btn = ttk.Button(
|
||||
version2_frame,
|
||||
text="Посмотреть схему",
|
||||
command=lambda: self._show_scheme("2"),
|
||||
width=30
|
||||
)
|
||||
view2_btn.pack(side=tk.LEFT, padx=(20, 0))
|
||||
|
||||
# ===== НОВЫЙ РАЗДЕЛ: ТИП ДАТЧИКА ХОППЕРА =====
|
||||
# Фрейм для выбора типа датчика хоппера
|
||||
sensor_frame = ttk.LabelFrame(
|
||||
selector_frame,
|
||||
text="Тип датчика хоппера",
|
||||
padding=15
|
||||
)
|
||||
sensor_frame.pack(fill=tk.X, pady=(10, 20))
|
||||
|
||||
# Описание для датчика хоппера
|
||||
sensor_desc_label = ttk.Label(
|
||||
sensor_frame,
|
||||
text="Выберите тип контакта датчика хоппера:",
|
||||
font=APP_STYLE['label_font']
|
||||
)
|
||||
sensor_desc_label.pack(anchor=tk.W, pady=(0, 10))
|
||||
|
||||
# Переменная для хранения выбранного типа датчика
|
||||
self.sensor_var = tk.StringVar(value="1") # По умолчанию "Нормально разомкнутый"
|
||||
|
||||
# Вариант 1: Нормально разомкнутый
|
||||
sensor1_radio = ttk.Radiobutton(
|
||||
sensor_frame,
|
||||
text="Нормально разомкнутый (по умолчанию)",
|
||||
variable=self.sensor_var,
|
||||
value="1",
|
||||
command=self._on_sensor_change
|
||||
)
|
||||
sensor1_radio.pack(anchor=tk.W, pady=(0, 5))
|
||||
|
||||
# Вариант 2: Нормально замкнутый
|
||||
sensor2_radio = ttk.Radiobutton(
|
||||
sensor_frame,
|
||||
text="Нормально замкнутый",
|
||||
variable=self.sensor_var,
|
||||
value="2",
|
||||
command=self._on_sensor_change
|
||||
)
|
||||
sensor2_radio.pack(anchor=tk.W)
|
||||
# ===== КОНЕЦ НОВОГО РАЗДЕЛА =====
|
||||
|
||||
# Кнопки управления
|
||||
button_frame = ttk.Frame(selector_frame)
|
||||
button_frame.pack(fill=tk.X)
|
||||
|
||||
# Кнопка сохранения
|
||||
save_btn = ttk.Button(
|
||||
button_frame,
|
||||
text="Сохранить все настройки",
|
||||
command=self.save_all_settings,
|
||||
width=25
|
||||
)
|
||||
save_btn.pack(side=tk.LEFT, padx=(0, 10))
|
||||
|
||||
# Кнопка загрузки
|
||||
load_btn = ttk.Button(
|
||||
button_frame,
|
||||
text="Загрузить из файлов",
|
||||
command=self.load_saved_settings,
|
||||
width=20
|
||||
)
|
||||
load_btn.pack(side=tk.LEFT)
|
||||
|
||||
# Информационная панель
|
||||
info_frame = ttk.LabelFrame(
|
||||
self.container,
|
||||
text="Информация",
|
||||
padding=15
|
||||
)
|
||||
info_frame.pack(fill=tk.X)
|
||||
|
||||
# Создаем фрейм для информации о файлах с прокруткой
|
||||
info_canvas = tk.Canvas(info_frame, height=80)
|
||||
scrollbar = ttk.Scrollbar(info_frame, orient="vertical", command=info_canvas.yview)
|
||||
info_scrollable_frame = ttk.Frame(info_canvas)
|
||||
|
||||
info_scrollable_frame.bind(
|
||||
"<Configure>",
|
||||
lambda e: info_canvas.configure(scrollregion=info_canvas.bbox("all"))
|
||||
)
|
||||
|
||||
info_canvas.create_window((0, 0), window=info_scrollable_frame, anchor="nw")
|
||||
info_canvas.configure(yscrollcommand=scrollbar.set)
|
||||
|
||||
info_canvas.pack(side="left", fill="both", expand=True, padx=(0, 5))
|
||||
scrollbar.pack(side="right", fill="y")
|
||||
|
||||
# Информация о файле электроники
|
||||
self.electro_info_label = ttk.Label(
|
||||
info_scrollable_frame,
|
||||
text="Электроника: не выбрано",
|
||||
font=APP_STYLE['label_font']
|
||||
)
|
||||
self.electro_info_label.pack(anchor=tk.W, pady=(0, 5))
|
||||
|
||||
# Информация о файле датчика хоппера
|
||||
self.sensor_info_label = ttk.Label(
|
||||
info_scrollable_frame,
|
||||
text="Датчик хоппера: не выбрано",
|
||||
font=APP_STYLE['label_font']
|
||||
)
|
||||
self.sensor_info_label.pack(anchor=tk.W, pady=(0, 5))
|
||||
|
||||
# Статус сохранения
|
||||
self.status_label = ttk.Label(
|
||||
info_frame,
|
||||
text="Статус: настройки не сохранены",
|
||||
font=APP_STYLE['label_font']
|
||||
)
|
||||
self.status_label.pack(anchor=tk.W, pady=(10, 0))
|
||||
|
||||
def _load_scheme_image(self, version):
|
||||
"""Загрузить изображение схемы"""
|
||||
# Это заглушка - на практике здесь будет загрузка реальных изображений
|
||||
# Создаем тестовое изображение с текстом
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import io
|
||||
|
||||
if version == "1":
|
||||
# Создаем изображение для схемы 1
|
||||
img = Image.new('RGB', (600, 400), color='white')
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# Простой текст вместо изображения
|
||||
try:
|
||||
font = ImageFont.truetype("arial.ttf", 24)
|
||||
except:
|
||||
font = ImageFont.load_default()
|
||||
|
||||
draw.text((50, 50), "Что то пошло не так", fill='black', font=font)
|
||||
draw.text((50, 100), "пните серегу", fill='blue', font=font)
|
||||
|
||||
else: # version == "2"
|
||||
# Создаем изображение для схемы 2
|
||||
img = Image.new('RGB', (600, 400), color='white')
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
try:
|
||||
font = ImageFont.truetype("arial.ttf", 24)
|
||||
except:
|
||||
font = ImageFont.load_default()
|
||||
|
||||
draw.text((50, 50), "Что то пошло не так v2", fill='black', font=font)
|
||||
draw.text((50, 100), "пните серегу", fill='blue', font=font)
|
||||
|
||||
return ImageTk.PhotoImage(img)
|
||||
|
||||
def _show_scheme(self, version):
|
||||
"""Показать окно со схемой подключения"""
|
||||
scheme_window = tk.Toplevel(self.parent)
|
||||
|
||||
if version == "1":
|
||||
scheme_window.title("Схема подключения - Версия 1.0")
|
||||
window_title = "СХЕМА ПОДКЛЮЧЕНИЯ v1.0"
|
||||
else: # version == "2"
|
||||
scheme_window.title("Схема подключения - Версия 2.0")
|
||||
window_title = "СХЕМА ПОДКЛЮЧЕНИЯ v2.0"
|
||||
|
||||
# Устанавливаем размер окна
|
||||
scheme_window.geometry("1200x1000")
|
||||
scheme_window.resizable(True, True)
|
||||
|
||||
# Создаем основной фрейм
|
||||
main_frame = ttk.Frame(scheme_window, padding=20)
|
||||
main_frame.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# Заголовок
|
||||
title_label = ttk.Label(
|
||||
main_frame,
|
||||
text=window_title,
|
||||
font=("Segoe UI", 16, "bold"),
|
||||
foreground="#2196F3"
|
||||
)
|
||||
title_label.pack(pady=(0, 20))
|
||||
|
||||
# Фрейм для изображения
|
||||
image_frame = ttk.Frame(main_frame)
|
||||
image_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 20))
|
||||
|
||||
# Загружаем изображение
|
||||
try:
|
||||
# Пытаемся загрузить реальное изображение
|
||||
if version == "1":
|
||||
image_path = Path("schemes") / "scheme_v1.jpg"
|
||||
else:
|
||||
image_path = Path("schemes") / "scheme_v2.jpg"
|
||||
|
||||
if image_path.exists():
|
||||
# Загружаем реальное изображение
|
||||
pil_image = Image.open(image_path)
|
||||
# Масштабируем для отображения
|
||||
pil_image = pil_image.resize((1024, 1024), Image.LANCZOS)
|
||||
image = ImageTk.PhotoImage(pil_image)
|
||||
else:
|
||||
# Используем заглушку
|
||||
image = self._load_scheme_image(version)
|
||||
except Exception as e:
|
||||
# Если не удалось загрузить изображение, показываем заглушку
|
||||
print(f"Ошибка загрузки изображения: {e}")
|
||||
image = self._load_scheme_image(version)
|
||||
|
||||
# Сохраняем ссылку на изображение, чтобы оно не было удалено сборщиком мусора
|
||||
scheme_window.image_ref = image
|
||||
|
||||
# Отображаем изображение
|
||||
image_label = ttk.Label(image_frame, image=image)
|
||||
image_label.pack()
|
||||
|
||||
# Центрируем окно
|
||||
scheme_window.update_idletasks()
|
||||
x = scheme_window.winfo_screenwidth() // 2 - scheme_window.winfo_width() // 2
|
||||
y = scheme_window.winfo_screenheight() // 2 - scheme_window.winfo_height() // 2
|
||||
scheme_window.geometry(f"+{x}+{y}")
|
||||
|
||||
# Устанавливаем фокус на новое окно
|
||||
scheme_window.focus_set()
|
||||
scheme_window.grab_set()
|
||||
|
||||
def _on_version_change(self):
|
||||
"""Обработчик изменения выбранной версии электроники"""
|
||||
version = self.version_var.get()
|
||||
self.current_version = version
|
||||
|
||||
# Обновляем информацию в интерфейсе
|
||||
if version == "1":
|
||||
self.electro_info_label.config(
|
||||
text="Электроника: выбрана версия 1.0",
|
||||
foreground="orange"
|
||||
)
|
||||
elif version == "2":
|
||||
self.electro_info_label.config(
|
||||
text="Электроника: выбрана версия 2.0",
|
||||
foreground="orange"
|
||||
)
|
||||
|
||||
self._update_status()
|
||||
|
||||
def _on_sensor_change(self):
|
||||
"""Обработчик изменения типа датчика хоппера"""
|
||||
sensor_type = self.sensor_var.get()
|
||||
self.current_sensor_type = sensor_type
|
||||
|
||||
# Обновляем информацию в интерфейсе
|
||||
if sensor_type == "1":
|
||||
self.sensor_info_label.config(
|
||||
text="Датчик хоппера: Нормально разомкнутый",
|
||||
foreground="orange"
|
||||
)
|
||||
elif sensor_type == "2":
|
||||
self.sensor_info_label.config(
|
||||
text="Датчик хоппера: Нормально замкнутый",
|
||||
foreground="orange"
|
||||
)
|
||||
|
||||
self._update_status()
|
||||
|
||||
def _update_status(self):
|
||||
"""Обновить статус сохранения"""
|
||||
version_selected = bool(self.version_var.get())
|
||||
sensor_selected = bool(self.sensor_var.get())
|
||||
|
||||
if version_selected and sensor_selected:
|
||||
self.status_label.config(
|
||||
text="Статус: все настройки выбраны (готово к сохранению)",
|
||||
foreground="blue"
|
||||
)
|
||||
elif version_selected or sensor_selected:
|
||||
self.status_label.config(
|
||||
text="Статус: часть настроек выбрана",
|
||||
foreground="orange"
|
||||
)
|
||||
else:
|
||||
self.status_label.config(
|
||||
text="Статус: настройки не выбраны",
|
||||
foreground="red"
|
||||
)
|
||||
|
||||
def _save_electro_version(self):
|
||||
"""Сохранить версию электроники в файл"""
|
||||
version = self.version_var.get()
|
||||
|
||||
if not version:
|
||||
return False, "Версия электроники не выбрана"
|
||||
|
||||
try:
|
||||
# Создаем директорию, если её нет
|
||||
DOCUMENTS_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Записываем версию в файл
|
||||
with ELECTRO_FILE.open("w", encoding="utf-8") as f:
|
||||
f.write(version + "\n")
|
||||
|
||||
return True, f"Версия электроники {version}.0 сохранена"
|
||||
|
||||
except Exception as e:
|
||||
return False, f"Ошибка сохранения электроники: {e}"
|
||||
|
||||
def _save_hopper_sensor(self):
|
||||
"""Сохранить тип датчика хоппера в файл"""
|
||||
sensor_type = self.sensor_var.get()
|
||||
|
||||
if not sensor_type:
|
||||
return False, "Тип датчика хоппера не выбран"
|
||||
|
||||
try:
|
||||
# Создаем директорию, если её нет
|
||||
DOCUMENTS_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Записываем тип датчика в файл
|
||||
with HOPPER_SENSOR_FILE.open("w", encoding="utf-8") as f:
|
||||
f.write(sensor_type + "\n")
|
||||
|
||||
# Определяем текст для пользователя
|
||||
sensor_text = "Нормально разомкнутый" if sensor_type == "1" else "Нормально замкнутый"
|
||||
return True, f"Тип датчика хоппера '{sensor_text}' сохранен"
|
||||
|
||||
except Exception as e:
|
||||
return False, f"Ошибка сохранения датчика хоппера: {e}"
|
||||
|
||||
def save_all_settings(self):
|
||||
"""Сохранить все настройки (версию электроники и тип датчика хоппера)"""
|
||||
# Проверяем, что выбрана версия электроники
|
||||
if not self.version_var.get():
|
||||
messagebox.showerror(
|
||||
"Ошибка",
|
||||
"Выберите версию электроники перед сохранением."
|
||||
)
|
||||
return
|
||||
|
||||
# Проверяем, что выбран тип датчика хоппера
|
||||
if not self.sensor_var.get():
|
||||
messagebox.showerror(
|
||||
"Ошибка",
|
||||
"Выберите тип датчика хоппера перед сохранением."
|
||||
)
|
||||
return
|
||||
|
||||
results = []
|
||||
errors = []
|
||||
|
||||
# Сохраняем версию электроники
|
||||
success_electro, message_electro = self._save_electro_version()
|
||||
if success_electro:
|
||||
results.append(message_electro)
|
||||
else:
|
||||
errors.append(message_electro)
|
||||
|
||||
# Сохраняем тип датчика хоппера
|
||||
success_sensor, message_sensor = self._save_hopper_sensor()
|
||||
if success_sensor:
|
||||
results.append(message_sensor)
|
||||
else:
|
||||
errors.append(message_sensor)
|
||||
|
||||
# Формируем итоговое сообщение
|
||||
if errors:
|
||||
# Были ошибки
|
||||
error_message = "Не все настройки удалось сохранить:\n\n"
|
||||
error_message += "\n".join(results) if results else ""
|
||||
error_message += "\n\nОшибки:\n"
|
||||
error_message += "\n".join(errors)
|
||||
|
||||
messagebox.showerror("Ошибка сохранения", error_message)
|
||||
|
||||
# Обновляем статус
|
||||
self.status_label.config(
|
||||
text="Статус: ошибка сохранения",
|
||||
foreground="red"
|
||||
)
|
||||
else:
|
||||
# Все успешно сохранено
|
||||
success_message = "Все настройки успешно сохранены!\n\n"
|
||||
success_message += "\n".join(results)
|
||||
|
||||
messagebox.showinfo("Готово", success_message)
|
||||
|
||||
# Обновляем информацию в интерфейсе
|
||||
version = self.version_var.get()
|
||||
sensor_type = self.sensor_var.get()
|
||||
sensor_text = "Нормально разомкнутый" if sensor_type == "1" else "Нормально замкнутый"
|
||||
|
||||
self.electro_info_label.config(
|
||||
text=f"Электроника: ✓ версия {version}.0 (сохранено)",
|
||||
foreground="green"
|
||||
)
|
||||
|
||||
self.sensor_info_label.config(
|
||||
text=f"Датчик хоппера: ✓ {sensor_text} (сохранено)",
|
||||
foreground="green"
|
||||
)
|
||||
|
||||
self.status_label.config(
|
||||
text="Статус: ✓ все настройки сохранены",
|
||||
foreground="green"
|
||||
)
|
||||
|
||||
def load_saved_settings(self):
|
||||
"""Загрузить сохраненные настройки из файлов"""
|
||||
results = []
|
||||
warnings = []
|
||||
|
||||
# Загружаем версию электроники
|
||||
try:
|
||||
if ELECTRO_FILE.exists():
|
||||
with ELECTRO_FILE.open("r", encoding="utf-8") as f:
|
||||
version = f.readline().strip()
|
||||
|
||||
if version in ["1", "2"]:
|
||||
self.version_var.set(version)
|
||||
self.current_version = version
|
||||
|
||||
version_text = f"Версия {version}.0"
|
||||
results.append(f"Электроника: {version_text}")
|
||||
|
||||
if version == "1":
|
||||
self.electro_info_label.config(
|
||||
text=f"Электроника: {version_text} (загружено)",
|
||||
foreground="green"
|
||||
)
|
||||
else:
|
||||
self.electro_info_label.config(
|
||||
text=f"Электроника: {version_text} (загружено)",
|
||||
foreground="green"
|
||||
)
|
||||
else:
|
||||
warnings.append("Неверный формат файла электроники")
|
||||
else:
|
||||
warnings.append("Файл электроники не найден")
|
||||
|
||||
except Exception as e:
|
||||
warnings.append(f"Ошибка загрузки электроники: {e}")
|
||||
|
||||
# Загружаем тип датчика хоппера
|
||||
try:
|
||||
if HOPPER_SENSOR_FILE.exists():
|
||||
with HOPPER_SENSOR_FILE.open("r", encoding="utf-8") as f:
|
||||
sensor_type = f.readline().strip()
|
||||
|
||||
if sensor_type in ["1", "2"]:
|
||||
self.sensor_var.set(sensor_type)
|
||||
self.current_sensor_type = sensor_type
|
||||
|
||||
sensor_text = "Нормально разомкнутый" if sensor_type == "1" else "Нормально замкнутый"
|
||||
results.append(f"Датчик хоппера: {sensor_text}")
|
||||
|
||||
self.sensor_info_label.config(
|
||||
text=f"Датчик хоппера: {sensor_text} (загружено)",
|
||||
foreground="green"
|
||||
)
|
||||
else:
|
||||
warnings.append("Неверный формат файла датчика хоппера")
|
||||
else:
|
||||
# Используем значение по умолчанию (нормально разомкнутый)
|
||||
self.sensor_var.set("1")
|
||||
self.current_sensor_type = "1"
|
||||
results.append("Датчик хоппера: Нормально разомкнутый (по умолчанию)")
|
||||
|
||||
self.sensor_info_label.config(
|
||||
text="Датчик хоппера: Нормально разомкнутый (по умолчанию)",
|
||||
foreground="blue"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
warnings.append(f"Ошибка загрузки датчика хоппера: {e}")
|
||||
|
||||
# Обновляем статус
|
||||
if results and not warnings:
|
||||
self.status_label.config(
|
||||
text="Статус: ✓ настройки загружены",
|
||||
foreground="green"
|
||||
)
|
||||
elif warnings:
|
||||
warning_text = "\n".join(warnings)
|
||||
self.status_label.config(
|
||||
text="Статус: загружены с ошибками",
|
||||
foreground="orange"
|
||||
)
|
||||
|
||||
if results:
|
||||
# Показываем сообщение с предупреждениями
|
||||
message_text = "Загружены не все настройки:\n\n"
|
||||
message_text += "\n".join(results)
|
||||
message_text += "\n\nПредупреждения:\n"
|
||||
message_text += warning_text
|
||||
|
||||
messagebox.showwarning("Предупреждение", message_text)
|
||||
|
||||
# Обновляем общий статус
|
||||
self._update_status()
|
||||
|
||||
return len(warnings) == 0
|
||||
|
||||
def get_current_version(self):
|
||||
"""Получить текущую выбранную версию электроники (для использования другими модулями)"""
|
||||
return self.current_version
|
||||
|
||||
def get_current_sensor_type(self):
|
||||
"""Получить текущий выбранный тип датчика хоппера (для использования другими модулями)"""
|
||||
return self.current_sensor_type
|
||||
|
||||
def save_electro_config(self):
|
||||
"""Сохранить конфигурацию электроники (интерфейсный метод для main)"""
|
||||
self.save_all_settings()
|
||||
264
Tools/Configapp/modules/light_module.py
Normal file
264
Tools/Configapp/modules/light_module.py
Normal file
@ -0,0 +1,264 @@
|
||||
# modules/light_module.py
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Добавляем родительскую директорию в путь для импорта
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
try:
|
||||
import config
|
||||
DOCUMENTS_PATH = config.DOCUMENTS_PATH
|
||||
except ImportError:
|
||||
# Локальные значения по умолчанию
|
||||
DOCUMENTS_PATH = Path.home() / "Documents" / "C4"
|
||||
|
||||
|
||||
class LightModuleTab:
|
||||
"""
|
||||
Класс для создания вкладки настройки подсветки.
|
||||
Поддерживает версии 1 и 2 подсветки для аппаратов "Фишка".
|
||||
"""
|
||||
|
||||
def __init__(self, parent_frame):
|
||||
"""
|
||||
Инициализация компонента вкладки.
|
||||
|
||||
Args:
|
||||
parent_frame: Родительский фрейм, куда будет помещен интерфейс
|
||||
"""
|
||||
self.parent = parent_frame
|
||||
|
||||
# Пути к файлам
|
||||
self.overrides_dir = DOCUMENTS_PATH / "overrides"
|
||||
self.light_conf_file = self.overrides_dir / "Light.conf"
|
||||
|
||||
# Текущая версия подсветки
|
||||
self.current_version = None
|
||||
|
||||
# Переменная для радиокнопок
|
||||
self.light_version = tk.IntVar(value=2) # По умолчанию вторая версия
|
||||
|
||||
# Создаем основной контейнер для вкладки
|
||||
self.container = ttk.Frame(parent_frame, padding=20)
|
||||
self.container.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
self._build_ui()
|
||||
|
||||
# Проверяем текущую версию при запуске
|
||||
self.check_light_version()
|
||||
|
||||
def _build_ui(self):
|
||||
"""Построение интерфейса вкладки"""
|
||||
|
||||
# Заголовок вкладки
|
||||
title_frame = ttk.Frame(self.container)
|
||||
title_frame.pack(fill=tk.X, pady=(0, 20))
|
||||
|
||||
title_label = ttk.Label(
|
||||
title_frame,
|
||||
text='Настройка подсветки',
|
||||
font=("Segoe UI", 12, "bold")
|
||||
)
|
||||
title_label.pack()
|
||||
|
||||
# Разделитель
|
||||
ttk.Separator(self.container, orient="horizontal").pack(
|
||||
fill=tk.X, pady=(0, 20)
|
||||
)
|
||||
|
||||
# Фрейм для выбора версии
|
||||
selector_frame = ttk.LabelFrame(
|
||||
self.container,
|
||||
text="Выбор версии подсветки",
|
||||
padding=15
|
||||
)
|
||||
selector_frame.pack(fill=tk.X, pady=(0, 20))
|
||||
|
||||
# Версия 1
|
||||
version1_frame = ttk.Frame(selector_frame)
|
||||
version1_frame.pack(fill=tk.X, pady=(0, 10))
|
||||
|
||||
version1_radio = ttk.Radiobutton(
|
||||
version1_frame,
|
||||
text="Версия 1 (старая)",
|
||||
variable=self.light_version,
|
||||
value=1,
|
||||
command=self._on_version_change
|
||||
)
|
||||
version1_radio.pack(side=tk.LEFT, anchor=tk.W)
|
||||
|
||||
|
||||
# Версия 2
|
||||
version2_frame = ttk.Frame(selector_frame)
|
||||
version2_frame.pack(fill=tk.X, pady=(0, 10))
|
||||
|
||||
version2_radio = ttk.Radiobutton(
|
||||
version2_frame,
|
||||
text="Версия 2 (новая, по умолчанию)",
|
||||
variable=self.light_version,
|
||||
value=2,
|
||||
command=self._on_version_change
|
||||
)
|
||||
version2_radio.pack(side=tk.LEFT, anchor=tk.W)
|
||||
|
||||
|
||||
# Кнопки управления
|
||||
button_frame = ttk.Frame(selector_frame)
|
||||
button_frame.pack(fill=tk.X, pady=(10, 0))
|
||||
|
||||
# Кнопка сохранения
|
||||
save_btn = ttk.Button(
|
||||
button_frame,
|
||||
text="Сохранить настройки",
|
||||
command=self._save_config,
|
||||
width=30
|
||||
)
|
||||
save_btn.pack(side=tk.LEFT, padx=(0, 10))
|
||||
|
||||
# Кнопка проверки
|
||||
check_btn = ttk.Button(
|
||||
button_frame,
|
||||
text="Проверить текущую версию",
|
||||
command=self.check_light_version,
|
||||
width=30
|
||||
)
|
||||
check_btn.pack(side=tk.LEFT)
|
||||
|
||||
# Информационная панель
|
||||
info_frame = ttk.LabelFrame(
|
||||
self.container,
|
||||
text="Информация",
|
||||
padding=15
|
||||
)
|
||||
info_frame.pack(fill=tk.X)
|
||||
|
||||
# Статус
|
||||
self.status_label = ttk.Label(
|
||||
info_frame,
|
||||
text="Статус: не проверено",
|
||||
font=("Segoe UI", 10)
|
||||
)
|
||||
self.status_label.pack(anchor=tk.W, pady=(0, 5))
|
||||
|
||||
# Файл
|
||||
self.file_label = ttk.Label(
|
||||
info_frame,
|
||||
text=f"Файл: {self.light_conf_file.name}",
|
||||
font=("Segoe UI", 9),
|
||||
foreground="gray"
|
||||
)
|
||||
self.file_label.pack(anchor=tk.W)
|
||||
|
||||
def _on_version_change(self):
|
||||
"""Обработчик изменения выбранной версии"""
|
||||
selected_version = self.light_version.get()
|
||||
|
||||
# Визуальная обратная связь
|
||||
if selected_version == 1:
|
||||
self.status_label.config(
|
||||
text="Статус: выбрана версия 1",
|
||||
foreground="orange"
|
||||
)
|
||||
else:
|
||||
self.status_label.config(
|
||||
text="Статус: выбрана версия 2",
|
||||
foreground="green"
|
||||
)
|
||||
|
||||
def check_light_version(self):
|
||||
"""Проверить текущую версию подсветки"""
|
||||
try:
|
||||
# Проверяем существование файла
|
||||
if not self.light_conf_file.exists():
|
||||
self.current_version = None
|
||||
self.status_label.config(
|
||||
text="Статус: файл не найден",
|
||||
foreground="red"
|
||||
)
|
||||
return None
|
||||
|
||||
# Читаем файл
|
||||
with open(self.light_conf_file, 'r', encoding='utf-8') as f:
|
||||
content = f.read().strip()
|
||||
|
||||
# Парсим версию
|
||||
if content == "1":
|
||||
self.current_version = 1
|
||||
self.light_version.set(1)
|
||||
self.status_label.config(
|
||||
text="Статус: установлена версия 1",
|
||||
foreground="orange"
|
||||
)
|
||||
elif content == "2":
|
||||
self.current_version = 2
|
||||
self.light_version.set(2)
|
||||
self.status_label.config(
|
||||
text="Статус: установлена версия 2",
|
||||
foreground="green"
|
||||
)
|
||||
else:
|
||||
self.current_version = None
|
||||
self.status_label.config(
|
||||
text="Статус: некорректное содержимое файла",
|
||||
foreground="red"
|
||||
)
|
||||
|
||||
return self.current_version
|
||||
|
||||
except Exception as e:
|
||||
self.current_version = None
|
||||
self.status_label.config(
|
||||
text=f"Статус: ошибка чтения файла",
|
||||
foreground="red"
|
||||
)
|
||||
return None
|
||||
|
||||
def _save_config(self):
|
||||
"""Сохранить выбранную версию подсветки (внутренний метод)"""
|
||||
try:
|
||||
selected_version = self.light_version.get()
|
||||
|
||||
# Создаем директорию, если её нет
|
||||
self.overrides_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Сохраняем в файл
|
||||
with open(self.light_conf_file, 'w', encoding='utf-8') as f:
|
||||
f.write(str(selected_version))
|
||||
|
||||
# Обновляем текущую версию
|
||||
self.current_version = selected_version
|
||||
|
||||
# Обновляем интерфейс
|
||||
if selected_version == 1:
|
||||
self.status_label.config(
|
||||
text="Статус: ✓ сохранена версия 1",
|
||||
foreground="green"
|
||||
)
|
||||
else:
|
||||
self.status_label.config(
|
||||
text="Статус: ✓ сохранена версия 2",
|
||||
foreground="green"
|
||||
)
|
||||
|
||||
messagebox.showinfo(
|
||||
"Готово",
|
||||
f"Версия подсветки успешно сохранена!\n\n"
|
||||
f"Версия: {selected_version}"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
messagebox.showerror(
|
||||
"Ошибка сохранения",
|
||||
f"Не удалось сохранить настройки подсветки:\n{e}"
|
||||
)
|
||||
|
||||
def get_current_version(self):
|
||||
"""Получить текущую версию подсветки (для использования другими модулями)"""
|
||||
return self.current_version
|
||||
|
||||
def save_light_config(self):
|
||||
"""Сохранить конфигурацию подсветки (интерфейсный метод для main)"""
|
||||
self._save_config()
|
||||
545
Tools/Configapp/modules/serial_writer.py
Normal file
545
Tools/Configapp/modules/serial_writer.py
Normal file
@ -0,0 +1,545 @@
|
||||
# modules/serial_writer.py
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import os
|
||||
from datetime import datetime
|
||||
import json
|
||||
|
||||
# Добавляем родительскую директорию в путь для импорта
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
try:
|
||||
# Пытаемся импортировать из config.py
|
||||
import config
|
||||
SEGMENT_LENGTHS = config.SEGMENT_LENGTHS
|
||||
DOCUMENTS_PATH = config.DOCUMENTS_PATH
|
||||
SERIAL_FILE = config.SERIAL_FILE
|
||||
APP_STYLE = config.APP_STYLE
|
||||
except ImportError:
|
||||
# Локальные значения по умолчанию
|
||||
SEGMENT_LENGTHS = [4, 9, 4, 4]
|
||||
DOCUMENTS_PATH = Path.home() / "Documents" / "C4"
|
||||
SERIAL_FILE = DOCUMENTS_PATH / "serialdata.dat"
|
||||
APP_STYLE = {
|
||||
'title_font': ("Segoe UI", 12, "bold"),
|
||||
'entry_font': ("Consolas", 14),
|
||||
'label_font': ("Segoe UI", 10),
|
||||
'padding': {'padx': 20, 'pady': 10}
|
||||
}
|
||||
|
||||
class SerialWriterTab:
|
||||
"""
|
||||
Класс для создания вкладки ввода серийного номера.
|
||||
Теперь это не отдельное приложение, а компонент для конфигуратора.
|
||||
"""
|
||||
|
||||
def __init__(self, parent_frame):
|
||||
"""
|
||||
Инициализация компонента вкладки.
|
||||
|
||||
Args:
|
||||
parent_frame: Родительский фрейм, куда будет помещен интерфейс
|
||||
"""
|
||||
self.parent = parent_frame
|
||||
self.segment_lengths = SEGMENT_LENGTHS
|
||||
self.prefixes = ['A', 'D', 'V', 'N'] # Буквенные префиксы для каждого сегмента
|
||||
self.vars = []
|
||||
self.entries = []
|
||||
self._updating = False # защита от рекурсии в trace
|
||||
|
||||
# Определяем путь для файла serial.temp (рядом с исполняемым файлом)
|
||||
self.executable_dir = Path(sys.executable).parent if hasattr(sys, 'frozen') else Path(__file__).parent.parent
|
||||
self.serial_temp_file = self.executable_dir / "serial.temp"
|
||||
|
||||
# Создаем основной контейнер для вкладки
|
||||
self.container = ttk.Frame(parent_frame, padding=20)
|
||||
self.container.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
self._build_ui()
|
||||
|
||||
# Загружаем данные о последней записи
|
||||
self.load_last_serial_info()
|
||||
|
||||
# Проверяем существующий серийный номер
|
||||
self._check_existing_serial()
|
||||
|
||||
def _build_ui(self):
|
||||
"""Построение интерфейса вкладки"""
|
||||
|
||||
# Заголовок вкладки
|
||||
title_frame = ttk.Frame(self.container)
|
||||
title_frame.pack(fill=tk.X, pady=(0, 20))
|
||||
|
||||
title_label = ttk.Label(
|
||||
title_frame,
|
||||
text='Серийный номер аппарата "ФИШКА"',
|
||||
font=APP_STYLE['title_font']
|
||||
)
|
||||
title_label.pack()
|
||||
|
||||
# Разделитель
|
||||
ttk.Separator(self.container, orient="horizontal").pack(
|
||||
fill=tk.X, pady=(0, 20)
|
||||
)
|
||||
|
||||
# Фрейм для полей ввода
|
||||
entry_frame = ttk.Frame(self.container)
|
||||
entry_frame.pack(pady=(0, 20))
|
||||
|
||||
# Поля ввода серийного номера
|
||||
self._create_entry_fields(entry_frame)
|
||||
|
||||
# Кнопка загрузки последнего серийника
|
||||
self._create_load_last_button(entry_frame)
|
||||
|
||||
# Фрейм для кнопок
|
||||
button_frame = ttk.Frame(self.container)
|
||||
button_frame.pack(pady=(20, 0))
|
||||
|
||||
self._create_buttons(button_frame)
|
||||
|
||||
# Панель статуса
|
||||
self._create_status_panel()
|
||||
|
||||
# Устанавливаем фокус на первое поле
|
||||
self.entries[0].focus_set()
|
||||
|
||||
def _create_entry_fields(self, parent):
|
||||
"""Создание полей ввода для серийного номера"""
|
||||
col = 0
|
||||
for i, (length, prefix) in enumerate(zip(self.segment_lengths, self.prefixes)):
|
||||
# Создаем Label с префиксом
|
||||
prefix_label = ttk.Label(
|
||||
parent,
|
||||
text=prefix,
|
||||
font=APP_STYLE['entry_font'],
|
||||
foreground="black"
|
||||
)
|
||||
prefix_label.grid(row=0, column=col, padx=(0, 2), pady=(0, 10))
|
||||
col += 1
|
||||
|
||||
# Поле для цифр (длина на 1 меньше, так как первый символ - буква)
|
||||
var = tk.StringVar()
|
||||
var.trace_add("write", lambda *args, i=i: self._on_segment_change(i))
|
||||
|
||||
entry = ttk.Entry(
|
||||
parent,
|
||||
textvariable=var,
|
||||
width=length, # Один символ уже занят буквой
|
||||
justify="center",
|
||||
font=APP_STYLE['entry_font']
|
||||
)
|
||||
entry.grid(row=0, column=col, padx=2, pady=(0, 10))
|
||||
self.vars.append(var)
|
||||
self.entries.append(entry)
|
||||
|
||||
# Навигация Backspace влево
|
||||
entry.bind("<KeyPress>", lambda e, i=i: self._on_key(e, i))
|
||||
|
||||
col += 1
|
||||
if i != len(self.segment_lengths) - 1:
|
||||
slash = ttk.Label(parent, text="/", font=APP_STYLE['entry_font'])
|
||||
slash.grid(row=0, column=col, padx=2, pady=(0, 10))
|
||||
col += 1
|
||||
|
||||
# Enter на последнем поле = Сохранить
|
||||
self.entries[-1].bind("<Return>", lambda e: self.save_serial())
|
||||
|
||||
def _create_load_last_button(self, parent):
|
||||
"""Создание кнопки загрузки последнего серийного номера"""
|
||||
self.load_last_btn = ttk.Button(
|
||||
parent,
|
||||
text="Загрузить последний",
|
||||
command=self.load_last_serial,
|
||||
width=30
|
||||
)
|
||||
self.load_last_btn.grid(row=0, column=20, padx=(20, 0), pady=(0, 10))
|
||||
|
||||
# Обновляем состояние кнопки
|
||||
self.update_load_last_button()
|
||||
|
||||
def _create_buttons(self, parent):
|
||||
"""Создание кнопок управления"""
|
||||
# Кнопка сохранения
|
||||
save_btn = ttk.Button(
|
||||
parent,
|
||||
text="Сохранить серийный номер",
|
||||
command=self.save_serial,
|
||||
width=30
|
||||
)
|
||||
save_btn.grid(row=0, column=0, padx=(0, 10))
|
||||
|
||||
# Кнопка очистки
|
||||
clear_btn = ttk.Button(
|
||||
parent,
|
||||
text="Очистить поля",
|
||||
command=self.clear_fields,
|
||||
width=30
|
||||
)
|
||||
clear_btn.grid(row=0, column=1, padx=(0, 10))
|
||||
|
||||
# Кнопка проверки
|
||||
check_btn = ttk.Button(
|
||||
parent,
|
||||
text="Проверить формат",
|
||||
command=self.check_format,
|
||||
width=30
|
||||
)
|
||||
check_btn.grid(row=0, column=2)
|
||||
|
||||
def _create_status_panel(self):
|
||||
"""Создание панели статуса"""
|
||||
status_frame = ttk.LabelFrame(
|
||||
self.container,
|
||||
text="Информация",
|
||||
padding=10
|
||||
)
|
||||
status_frame.pack(fill=tk.X, pady=(20, 0))
|
||||
|
||||
# Формат номера
|
||||
format_label = ttk.Label(
|
||||
status_frame,
|
||||
text="Формат: A999/D15112025/V999/N999",
|
||||
font=APP_STYLE['label_font']
|
||||
)
|
||||
format_label.pack(anchor=tk.W, pady=(0, 5))
|
||||
|
||||
# Информация о последней записи
|
||||
self.last_record_label = ttk.Label(
|
||||
status_frame,
|
||||
text="Последняя запись: не найдена",
|
||||
font=APP_STYLE['label_font'],
|
||||
foreground="gray"
|
||||
)
|
||||
self.last_record_label.pack(anchor=tk.W, pady=(0, 5))
|
||||
|
||||
# Текущий серийный номер
|
||||
self.current_serial_label = ttk.Label(
|
||||
status_frame,
|
||||
text="Текущий серийный номер: не указан",
|
||||
font=APP_STYLE['label_font'],
|
||||
foreground="gray"
|
||||
)
|
||||
self.current_serial_label.pack(anchor=tk.W, pady=(0, 5))
|
||||
|
||||
# Статус заполнения
|
||||
self.status_label = ttk.Label(
|
||||
status_frame,
|
||||
text="Статус: Не заполнено",
|
||||
font=APP_STYLE['label_font']
|
||||
)
|
||||
self.status_label.pack(anchor=tk.W)
|
||||
|
||||
def load_last_serial_info(self):
|
||||
"""Загрузить информацию о последней записи из файла serial.temp"""
|
||||
try:
|
||||
if self.serial_temp_file.exists():
|
||||
with self.serial_temp_file.open("r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
last_date = data.get("last_write_date", "неизвестно")
|
||||
last_serial = data.get("last_serial", "неизвестно")
|
||||
|
||||
self.last_record_label.config(
|
||||
text=f"Последняя запись: {last_date} - {last_serial}",
|
||||
foreground="blue"
|
||||
)
|
||||
|
||||
# Обновляем состояние кнопки загрузки
|
||||
self.update_load_last_button()
|
||||
|
||||
return {
|
||||
"date": last_date,
|
||||
"serial": last_serial
|
||||
}
|
||||
else:
|
||||
self.last_record_label.config(
|
||||
text="Последняя запись: не найдена",
|
||||
foreground="gray"
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Ошибка при чтении serial.temp: {e}")
|
||||
self.last_record_label.config(
|
||||
text="Последняя запись: ошибка чтения",
|
||||
foreground="red"
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def save_last_serial_info(self, serial_number):
|
||||
"""Сохранить информацию о последней записи в файл serial.temp"""
|
||||
try:
|
||||
data = {
|
||||
"last_write_date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"last_serial": serial_number
|
||||
}
|
||||
|
||||
with self.serial_temp_file.open("w", encoding="utf-8") as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
# Обновляем информацию в интерфейсе
|
||||
self.load_last_serial_info()
|
||||
|
||||
except Exception as e:
|
||||
print(f"Ошибка при сохранении serial.temp: {e}")
|
||||
|
||||
def load_last_serial(self):
|
||||
"""Загрузить последний серийный номер из serial.temp в поля ввода"""
|
||||
info = self.load_last_serial_info()
|
||||
if info and info.get("serial"):
|
||||
serial = info["serial"]
|
||||
|
||||
# Разбиваем серийный номер на сегменты
|
||||
segments = serial.split("/")
|
||||
if len(segments) == len(self.segment_lengths):
|
||||
for i, seg in enumerate(segments):
|
||||
if i < len(self.vars):
|
||||
# Убираем буквенный префикс и устанавливаем только цифры
|
||||
if len(seg) >= 2: # Буква + хотя бы одна цифра
|
||||
digits = seg[1:] # Пропускаем первую букву
|
||||
self.vars[i].set(digits)
|
||||
|
||||
self._update_status()
|
||||
messagebox.showinfo(
|
||||
"Загрузка",
|
||||
f"Загружен последний серийный номер:\n{serial}"
|
||||
)
|
||||
return True
|
||||
else:
|
||||
messagebox.showwarning(
|
||||
"Ошибка формата",
|
||||
f"Формат последнего серийного номера не соответствует ожидаемому"
|
||||
)
|
||||
else:
|
||||
messagebox.showinfo(
|
||||
"Информация",
|
||||
"Нет данных о последнем серийном номере"
|
||||
)
|
||||
return False
|
||||
|
||||
def update_load_last_button(self):
|
||||
"""Обновить состояние кнопки загрузки последнего серийника"""
|
||||
if self.serial_temp_file.exists():
|
||||
self.load_last_btn.config(state=tk.NORMAL)
|
||||
else:
|
||||
self.load_last_btn.config(state=tk.DISABLED)
|
||||
|
||||
def _check_existing_serial(self):
|
||||
"""Проверить существующий серийный номер при запуске"""
|
||||
try:
|
||||
if SERIAL_FILE.exists():
|
||||
with SERIAL_FILE.open("r", encoding="utf-8") as f:
|
||||
serial = f.readline().strip()
|
||||
if serial:
|
||||
self.current_serial_label.config(
|
||||
text=f"Текущий серийный номер: {serial}",
|
||||
foreground="green"
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _on_segment_change(self, index: int):
|
||||
"""Автоматически ограничивает длину сегмента и переносит фокус далее."""
|
||||
if self._updating:
|
||||
return
|
||||
|
||||
try:
|
||||
self._updating = True
|
||||
value = self.vars[index].get()
|
||||
max_len = self.segment_lengths[index] - 1 # Один символ уже занят буквой
|
||||
|
||||
# Разрешаем только цифры
|
||||
digits_only = ''.join(filter(str.isdigit, value))
|
||||
|
||||
# Обрезаем лишние цифры
|
||||
if len(digits_only) > max_len:
|
||||
digits_only = digits_only[:max_len]
|
||||
|
||||
# Устанавливаем очищенное значение
|
||||
if digits_only != value:
|
||||
self.vars[index].set(digits_only)
|
||||
|
||||
# Если сегмент заполнен, переходим к следующему
|
||||
if len(digits_only) == max_len and index + 1 < len(self.entries):
|
||||
next_entry = self.entries[index + 1]
|
||||
next_entry.focus_set()
|
||||
next_entry.icursor("end")
|
||||
|
||||
# Обновляем статус
|
||||
self._update_status()
|
||||
finally:
|
||||
self._updating = False
|
||||
|
||||
def _on_key(self, event, index: int):
|
||||
"""Backspace на пустом поле переносит фокус на предыдущий сегмент."""
|
||||
if event.keysym == "BackSpace":
|
||||
entry = self.entries[index]
|
||||
try:
|
||||
cursor_pos = entry.index(tk.INSERT)
|
||||
except tk.TclError:
|
||||
cursor_pos = 0
|
||||
|
||||
if cursor_pos == 0 and index > 0 and entry.get() == "":
|
||||
prev_entry = self.entries[index - 1]
|
||||
prev_entry.focus_set()
|
||||
prev_entry.icursor("end")
|
||||
|
||||
def _get_segments(self):
|
||||
"""Получить значения всех сегментов"""
|
||||
segments = []
|
||||
for i, (var, prefix) in enumerate(zip(self.vars, self.prefixes)):
|
||||
digits = var.get().strip()
|
||||
segments.append(f"{prefix}{digits}")
|
||||
return segments
|
||||
|
||||
def _get_full_serial(self):
|
||||
"""Получить полный серийный номер"""
|
||||
segments = self._get_segments()
|
||||
return "/".join(segments)
|
||||
|
||||
def _check_complete(self):
|
||||
"""Проверить, полностью ли заполнены все сегменты"""
|
||||
segments = self._get_segments()
|
||||
for seg, length in zip(segments, self.segment_lengths):
|
||||
if len(seg) != length:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _update_status(self):
|
||||
"""Обновить статус заполнения"""
|
||||
if self._check_complete():
|
||||
serial = self._get_full_serial()
|
||||
self.status_label.config(
|
||||
text=f"Статус: ✓ Готово к сохранению: {serial}",
|
||||
foreground="green"
|
||||
)
|
||||
else:
|
||||
segments = self._get_segments()
|
||||
partial_serial = "/".join(segments) if any(segments) else "Не заполнено"
|
||||
self.status_label.config(
|
||||
text=f"Статус: {partial_serial}",
|
||||
foreground="orange" if any(segments) else "red"
|
||||
)
|
||||
|
||||
def clear_fields(self):
|
||||
"""Очистить все поля ввода"""
|
||||
for var in self.vars:
|
||||
var.set("")
|
||||
self.entries[0].focus_set()
|
||||
self.status_label.config(
|
||||
text="Статус: Не заполнено",
|
||||
foreground="red"
|
||||
)
|
||||
|
||||
def check_format(self):
|
||||
"""Проверить формат введённых данных"""
|
||||
segments = [v.get().strip() for v in self.vars]
|
||||
|
||||
if not segments or all(seg == "" for seg in segments):
|
||||
messagebox.showinfo(
|
||||
"Проверка формата",
|
||||
"Поля не заполнены."
|
||||
)
|
||||
return
|
||||
|
||||
errors = []
|
||||
for i, (seg, length, prefix) in enumerate(zip(segments, self.segment_lengths, self.prefixes)):
|
||||
expected_digits = length - 1 # Один символ - буква
|
||||
if len(seg) != expected_digits:
|
||||
errors.append(f"Сегмент {prefix}: ожидается {expected_digits} цифр, получено {len(seg)}")
|
||||
elif not seg.isdigit():
|
||||
errors.append(f"Сегмент {prefix}: должны быть только цифры")
|
||||
|
||||
if errors:
|
||||
messagebox.showwarning(
|
||||
"Проверка формата",
|
||||
"Найдены ошибки:\n\n" + "\n".join(errors)
|
||||
)
|
||||
else:
|
||||
serial = self._get_full_serial()
|
||||
messagebox.showinfo(
|
||||
"Проверка формата",
|
||||
f"✓ Формат корректен!\n\nСерийный номер:\n{serial}"
|
||||
)
|
||||
|
||||
def save_serial(self):
|
||||
"""Сохранить серийный номер в файл."""
|
||||
if not self._check_complete():
|
||||
messagebox.showerror(
|
||||
"Ошибка",
|
||||
"Заполните все части серийного номера полностью."
|
||||
)
|
||||
return
|
||||
|
||||
serial = self._get_full_serial()
|
||||
|
||||
try:
|
||||
# Создаем директорию, если её нет
|
||||
DOCUMENTS_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Добавляем новую строку в конец файла
|
||||
with SERIAL_FILE.open("w", encoding="utf-8") as f:
|
||||
f.write(serial + "\n")
|
||||
|
||||
# Сохраняем информацию о последней записи
|
||||
self.save_last_serial_info(serial)
|
||||
|
||||
# Обновляем информацию о текущем серийном номере
|
||||
self.current_serial_label.config(
|
||||
text=f"Текущий серийный номер: {serial}",
|
||||
foreground="green"
|
||||
)
|
||||
|
||||
messagebox.showinfo(
|
||||
"Готово",
|
||||
f"Серийный номер успешно сохранён!\n\n"
|
||||
f"Номер: {serial}\n\n"
|
||||
f"Информация сохранена в:\n{self.serial_temp_file}"
|
||||
)
|
||||
|
||||
# Обновляем статус
|
||||
self.status_label.config(
|
||||
text=f"Статус: ✓ Сохранено: {serial}",
|
||||
foreground="green"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
messagebox.showerror(
|
||||
"Ошибка сохранения",
|
||||
f"Не удалось сохранить серийный номер:\n{e}"
|
||||
)
|
||||
|
||||
def get_serial_number(self):
|
||||
"""Получить текущий серийный номер (для использования другими модулями)"""
|
||||
if self._check_complete():
|
||||
return self._get_full_serial()
|
||||
return None
|
||||
|
||||
def load_serial_from_file(self):
|
||||
"""Загрузить серийный номер из файла (если существует)"""
|
||||
try:
|
||||
if SERIAL_FILE.exists():
|
||||
with SERIAL_FILE.open("r", encoding="utf-8") as f:
|
||||
serial = f.readline().strip()
|
||||
segments = serial.split("/")
|
||||
|
||||
if len(segments) == len(self.segment_lengths):
|
||||
for i, seg in enumerate(segments):
|
||||
if i < len(self.vars):
|
||||
# Убираем буквенный префикс и устанавливаем только цифры
|
||||
if len(seg) >= 2: # Буква + хотя бы одна цифра
|
||||
digits = seg[1:] # Пропускаем первую букву
|
||||
self.vars[i].set(digits)
|
||||
|
||||
self._update_status()
|
||||
# Обновляем информацию о текущем серийном номере
|
||||
self.current_serial_label.config(
|
||||
text=f"Текущий серийный номер: {serial}",
|
||||
foreground="green"
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
267
Tools/Configapp/modules/server_module.py
Normal file
267
Tools/Configapp/modules/server_module.py
Normal file
@ -0,0 +1,267 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Добавляем родительскую директорию в путь для импорта
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
# DOCUMENTS_PATH как в других вкладках
|
||||
try:
|
||||
import config
|
||||
DOCUMENTS_PATH = config.DOCUMENTS_PATH
|
||||
except ImportError:
|
||||
DOCUMENTS_PATH = Path(os.environ.get("USERPROFILE", str(Path.home()))) / "Documents" / "C4"
|
||||
|
||||
|
||||
class ServerModuleTab:
|
||||
"""
|
||||
Вкладка управления веб-сервером (сайт-панелью):
|
||||
- чекбокс "Запускать сайт-панель" => Documents\\C4\\serverOn.rr (1/0)
|
||||
- пароль админа (до 10 символов) => AppData\\LocalLow\\Robotic Retailers\\Robonect4\\admin_password.txt
|
||||
- снизу статус: состояние сервера и текущий пароль (или предупреждение о дефолтном 1234)
|
||||
"""
|
||||
|
||||
def __init__(self, parent_frame):
|
||||
self.parent = parent_frame
|
||||
|
||||
# Пути
|
||||
self.server_on_file = DOCUMENTS_PATH / "serverOn.rr"
|
||||
|
||||
user_home = Path(os.environ.get("USERPROFILE", str(Path.home())))
|
||||
self.password_file = (
|
||||
user_home
|
||||
/ "AppData"
|
||||
/ "LocalLow"
|
||||
/ "Robotic Retailers"
|
||||
/ "Robonect4"
|
||||
/ "admin_password.txt"
|
||||
)
|
||||
|
||||
# Vars
|
||||
self.server_enabled_var = tk.BooleanVar(value=False)
|
||||
self.password_var = tk.StringVar(value="")
|
||||
|
||||
# UI container
|
||||
self.container = ttk.Frame(parent_frame, padding=20)
|
||||
self.container.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
self._build_ui()
|
||||
|
||||
# Обновлять статус при открытии вкладки
|
||||
# (в Notebook при переключении вкладок обычно триггерится Visibility)
|
||||
self.parent.bind("<Visibility>", lambda e: self.update_status())
|
||||
|
||||
# Загрузим текущее состояние
|
||||
self.load_state()
|
||||
self.update_status()
|
||||
|
||||
# ---------------- UI ----------------
|
||||
|
||||
def _build_ui(self):
|
||||
# Заголовок
|
||||
title_frame = ttk.Frame(self.container)
|
||||
title_frame.pack(fill=tk.X, pady=(0, 20))
|
||||
|
||||
ttk.Label(
|
||||
title_frame,
|
||||
text="Управление веб-сервером",
|
||||
font=("Segoe UI", 12, "bold"),
|
||||
).pack()
|
||||
|
||||
ttk.Separator(self.container, orient="horizontal").pack(fill=tk.X, pady=(0, 20))
|
||||
|
||||
# Основной блок настроек
|
||||
settings_frame = ttk.LabelFrame(self.container, text="Настройки", padding=15)
|
||||
settings_frame.pack(fill=tk.X, pady=(0, 15))
|
||||
|
||||
# 1) Чекбокс
|
||||
self.server_check = ttk.Checkbutton(
|
||||
settings_frame,
|
||||
text="Запускать сайт-панель",
|
||||
variable=self.server_enabled_var,
|
||||
command=self._on_server_toggle,
|
||||
)
|
||||
self.server_check.pack(anchor=tk.W, pady=(0, 12))
|
||||
|
||||
# 2) Пароль
|
||||
pass_row = ttk.Frame(settings_frame)
|
||||
pass_row.pack(fill=tk.X, pady=(0, 8))
|
||||
|
||||
ttk.Label(pass_row, text="Пароль администратора (до 10 символов):").pack(
|
||||
side=tk.LEFT, padx=(0, 10)
|
||||
)
|
||||
|
||||
vcmd = (self.container.register(self._validate_password_len), "%P")
|
||||
self.password_entry = ttk.Entry(
|
||||
pass_row,
|
||||
textvariable=self.password_var,
|
||||
width=20,
|
||||
show="*",
|
||||
validate="key",
|
||||
validatecommand=vcmd,
|
||||
)
|
||||
self.password_entry.pack(side=tk.LEFT)
|
||||
|
||||
# Кнопки
|
||||
btn_row = ttk.Frame(settings_frame)
|
||||
btn_row.pack(fill=tk.X, pady=(10, 0))
|
||||
|
||||
ttk.Button(
|
||||
btn_row,
|
||||
text="Сохранить пароль",
|
||||
command=self._save_password,
|
||||
width=25,
|
||||
).pack(side=tk.LEFT, padx=(0, 10))
|
||||
|
||||
ttk.Button(
|
||||
btn_row,
|
||||
text="Обновить статус",
|
||||
command=self.update_status,
|
||||
width=25,
|
||||
).pack(side=tk.LEFT)
|
||||
|
||||
# Статус снизу
|
||||
self.status_frame = ttk.LabelFrame(self.container, text="Статус", padding=15)
|
||||
self.status_frame.pack(fill=tk.X)
|
||||
|
||||
self.server_status_label = ttk.Label(
|
||||
self.status_frame,
|
||||
text="Сайт-панель: —",
|
||||
font=("Segoe UI", 10),
|
||||
)
|
||||
self.server_status_label.pack(anchor=tk.W, pady=(0, 6))
|
||||
|
||||
self.password_status_label = ttk.Label(
|
||||
self.status_frame,
|
||||
text="Пароль: —",
|
||||
font=("Segoe UI", 10),
|
||||
)
|
||||
self.password_status_label.pack(anchor=tk.W, pady=(0, 10))
|
||||
|
||||
# Пути (серым)
|
||||
self.paths_label = ttk.Label(
|
||||
self.status_frame,
|
||||
text=f"serverOn.rr: {self.server_on_file}\npassword: {self.password_file}",
|
||||
font=("Segoe UI", 9),
|
||||
foreground="gray",
|
||||
)
|
||||
self.paths_label.pack(anchor=tk.W)
|
||||
|
||||
# ---------------- Logic ----------------
|
||||
|
||||
def _validate_password_len(self, proposed_value: str) -> bool:
|
||||
"""Разрешаем ввод максимум 10 символов."""
|
||||
return len(proposed_value) <= 10
|
||||
|
||||
def load_state(self):
|
||||
"""Загрузить состояние из файлов в UI."""
|
||||
# serverOn.rr
|
||||
enabled = self._read_server_enabled()
|
||||
self.server_enabled_var.set(enabled)
|
||||
|
||||
# password
|
||||
pwd = self._read_password()
|
||||
# Если вдруг в файле длиннее 10 — в поле покажем первые 10, а статус покажет как есть
|
||||
self.password_var.set(pwd[:10] if pwd else "")
|
||||
|
||||
def _on_server_toggle(self):
|
||||
"""Сразу пишем 1/0 в serverOn.rr при клике по чекбоксу."""
|
||||
try:
|
||||
self._write_server_enabled(self.server_enabled_var.get())
|
||||
self.update_status()
|
||||
except Exception as e:
|
||||
messagebox.showerror("Ошибка", f"Не удалось записать serverOn.rr:\n{e}")
|
||||
# Откатим UI к факту из файла
|
||||
self.server_enabled_var.set(self._read_server_enabled())
|
||||
self.update_status()
|
||||
|
||||
def _write_server_enabled(self, enabled: bool):
|
||||
DOCUMENTS_PATH.mkdir(parents=True, exist_ok=True)
|
||||
with open(self.server_on_file, "w", encoding="utf-8") as f:
|
||||
f.write("1" if enabled else "0")
|
||||
|
||||
def _read_server_enabled(self) -> bool:
|
||||
try:
|
||||
if not self.server_on_file.exists():
|
||||
return False
|
||||
content = self.server_on_file.read_text(encoding="utf-8").strip()
|
||||
return content == "1"
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _save_password(self):
|
||||
"""Сохранить пароль в admin_password.txt"""
|
||||
try:
|
||||
pwd = (self.password_var.get() or "").strip()
|
||||
|
||||
if len(pwd) > 10:
|
||||
messagebox.showerror("Ошибка", "Пароль должен быть не длиннее 10 символов.")
|
||||
return
|
||||
|
||||
# Если пусто — считаем что пароль НЕ задан (удалим файл, если был)
|
||||
if pwd == "":
|
||||
if self.password_file.exists():
|
||||
try:
|
||||
self.password_file.unlink()
|
||||
except Exception:
|
||||
# если не получилось удалить — просто перезапишем пустым
|
||||
self.password_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
self.password_file.write_text("", encoding="utf-8")
|
||||
self.update_status()
|
||||
messagebox.showinfo("Готово", "Пароль очищен (не задан).")
|
||||
return
|
||||
|
||||
self.password_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
self.password_file.write_text(pwd, encoding="utf-8")
|
||||
|
||||
self.update_status()
|
||||
messagebox.showinfo("Готово", "Пароль сохранён.")
|
||||
|
||||
except Exception as e:
|
||||
messagebox.showerror("Ошибка", f"Не удалось сохранить пароль:\n{e}")
|
||||
|
||||
def _read_password(self) -> str:
|
||||
try:
|
||||
if not self.password_file.exists():
|
||||
return ""
|
||||
return self.password_file.read_text(encoding="utf-8").strip()
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
def update_status(self):
|
||||
"""Обновить статус-фрейм: состояние сервера + пароль."""
|
||||
enabled = self._read_server_enabled()
|
||||
pwd = self._read_password()
|
||||
|
||||
# Сервер
|
||||
if enabled:
|
||||
self.server_status_label.config(
|
||||
text="Сайт-панель: ВКЛЮЧЕНА (будет запускаться)",
|
||||
foreground="green",
|
||||
)
|
||||
else:
|
||||
self.server_status_label.config(
|
||||
text="Сайт-панель: ВЫКЛЮЧЕНА (не будет запускаться)",
|
||||
foreground="gray",
|
||||
)
|
||||
|
||||
# Пароль
|
||||
if not pwd:
|
||||
self.password_status_label.config(
|
||||
text="Пароль: пароль не задан. Пароль по умолчанию 1234",
|
||||
foreground="red",
|
||||
)
|
||||
else:
|
||||
self.password_status_label.config(
|
||||
text=f"Пароль: {pwd}",
|
||||
foreground="green",
|
||||
)
|
||||
|
||||
# Для совместимости с main.save_all (если у тебя есть общая кнопка "сохранить всё")
|
||||
def save_server_config(self):
|
||||
"""Сохранить текущее состояние из UI в файлы."""
|
||||
self._write_server_enabled(self.server_enabled_var.get())
|
||||
# пароль сохраняем как по кнопке (включая “очистку”)
|
||||
self._save_password()
|
||||
BIN
Tools/Configapp/schemes/scheme_v1.jpg
Normal file
BIN
Tools/Configapp/schemes/scheme_v1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
BIN
Tools/Configapp/schemes/scheme_v2.jpg
Normal file
BIN
Tools/Configapp/schemes/scheme_v2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
4
Tools/Configapp/serial.temp
Normal file
4
Tools/Configapp/serial.temp
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"last_write_date": "2025-12-08 14:52:52",
|
||||
"last_serial": "A020/D08122025/V002/N008"
|
||||
}
|
||||
41
Tools/Configapp/utils.py
Normal file
41
Tools/Configapp/utils.py
Normal file
@ -0,0 +1,41 @@
|
||||
# utils.py
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def save_config(config_dict, filename="config.json"):
|
||||
"""Сохранить конфигурацию в JSON файл"""
|
||||
config_path = Path.home() / "Documents" / "C4" / filename
|
||||
config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(config_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(config_dict, f, indent=2, ensure_ascii=False)
|
||||
|
||||
return config_path
|
||||
|
||||
|
||||
def load_config(filename="config.json"):
|
||||
"""Загрузить конфигурацию из JSON файла"""
|
||||
config_path = Path.home() / "Documents" / "C4" / filename
|
||||
|
||||
if config_path.exists():
|
||||
with open(config_path, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
return {}
|
||||
|
||||
|
||||
class ModuleManager:
|
||||
"""Менеджер для работы с модулями"""
|
||||
|
||||
def __init__(self):
|
||||
self.modules = {}
|
||||
|
||||
def register_module(self, name, module_class):
|
||||
"""Зарегистрировать модуль"""
|
||||
self.modules[name] = module_class
|
||||
|
||||
def create_module(self, name, parent_frame):
|
||||
"""Создать экземпляр модуля"""
|
||||
if name in self.modules:
|
||||
return self.modules[name](parent_frame)
|
||||
return None
|
||||
Loading…
x
Reference in New Issue
Block a user