Checkliste zur Abarbeitung von Schritten für die Bildbearbeitung...

linuxer

Aktives Mitglied
Morgen Leute,

wenn ich meine Bilder bearbeite dann gehe ich nach einem bestimmten Schema vor, ich denke das machen die meisten von euch.
Anfangs habe ich eine normales Textfile verwendet in das ich meine Schritte aufgeschrieben hatte, die ich dann nach und nach Abgearbeitet habe.
Irgendwann dachte ich es wäre cool eine Checkliste zu haben wo ich die einzelnen Schritte abhaken könnte. Da ich Gelegenheitsprogrammierer bin und nur ab und zu etwas in Python schreibe, dachte ich es wäre Sinnvoll das einer KI zu überlassen. So spare ich Zeit und brauche mich nicht damit zu beschäftigen, denn ich brauchte das jetzt und nicht erst in 2 Wochen. ;)

Also habe ich zusammen gefasst wie ich mir das Programm vorstelle und habe die Leo-KI von Brave damit beauftragt das zu übernehmen.
Das kam nach 2 Änderungen und 20 Minuten dabei heraus.
IMG_20260420_215119.png



Das Programm ist relativ Simpel und selbsterklärend.

Code:
import sys
import json
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QCheckBox, QLineEdit, QPushButton, QScrollArea, QFileDialog,
    QLabel, QFrame, QStyle, QMenu, QInputDialog, QToolButton
)
from PyQt6.QtCore import Qt, QMimeData, QUrl
from PyQt6.QtGui import QDrag, QPixmap, QCursor, QAction


class ChecklistItem(QWidget):
    def __init__(self, text="", checked=False, parent=None, app=None):
        super().__init__(parent)
        self.app = app
        self.layout = QHBoxLayout(self)
        self.layout.setContentsMargins(0, 2, 0, 2)

        self.checkbox = QCheckBox()
        self.checkbox.setChecked(checked)
        self.checkbox.setFixedWidth(20)

        self.line_edit = QLineEdit()
        self.line_edit.setText(str(text))
        self.line_edit.setPlaceholderText("Arbeitsschritt eingeben...")
        self.line_edit.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.line_edit.customContextMenuRequested.connect(self._show_context_menu)

        self.layout.addWidget(self.checkbox)
        self.layout.addWidget(self.line_edit)

        # Rechtsklick-Menü
        self.context_menu = QMenu(self)
        self.delete_action = QAction("Löschen", self)
        self.delete_action.triggered.connect(self._delete_item)
        self.context_menu.addAction(self.delete_action)

        # Klick-Flag für Löschen
        self.is_selected = False
        self.line_edit.mousePressEvent = self._on_click

    def _on_click(self, event):
        if self.app:
            for item in self.app.items:
                item.is_selected = False
        self.is_selected = True
        self.line_edit.setFocus()

    def _show_context_menu(self, pos):
        self.context_menu.exec(self.mapToGlobal(pos))

    def _delete_item(self):
        if self.app and self in self.app.items:
            self.app.scroll_layout.removeWidget(self)
            self.app.items.remove(self)
            self.deleteLater()

    def get_data(self):
        return {
            "type": "item",
            "text": self.line_edit.text(),
            "checked": self.checkbox.isChecked()
        }


class SectionHeader(QWidget):
    def __init__(self, text="", parent=None, app=None):
        super().__init__(parent)
        self.app = app
        self.layout = QHBoxLayout(self)
        self.layout.setContentsMargins(0, 5, 0, 5)

        self.label = QLabel(text)
        self.label.setStyleSheet("font-weight: bold; color: #2c3e50; background: #ecf0f1; padding: 5px; border-radius: 3px;")
        self.label.setFixedHeight(30)
        self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)

        self.label.setMouseTracking(True)
        self.label.setCursor(Qt.CursorShape.PointingHandCursor)

        # X-Button zum Löschen
        self.delete_btn = QToolButton()
        self.delete_btn.setText("❌")
        self.delete_btn.setFixedSize(20, 20)
        self.delete_btn.clicked.connect(self._delete_header)

        self.layout.addWidget(self.label)
        self.layout.addWidget(self.delete_btn)
        self.layout.addStretch()

        # Klick-Flag
        self.is_selected = False
        self.label.mousePressEvent = self._on_label_click

    def _on_label_click(self, event):
        if self.app:
            for item in self.app.items:
                item.is_selected = False
        self.is_selected = True

        text, ok = QInputDialog.getText(self, "Überschrift bearbeiten", "Neuer Text:", text=self.label.text())
        if ok and text.strip():
            self.label.setText(text.strip())

    def _delete_header(self):
        if self.app and self in self.app.items:
            self.app.scroll_layout.removeWidget(self)
            self.app.items.remove(self)
            self.deleteLater()

    def get_data(self):
        return {
            "type": "header",
            "text": self.label.text()
        }


class SpacerWidget(QWidget):
    def __init__(self, parent=None, app=None):
        super().__init__(parent)
        self.app = app
        self.setFixedHeight(10)
        self.setStyleSheet("background: #f8f9fa;")

        # Klick-Flag
        self.is_selected = False
        self.mousePressEvent = self._on_click

    def _on_click(self, event):
        if self.app:
            for item in self.app.items:
                item.is_selected = False
        self.is_selected = True

    def get_data(self):
        return {"type": "spacer"}


class ChecklistApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Checkliste V2.3")
        self.setMinimumSize(500, 400)
        self.items = []

        self._build_ui()

    def _build_ui(self):
        central = QWidget()
        self.setCentralWidget(central)
        main_layout = QVBoxLayout(central)
        main_layout.setContentsMargins(10, 10, 10, 10)

        # Scrollbereich
        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)

        self.scroll_widget = QWidget()
        self.scroll_layout = QVBoxLayout(self.scroll_widget)
        self.scroll_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
        self.scroll_layout.setSpacing(0)

        self.scroll_area.setWidget(self.scroll_widget)
        main_layout.addWidget(self.scroll_area)

        # Buttons
        btn_layout = QHBoxLayout()

        btn_load = QPushButton("📂 Laden")
        btn_load.setToolTip("Lädt eine gespeicherte Liste von Arbeitsschritten")
        btn_save = QPushButton("💾 Speichern")
        btn_save.setToolTip("Speichert die aktuelle Liste als JSON-Datei")
        btn_quit = QPushButton("❌ Beenden")
        btn_quit.setToolTip("Schließt das Programm")
        btn_header = QPushButton("➕ Überschrift")
        btn_header.setToolTip("Fügt einen neuen Abschnitt mit Überschrift hinzu")
        btn_spacer = QPushButton("➖ Leerzeile")
        btn_spacer.setToolTip("Fügt eine visuelle Trennlinie hinzu")
        btn_add_item = QPushButton("➕ Neue Checkbox")
        btn_add_item.setToolTip("Fügt eine neue leere Arbeitsschritt-Zeile hinzu")
        btn_delete_item = QPushButton("🗑️ Löschen")
        btn_delete_item.setToolTip("Löscht das aktuell ausgewählte Element")

        btn_load.clicked.connect(self._load)
        btn_save.clicked.connect(self._save)
        btn_quit.clicked.connect(self.close)
        btn_header.clicked.connect(self._add_header)
        btn_spacer.clicked.connect(self._add_spacer)
        btn_add_item.clicked.connect(lambda: self._add_item())
        btn_delete_item.clicked.connect(self._delete_selected)

        for btn in [btn_load, btn_save, btn_quit, btn_header, btn_spacer, btn_add_item, btn_delete_item]:
            btn.setFixedHeight(35)
            btn_layout.addWidget(btn)

        main_layout.addLayout(btn_layout)

    def _get_insert_index(self):
        """Gibt den Index zurück, nach dem eingefügt werden soll."""
        for i, item in enumerate(self.items):
            if hasattr(item, 'is_selected') and item.is_selected:
                return i + 1  # Nach dem ausgewählten Element einfügen
        return len(self.items)  # Fallback: ans Ende

    def _add_item(self, text="", checked=False, force_end=False):
        item = ChecklistItem(text=text, checked=checked, app=self)
        idx = len(self.items) if force_end else self._get_insert_index()
        self.scroll_layout.insertWidget(idx, item)
        self.items.insert(idx, item)

        # Neues Element als ausgewählt markieren
        for i in self.items:
            i.is_selected = False
        item.is_selected = True
        item.line_edit.setFocus()

        QApplication.processEvents()
        self.scroll_area.verticalScrollBar().setValue(
            self.scroll_area.verticalScrollBar().maximum()
        )

    def _add_header(self, force_end=False):
        header = SectionHeader("Neuer Abschnitt", app=self)
        idx = len(self.items) if force_end else self._get_insert_index()
        self.scroll_layout.insertWidget(idx, header)
        self.items.insert(idx, header)

        # Neues Element als ausgewählt markieren
        for i in self.items:
            i.is_selected = False
        header.is_selected = True

    def _add_spacer(self, force_end=False):
        spacer = SpacerWidget(app=self)
        idx = len(self.items) if force_end else self._get_insert_index()
        self.scroll_layout.insertWidget(idx, spacer)
        self.items.insert(idx, spacer)

        # Neues Element als ausgewählt markieren
        for i in self.items:
            i.is_selected = False
        spacer.is_selected = True

    def _delete_selected(self):
        for item in self.items[:]:
            if hasattr(item, 'is_selected') and item.is_selected:
                self.scroll_layout.removeWidget(item)
                self.items.remove(item)
                item.deleteLater()
                return

    def _save(self):
        path, _ = QFileDialog.getSaveFileName(
            self, "Speichern", "", "JSON Dateien (*.json)"
        )
        if path:
            data = [item.get_data() for item in self.items]
            with open(path, "w", encoding="utf-8") as f:
                json.dump(data, f, ensure_ascii=False, indent=2)

    def _load(self):
        path, _ = QFileDialog.getOpenFileName(
            self, "Laden", "", "JSON Dateien (*.json)"
        )
        if path:
            with open(path, "r", encoding="utf-8") as f:
                data = json.load(f)

            # Alles löschen
            for item in self.items[:]:
                self.scroll_layout.removeWidget(item)
                item.deleteLater()
            self.items.clear()

            # Neu aufbauen
            for entry in data:
                if entry["type"] == "item":
                    self._add_item(text=entry.get("text", ""), checked=entry.get("checked", False), force_end=True)
                elif entry["type"] == "header":
                    self._add_header(force_end=True)
                    for item in reversed(self.items):
                        if isinstance(item, SectionHeader):
                            item.label.setText(entry.get("text", "Neuer Abschnitt"))
                            break
                elif entry["type"] == "spacer":
                    self._add_spacer(force_end=True)


def main():
    app = QApplication(sys.argv)
    app.setStyle("Fusion")
    window = ChecklistApp()
    window.show()
    sys.exit(app.exec())


if __name__ == "__main__":
    main()

Da ich Linux verwende weis ich das es funktioniert, bei Windows weis ich das nicht da ich keinen Windows-Rechner habe.
Also einfach ausprobieren.
Wer Interesse hat, viel Spaß damit :)
 
Zuletzt von einem Moderator bearbeitet:
Hi,
gut zu wissen, Danke. Kannte ich noch nicht.
Bin immer noch dabei den besten Weg für mich zu finden. :) :y:
 
@ Horst (Admin/Mod)
Danke :y: :)
 
Zurück
Oben