Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
6faf65ad08 | |||
0d694adc2d | |||
ec76940dca | |||
6242dd7b0d | |||
703d2dfc4a | |||
52f782b4e8 | |||
7351100e55 | |||
c1580f6ace |
24
Changelog
24
Changelog
@ -4,7 +4,31 @@ Changelog for shared_libs
|
||||
|
||||
- add Info Window for user in delete logfile
|
||||
bevore delete logfile.
|
||||
|
||||
|
||||
### Added
|
||||
09.07.2025
|
||||
|
||||
- fix new icon for install Update
|
||||
|
||||
|
||||
### Added
|
||||
29.06.2025
|
||||
|
||||
- add new icon for install Update
|
||||
|
||||
- replace download with updater methode
|
||||
|
||||
- add methode for open lxtools_installer Appimage
|
||||
|
||||
- add german translation for logviewer
|
||||
|
||||
### Added
|
||||
15-06-2025
|
||||
|
||||
- Update MessageDialog Class description
|
||||
- import LxTools with try exception.
|
||||
|
||||
### Added
|
||||
14-06-2025
|
||||
|
||||
|
12
README.md
12
README.md
@ -1,3 +1,13 @@
|
||||
# shared_libs
|
||||
|
||||
Module Project for apps by git.ilunix.de
|
||||
Module Project for apps by git.ilunix.de
|
||||
Examples with a Theme from Projekt Wire-Py
|
||||
|
||||
# Screenshots
|
||||
[](https://fb.ilunix.de/share/KtaTPMMq)
|
||||
[](https://fb.ilunix.de/share/cRO_ksrM)
|
||||
[](https://fb.ilunix.de/share/1JEdSJcI)
|
||||
[](https://fb.ilunix.de/share/1XxNey7y7)
|
||||
[](https://fb.ilunix.de/share/4HCxiNwB)
|
||||
[](https://fb.ilunix.de/share/uui8b1xx)
|
||||
[](https://fb.ilunix.de/share/54OM6wUC)
|
||||
|
2
gitea.py
2
gitea.py
@ -67,7 +67,7 @@ class GiteaUpdate:
|
||||
"""
|
||||
|
||||
try:
|
||||
to_down: str = f"wget -qP {Path.home()} {" "} {urld}"
|
||||
to_down: str = f"wget -qP {Path.home()} {' '} {urld}"
|
||||
result: int = subprocess.call(to_down, shell=True)
|
||||
if result == 0:
|
||||
shutil.chown(f"{Path.home()}/{res}.zip", 1000, 1000)
|
||||
|
BIN
languages/de/logviewer.mo
Normal file
BIN
languages/de/logviewer.mo
Normal file
Binary file not shown.
163
languages/de/logviewer.po
Normal file
163
languages/de/logviewer.po
Normal file
@ -0,0 +1,163 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR polunga40@unity-mail.de, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-29 17:25+0200\n"
|
||||
"PO-Revision-Date: 2025-06-29 18:00+0200\n"
|
||||
"Last-Translator: Désiré Werner Menrath <polunga40@unity-mail.de>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: de_DE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 3.4.2\n"
|
||||
|
||||
#: gitea.py:127
|
||||
msgid "Download Successful"
|
||||
msgstr "Herunterladen erfolgreich"
|
||||
|
||||
#: gitea.py:128
|
||||
msgid "Your zip file is in home directory"
|
||||
msgstr "Ihre ZIP-Datei befindet sich im Home-Verzeichnis"
|
||||
|
||||
#: gitea.py:129
|
||||
msgid "Download error"
|
||||
msgstr "Fehler beim Herunterladen"
|
||||
|
||||
#: gitea.py:130
|
||||
msgid "Download failed! Please try again"
|
||||
msgstr "Herunterladen fehlgeschlagen! Bitte versuchen Sie es erneut."
|
||||
|
||||
#: gitea.py:131
|
||||
msgid "Download failed! No internet connection!"
|
||||
msgstr "Herunterladen fehlgeschlagen! Keine Internetverbindung!"
|
||||
|
||||
#: logviewer.py:102
|
||||
msgid "Load Log"
|
||||
msgstr "Logdatei laden"
|
||||
|
||||
#: logviewer.py:107
|
||||
msgid "Options"
|
||||
msgstr "Optionen"
|
||||
|
||||
#: logviewer.py:116
|
||||
msgid "Disable Updates"
|
||||
msgstr "Updates deaktivieren"
|
||||
|
||||
#: logviewer.py:149
|
||||
msgid "About"
|
||||
msgstr "Über"
|
||||
|
||||
#: logviewer.py:184
|
||||
msgid "Update search off"
|
||||
msgstr "Suche nach Updates ausgeschaltet"
|
||||
|
||||
#: logviewer.py:185
|
||||
msgid "Updates you have disabled"
|
||||
msgstr "Sie haben Updates deaktiviert"
|
||||
|
||||
#: logviewer.py:192
|
||||
msgid "No Server Connection!"
|
||||
msgstr "Keine Verbindung zum Server!"
|
||||
|
||||
#: logviewer.py:197
|
||||
msgid "Could not connect to update server"
|
||||
msgstr "Verbindung zum Update-Server nicht möglich"
|
||||
|
||||
#: logviewer.py:202
|
||||
msgid "No Updates"
|
||||
msgstr "Keine Updates verfügbar"
|
||||
|
||||
#: logviewer.py:203
|
||||
msgid "Congratulations! Wire-Py is up to date"
|
||||
msgstr "Glückwunsch! Wire-Py ist aktuell."
|
||||
|
||||
#: logviewer.py:223
|
||||
msgid "Click to install new version"
|
||||
msgstr "Klicken Sie, um die neue Version zu installieren"
|
||||
|
||||
#: logviewer.py:232
|
||||
msgid ""
|
||||
"Logviewer a simple Gui for View Logfiles.\n"
|
||||
"\n"
|
||||
"Logviewer is open source software written in Python.\n"
|
||||
"\n"
|
||||
"Email: polunga40@unity-mail.de also likes for donation.\n"
|
||||
"\n"
|
||||
"Use without warranty!\n"
|
||||
msgstr ""
|
||||
"Logviewer eine einfache GUI zur Anzeige von Protokolldateien.\n"
|
||||
"\n"
|
||||
"Logviewer ist Open-Source-Software, geschrieben in Python.\n"
|
||||
"\n"
|
||||
"E-Mail: polunga40@unity-mail.de (Spenden sind willkommen).\n"
|
||||
"\n"
|
||||
"Verwendung ohne Gewähr!\n"
|
||||
|
||||
#: logviewer.py:288
|
||||
msgid "Disable Tooltips"
|
||||
msgstr "Tooltips deaktivieren"
|
||||
|
||||
#: logviewer.py:291
|
||||
msgid "Enable Tooltips"
|
||||
msgstr "Tooltips aktivieren"
|
||||
|
||||
#: logviewer.py:319
|
||||
msgid "Dark"
|
||||
msgstr "Dunkel"
|
||||
|
||||
#: logviewer.py:321
|
||||
msgid "Light"
|
||||
msgstr "Hell"
|
||||
|
||||
#: logviewer.py:362
|
||||
msgid "Copy"
|
||||
msgstr "Kopieren"
|
||||
|
||||
#: logviewer.py:363
|
||||
msgid "Paste"
|
||||
msgstr "Einfügen"
|
||||
|
||||
#: logviewer.py:367
|
||||
msgid "Search"
|
||||
msgstr "Suchen"
|
||||
|
||||
#: logviewer.py:371
|
||||
msgid "Delete_Log"
|
||||
msgstr "Logdatei löschen"
|
||||
|
||||
#: logviewer.py:456
|
||||
msgid "A mistake occurred: {str(e)}"
|
||||
msgstr "Ein Fehler ist aufgetreten: {str(e)}"
|
||||
|
||||
#: logviewer.py:457
|
||||
msgid ""
|
||||
"A mistake occurred:\n"
|
||||
"{str(e)}\n"
|
||||
msgstr ""
|
||||
"Ein Fehler ist aufgetreten:\n"
|
||||
"{str(e)}\n"
|
||||
|
||||
#: logviewer.py:474
|
||||
#, python-brace-format
|
||||
msgid "A mistake occurred: {e}"
|
||||
msgstr "Ein Fehler ist aufgetreten: {e}"
|
||||
|
||||
#: logviewer.py:475
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"A mistake occurred:\n"
|
||||
"{e}\n"
|
||||
msgstr ""
|
||||
"Ein Fehler ist aufgetreten:\n"
|
||||
"{e}\n"
|
||||
|
||||
#: logview_app_config.py:146
|
||||
msgid "Click for Settings"
|
||||
msgstr "Klick für Einstellungen"
|
@ -51,14 +51,14 @@ class AppConfig:
|
||||
|
||||
# Updates
|
||||
# 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year
|
||||
VERSION: str = "v. 1.06.0325"
|
||||
VERSION: str = "v. 1.07.0925"
|
||||
UPDATE_URL: str = "https://git.ilunix.de/api/v1/repos/punix/shared_libs/releases"
|
||||
DOWNLOAD_URL: str = "https://git.ilunix.de/punix/shared_libs/archive"
|
||||
|
||||
# UI configuration
|
||||
UI_CONFIG: Dict[str, Any] = {
|
||||
"window_title2": "LogViewer",
|
||||
"window_size": (600, 383),
|
||||
"window_size": (590, 460),
|
||||
"font_family": "Ubuntu",
|
||||
"font_size": 11,
|
||||
"resizable_window": (True, True),
|
||||
@ -66,8 +66,6 @@ class AppConfig:
|
||||
|
||||
# Images and icons paths
|
||||
IMAGE_PATHS: Dict[str, Path] = {
|
||||
"icon_info": "/usr/share/icons/lx-icons/64/info.png",
|
||||
"icon_error": "/usr/share/icons/lx-icons/64/error.png",
|
||||
"icon_log": "/usr/share/icons/lx-icons/48/log.png",
|
||||
}
|
||||
|
||||
|
46
logviewer.py
46
logviewer.py
@ -4,7 +4,9 @@ import logging
|
||||
import tkinter as tk
|
||||
from tkinter import TclError, filedialog, ttk
|
||||
from pathlib import Path
|
||||
import os
|
||||
import webbrowser
|
||||
import subprocess
|
||||
from functools import partial
|
||||
from shared_libs.gitea import GiteaUpdate
|
||||
from shared_libs.message import MessageDialog
|
||||
@ -17,7 +19,6 @@ from shared_libs.common_tools import (
|
||||
)
|
||||
import sys
|
||||
from file_and_dir_ensure import prepare_app_environment
|
||||
import webbrowser
|
||||
|
||||
|
||||
class LogViewer(tk.Tk):
|
||||
@ -45,9 +46,12 @@ class LogViewer(tk.Tk):
|
||||
theme = ConfigManager.get("theme")
|
||||
ThemeManager.change_theme(self, theme)
|
||||
LxTools.center_window_cross_platform(self, self.x_width, self.y_height)
|
||||
self.createWidgets(_)
|
||||
self.createWidgets(modul_name, _)
|
||||
self.load_file(_, modul_name=modul_name)
|
||||
self.log_icon = tk.PhotoImage(file=modul_name.AppConfig.IMAGE_PATHS["icon_log"])
|
||||
self.log_icon = tk.PhotoImage(file="/usr/share/icons/lx-icons/48/log.png")
|
||||
self.update_icon = tk.PhotoImage(
|
||||
file="/usr/share/icons/lx-icons/16/settings.png"
|
||||
)
|
||||
self.iconphoto(True, self.log_icon)
|
||||
self.grid_rowconfigure(0, weight=1)
|
||||
self.grid_rowconfigure(1, weight=1)
|
||||
@ -165,6 +169,15 @@ class LogViewer(tk.Tk):
|
||||
else:
|
||||
self.updates_lb.grid_remove()
|
||||
|
||||
def updater(self):
|
||||
"""Start the lxtools_installer"""
|
||||
tmp_dir = Path("/tmp/lxtools")
|
||||
Path.mkdir(tmp_dir, exist_ok=True)
|
||||
os.chdir(tmp_dir)
|
||||
result = subprocess.run(["/usr/local/bin/lxtools_installer"], check=False)
|
||||
if result.returncode != 0:
|
||||
MessageDialog("error", result.stderr)
|
||||
|
||||
# Update the labels based on the result
|
||||
def update_ui_for_update(self, res, modul_name, _):
|
||||
"""Update UI elements based on an update check result"""
|
||||
@ -201,25 +214,20 @@ class LogViewer(tk.Tk):
|
||||
|
||||
else:
|
||||
self.set_update.set(value=0)
|
||||
update_text = f"Update {res} {_('available!')}"
|
||||
|
||||
# Clear the label text since we'll show the button instead
|
||||
self.update_label.set("")
|
||||
|
||||
# Create the update button
|
||||
self.update_btn = ttk.Menubutton(self.menu_frame, text=update_text)
|
||||
self.update_btn = ttk.Button(
|
||||
self.menu_frame,
|
||||
image=self.update_icon,
|
||||
style="Toolbutton",
|
||||
command=self.updater,
|
||||
)
|
||||
self.update_btn.grid(column=5, row=0, padx=0)
|
||||
Tooltip(
|
||||
self.update_btn, _("Click to download new version"), self.tooltip_state
|
||||
)
|
||||
|
||||
self.download = tk.Menu(self, relief="flat")
|
||||
self.update_btn.configure(menu=self.download, style="Toolbutton")
|
||||
self.download.add_command(
|
||||
label=_("Download"),
|
||||
command=lambda: GiteaUpdate.download(
|
||||
f"{modul_name.AppConfig.DOWNLOAD_URL}/{res}.zip", res
|
||||
),
|
||||
self.update_btn, _("Click to install new version"), self.tooltip_state
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@ -328,7 +336,7 @@ class LogViewer(tk.Tk):
|
||||
# Update Menulfield
|
||||
self.settings.entryconfigure(2, label=self.theme_label.get())
|
||||
|
||||
def createWidgets(self, _):
|
||||
def createWidgets(self, modul_name, _):
|
||||
|
||||
text_frame = ttk.Frame(self)
|
||||
text_frame.grid(row=1, column=0, padx=5, pady=5, sticky=tk.NSEW)
|
||||
@ -363,11 +371,11 @@ class LogViewer(tk.Tk):
|
||||
self.text_area.bind("<Button-3>", self.show_context_menu)
|
||||
self._entry.bind("<Button-3>", self.show_context_menu)
|
||||
|
||||
search_button = ttk.Button(next_frame, text="Search", command=self._onFind)
|
||||
search_button = ttk.Button(next_frame, text=_("Search"), command=self._onFind)
|
||||
search_button.grid(row=0, column=0, padx=5, pady=5, sticky=tk.EW)
|
||||
|
||||
delete_button = ttk.Button(
|
||||
next_frame, text="Delete_Log", command=self.delete_file
|
||||
next_frame, text=_("Delete_Log"), command=self.delete_file
|
||||
)
|
||||
delete_button.grid(row=0, column=2, padx=5, pady=5, sticky=tk.EW)
|
||||
|
||||
@ -458,7 +466,7 @@ class LogViewer(tk.Tk):
|
||||
def directory_load(self, modul_name, _):
|
||||
|
||||
filepath = filedialog.askopenfilename(
|
||||
initialdir=f"{Path.home() / ".local/share/lxlogs/"}",
|
||||
initialdir=f"{Path.home() / '.local/share/lxlogs/'}",
|
||||
title="Select a Logfile File",
|
||||
filetypes=[("Logfiles", "*.log")],
|
||||
)
|
||||
|
224
message.py
224
message.py
@ -2,155 +2,104 @@ import os
|
||||
from typing import List, Optional, Dict
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from shared_libs.common_tools import LxTools
|
||||
|
||||
"""
|
||||
####################################################
|
||||
Attention! MessageDialog returns different values.
|
||||
From 3 buttons with Cancel, Cancel and the Close (x)
|
||||
None returns. otherwise always False.
|
||||
####################################################
|
||||
Usage Examples
|
||||
1. Basic Info Dialog
|
||||
from tkinter import Tk
|
||||
|
||||
root = Tk()
|
||||
dialog = MessageDialog(
|
||||
message_type="info",
|
||||
text="This is an information message.",
|
||||
buttons=["OK"],
|
||||
master=root,
|
||||
)
|
||||
result = dialog.show()
|
||||
print("User clicked OK:", result)
|
||||
|
||||
-----------------------------------------------------
|
||||
My Favorite Example,
|
||||
for simply information message:
|
||||
|
||||
MessageDialog(text="This is an information message.")
|
||||
result = MessageDialog(text="This is an information message.").show()
|
||||
-----------------------------------------------------
|
||||
Explanation: if you need the return value e.g. in the vaiable result,
|
||||
you need to add .show(). otherwise only if no root.mainloop z.b is used to test the window.
|
||||
#####################################################
|
||||
|
||||
2. Error Dialog with Custom Icon and Command
|
||||
def on_cancel():
|
||||
print("User canceled the operation.")
|
||||
|
||||
root = Tk()
|
||||
result = MessageDialog(
|
||||
message_type="error",
|
||||
text="An error occurred during processing.",
|
||||
buttons=["Retry", "Cancel"],
|
||||
commands=[None, on_cancel],
|
||||
icon="/path/to/custom/error_icon.png",
|
||||
title="Critical Error"
|
||||
).show()
|
||||
|
||||
print("User clicked Retry:", result)
|
||||
|
||||
-----------------------------------------------------
|
||||
My Favorite Example,
|
||||
for simply Error message:
|
||||
|
||||
MessageDialog(
|
||||
"error",
|
||||
text="An error occurred during processing.",
|
||||
).show()
|
||||
|
||||
#####################################################
|
||||
|
||||
3. Confirmation Dialog with Yes/No Buttons
|
||||
def on_confirm():
|
||||
print("User confirmed the action.")
|
||||
|
||||
root = Tk()
|
||||
dialog = MessageDialog(
|
||||
message_type="ask",
|
||||
text="Are you sure you want to proceed?",
|
||||
buttons=["Yes", "No"],
|
||||
commands=[on_confirm, None], # Either use comando or work with the values True and False
|
||||
)
|
||||
result = dialog.show()
|
||||
print("User confirmed:", result)
|
||||
-----------------------------------------------------
|
||||
|
||||
My Favorite Example,
|
||||
for simply Question message:
|
||||
|
||||
dialog = MessageDialog(
|
||||
"ask",
|
||||
text="Are you sure you want to proceed?",
|
||||
buttons=["Yes", "No"]
|
||||
).show()
|
||||
#####################################################
|
||||
|
||||
4. Warning Dialog with Custom Title
|
||||
|
||||
root = Tk()
|
||||
dialog = MessageDialog(
|
||||
message_type="warning",
|
||||
text="This action cannot be undone.",
|
||||
buttons=["Proceed", "Cancel"],
|
||||
title="Warning: Irreversible Action"
|
||||
)
|
||||
result = dialog.show()
|
||||
print("User proceeded:", result)
|
||||
-----------------------------------------------------
|
||||
And a special example for a "open link" button:
|
||||
Be careful not to forget to import it into the script in which this dialog is used!!!
|
||||
import webbrowser
|
||||
from functools import partial
|
||||
|
||||
dialog = MessageDialog(
|
||||
"ask",
|
||||
text="Are you sure you want to proceed?",
|
||||
buttons=["Yes", "Go to Exapmle"],
|
||||
commands=[
|
||||
None, # Default on "OK"
|
||||
partial(webbrowser.open, "https://exapmle.com"),
|
||||
],
|
||||
icon="/pathh/to/custom/icon.png",
|
||||
title="Example",
|
||||
).show()
|
||||
|
||||
|
||||
In all dialogues, a font can also be specified as a tuple. With font=("ubuntu", 11)
|
||||
and wraplength=300, the text is automatically wrapped.
|
||||
"""
|
||||
try:
|
||||
from manager import LxTools
|
||||
except (ModuleNotFoundError, NameError):
|
||||
from shared_libs.common_tools import LxTools
|
||||
|
||||
|
||||
class MessageDialog:
|
||||
"""
|
||||
A customizable message dialog window using tkinter.
|
||||
A customizable message dialog window using tkinter for user interaction.
|
||||
|
||||
This class creates modal dialogs for displaying information, warnings, errors,
|
||||
or questions to the user. It supports multiple button configurations and custom
|
||||
icons. The dialog is centered on the screen and handles user interactions.
|
||||
or questions to the user. It supports multiple button configurations, custom
|
||||
icons, keyboard navigation, and command binding. The dialog is centered on the
|
||||
screen and handles user interactions with focus management and accessibility.
|
||||
|
||||
Attributes:
|
||||
message_type (str): Type of message ("info", "error", "warning", "ask").
|
||||
text (str): Main message content.
|
||||
text (str): Main message content to display.
|
||||
buttons (List[str]): List of button labels (e.g., ["OK", "Cancel"]).
|
||||
result (bool): True if the user clicked a positive button (like "Yes" or "OK"), else False.
|
||||
icons: Dictionary mapping message types to tkinter.PhotoImage objects.
|
||||
result (bool or None):
|
||||
- True for positive actions (Yes, OK)
|
||||
- False for negative actions (No, Cancel)
|
||||
- None if "Cancel" was clicked with ≥3 buttons
|
||||
icons: Dictionary mapping message types to tkinter.PhotoImage objects
|
||||
|
||||
Parameters:
|
||||
message_type: Type of message dialog (default: "info").
|
||||
text: Message content to display.
|
||||
buttons: List of button labels (default: ["OK"]).
|
||||
master: Parent tkinter window (optional).
|
||||
commands: List of callables for each button (default: [None]).
|
||||
icon: Custom icon path (overrides default icons if provided).
|
||||
title: Window title (default: derived from message_type).
|
||||
message_type: Type of message dialog (default: "info")
|
||||
text: Message content to display
|
||||
buttons: List of button labels (default: ["OK"])
|
||||
master: Parent tkinter window (optional)
|
||||
commands: List of callables for each button (default: [None])
|
||||
icon: Custom icon path (overrides default icons if provided)
|
||||
title: Window title (default: derived from message_type)
|
||||
font: Font tuple for text styling
|
||||
wraplength: Text wrapping width in pixels
|
||||
|
||||
Methods:
|
||||
_get_title(): Returns the default window title based on message type.
|
||||
_load_icons(): Loads icons from system paths or fallback locations.
|
||||
_on_button_click(button_text): Sets result and closes the dialog.
|
||||
show(): Displays the dialog and waits for user response (returns self.result).
|
||||
show(): Displays the dialog and waits for user response.
|
||||
|
||||
Example Usage:
|
||||
|
||||
1. Basic Info Dialog:
|
||||
>>> MessageDialog(
|
||||
... text="This is an information message.")
|
||||
>>> result = dialog.show()
|
||||
>>> print("User clicked OK:", result)
|
||||
|
||||
Notes:
|
||||
My Favorite Example,
|
||||
for simply information message:
|
||||
|
||||
>>> MessageDialog(text="This is an information message.")
|
||||
>>> result = MessageDialog(text="This is an information message.").show()
|
||||
|
||||
Example Usage:
|
||||
|
||||
2. Error Dialog with Custom Command:
|
||||
>>> def on_retry():
|
||||
... print("User selected Retry")
|
||||
|
||||
>>> dialog = MessageDialog(
|
||||
... message_type="error",
|
||||
... text="An error occurred during processing.",
|
||||
... buttons=["Retry", "Cancel"],
|
||||
... commands=[on_retry, None],
|
||||
... title="Critical Error"
|
||||
... )
|
||||
>>> result = dialog.show()
|
||||
>>> print("User selected Retry:", result)
|
||||
|
||||
Example Usage:
|
||||
|
||||
3. And a special example for a "open link" button:
|
||||
Be careful not to forget to import it into the script in which
|
||||
this dialog is used!!! import webbrowser from functools import partial
|
||||
|
||||
>>> MessageDialog(
|
||||
... "info"
|
||||
... text="This is an information message.",
|
||||
... buttons=["Yes", "Go to Exapmle"],
|
||||
... commands=[
|
||||
... None, # Default on "OK"
|
||||
... partial(webbrowser.open, "https://exapmle.com"),
|
||||
... ],
|
||||
... icon="/pathh/to/custom/icon.png",
|
||||
... title="Example",
|
||||
... )
|
||||
|
||||
Notes:
|
||||
- Returns None if "Cancel" was clicked with ≥3 buttons
|
||||
- Supports keyboard navigation (Left/Right arrows and Enter)
|
||||
- Dialog automatically centers on screen
|
||||
- Result is False for window close (X) with 2 buttons
|
||||
- Font and wraplength parameters enable text styling
|
||||
"""
|
||||
|
||||
DEFAULT_ICON_PATH = "/usr/share/icons/lx-icons"
|
||||
@ -180,7 +129,7 @@ class MessageDialog:
|
||||
self.window = tk.Toplevel(master)
|
||||
self.window.grab_set()
|
||||
self.window.resizable(False, False)
|
||||
ttk.Style().configure("TButton", font=("Helvetica", 11), padding=5)
|
||||
ttk.Style().configure("TButton")
|
||||
self.buttons_widgets = []
|
||||
self.current_button_index = 0
|
||||
self._load_icons()
|
||||
@ -191,7 +140,7 @@ class MessageDialog:
|
||||
|
||||
# Layout
|
||||
frame = ttk.Frame(self.window)
|
||||
frame.pack(expand=True, fill="both")
|
||||
frame.pack(expand=True, fill="both", padx=15, pady=8)
|
||||
|
||||
# Grid-Configuration
|
||||
frame.grid_rowconfigure(0, weight=1)
|
||||
@ -218,13 +167,12 @@ class MessageDialog:
|
||||
row=0,
|
||||
column=1,
|
||||
padx=(10, 20),
|
||||
pady=(8, 20),
|
||||
sticky="nsew",
|
||||
)
|
||||
|
||||
# Create button frame
|
||||
self.button_frame = ttk.Frame(frame)
|
||||
self.button_frame.grid(row=1, columnspan=2, pady=(15, 10))
|
||||
self.button_frame.grid(row=1, columnspan=2, pady=(8, 10))
|
||||
|
||||
for i, btn_text in enumerate(buttons):
|
||||
if commands and len(commands) > i and commands[i] is not None:
|
||||
@ -243,7 +191,7 @@ class MessageDialog:
|
||||
)
|
||||
|
||||
padx_value = 50 if self.icon is not None and len(buttons) == 2 else 10
|
||||
btn.pack(side="left" if i == 0 else "right", padx=padx_value, pady=15)
|
||||
btn.pack(side="left" if i == 0 else "right", padx=padx_value, pady=5)
|
||||
btn.focus_set() if i == 0 else None # Set focus on first button
|
||||
self.buttons_widgets.append(btn)
|
||||
|
||||
@ -309,12 +257,12 @@ class MessageDialog:
|
||||
if os.path.exists(icon_paths[key]):
|
||||
self.icons[key] = tk.PhotoImage(file=icon_paths[key])
|
||||
else:
|
||||
self.icons[key] = tk.PhotoImage(file=fallback_paths[key])
|
||||
if os.path.exists(fallback_paths[key]):
|
||||
self.icons[key] = tk.PhotoImage(file=fallback_paths[key])
|
||||
except Exception as e:
|
||||
print(f"Error on load Icon '{[key]}': {e}")
|
||||
self.icons[key] = tk.PhotoImage()
|
||||
print(f"⚠️ No Icon found for '{key}'. Use standard Tkinter icon.")
|
||||
|
||||
return self.icons
|
||||
|
||||
def _get_icon_path(self) -> str:
|
||||
|
Reference in New Issue
Block a user