Erläuterung zum Erstellen einer Anwendung zum Anzeigen von Bildern und Zeichnen mit Python

Präambel

Python wird mit der Popularität von AI (Deep Learning) immer beliebter. Ich habe GUI-Anwendungen zum Anzeigen, Zeichnen und Speichern von Bildern mit Python erstellt, aber ich habe versucht, den Code zu organisieren und so weiter. Ich werde den Mechanismus schreiben, um mein Verständnis zu organisieren. Ich habe eine Bibliothek namens Qt für Python (PySide2) verwendet. Qt wurde ursprünglich in C ++ entwickelt und ermöglicht es Ihnen, plattformübergreifende Anwendungen zu entwickeln, die auf verschiedenen Betriebssystemen wie Windows, Mac und Linux aus demselben Quellcode ausgeführt werden. Es gibt Qt für Python oder PyQt, um Qt aus Python zu verwenden, aber ich habe Qt für Python verwendet, das nicht so stark an die Lizenz der erstellten App gebunden ist. Es ist leicht zu verstehen, ob Sie die Objektorientierung beim Erstellen von GUI-Anwendungen verstehen. Beim Zeichnen eines Bildes erscheinen viele Objekte, und für Anfänger ist es schwierig, die Rollen und Beziehungen der einzelnen Objekte zu verstehen. Es ist jedoch einfacher zu verstehen, ob etwas erstellt wird, das sich bewegt, auch wenn es nicht in einer schönen Form vorliegt. (Geschichte erleben) Wenn Sie also ein Bild haben, das Sie erstellen möchten, geben Sie nicht auf und probieren Sie verschiedene Dinge aus. Ich hoffe, dieser Artikel wird Ihnen zu diesem Zeitpunkt helfen.

Das große Bild der App

Das Gesamtbild der App ist wie folgt. Die Bildschirmkonfiguration wird von derjenigen verwaltet, die über eine Funktion namens Layout verfügt, die die platzierten Teile (Widgets) automatisch entsprechend der Größe des Fensters anordnet.

Qt_ImageEditor_Layout.png

QVBoxLayout () wird vertikal und QHBoxLayout () horizontal ausgerichtet. Verwenden Sie QFormLayout (), wenn Sie ein Paar wie einen Namen und seinen Wert erstellen möchten. Das Verwendungsbeispiel lautet wie folgt.

self.main_layout = QVBoxLayout()
#Stellen Sie den Bildanzeigebereich ein
self.graphics_view = QGraphicsView()
self.upper_layout.addWidget(self.graphics_view)
#Verschachteln Sie das Layout oben auf dem Bildschirm in das Hauptlayout
self.upper_layout = QHBoxLayout()
self.main_layout.addLayout(self.upper_layout)

Hauptfenster erstellen

Erstellen Sie eine Klasse MainWindow (QMainWIndow), die QMainWindow als Hauptfenster erbt. Platzieren Sie Teile (Widgets) mit verschiedenen Funktionen darin und beschreiben Sie den Vorgang, wenn Sie darauf drücken. Ich musste self.mainWidget = QWidget (self) in der Initialisierung hier deklarieren, bevor ich Layout festlegen konnte.

Der Code zum Starten der Anwendung sieht folgendermaßen aus:

class MainWindow(QMainWindow):

    def __init__(self):
    #Nachfolgend werden verschiedene Prozesse beschrieben


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

Erstellen einer Menüleiste

Deklarieren Sie es im Konstruktor (def init ()), um im Hauptfenster eine Menüleiste (Auswahl oben in der Anwendung) zu erstellen. Gehen Sie wie folgt vor, um eine Menüleiste und ein Menü mit dem Namen "Datei" zu erstellen.

class MainWindow(QMainWindow):

    def __init__(self):
        self.main_menu = self.menuBar()
        self.file_menu = self.main_menu.addMenu('File')

Wenn Sie im Menü "Datei" ein Element mit dem Namen "Datei öffnen" erstellen möchten, gehen Sie wie folgt vor.

# Set "Original Image Open" menu
self.org_img_open_button = QAction(self.style().standardIcon(getattr(QStyle, 'SP_FileDialogStart')), 'Open Orginal Image', self)
self.org_img_open_button.setShortcut('Ctrl+O')
self.org_img_open_button.triggered.connect(self.open_org_img_dialog)
self.file_menu.addAction(self.org_img_open_button)

In der ersten Zeile wird QAction () festgelegt, das funktioniert, wenn dieses Element ausgewählt wird, das Symbol aus den Standardelementen ausgewählt wird und der angezeigte Name "Open Orginal Image" lautet. Die zweite Zeile ist so eingestellt, dass dieses Element mit der Tastenkombination Strg + O ausgewählt werden kann. Die dritte Zeile ist mit der Funktion verbunden, die das Verhalten bei Auswahl dieses Elements festlegt. Dies wird im nächsten Abschnitt erläutert. Dieser Artikel ist in file_menu in der 4. Zeile registriert.

Mechanismus zum Empfangen von Aktionen an Teilen

Bei Qt werden Benutzeroperationen und entsprechende Computerreaktionen mit Methoden ausgeführt, die als Signal und Slot bezeichnet werden. Das Signal wird ausgegeben, wenn der Benutzer eine Operation wie eine Menütaste oder das Ziehen der Maus ausführt. Führen Sie dann die entsprechende Verarbeitung in dem definierten Steckplatz durch, um jedes Signal zu empfangen. Insbesondere wird die Operation, wenn ein Element in der Menüleiste ausgewählt ist, wie folgt geschrieben.

#Menüleiste->Datei-> 'Original Image Open'Wann ist ausgewählt
#Senden Sie ein ausgelöstes Signal. Das Signal ist offen_org_img_Verbunden mit der Dialogfunktion.
self.org_img_open_button = QAction(self.style().standardIcon(getattr(QStyle, 'SP_FileDialogStart')), 'Open Orginal Image', self)
self.org_img_open_button.triggered.connect(self.open_org_img_dialog)

#Menüleiste->Datei-> 'Original Image Open'Eine Funktion, die zu einem Steckplatz wird, der das bei der Übertragung gesendete Signal empfängt
def open_org_img_dialog(self):
    options = QFileDialog.Options()
    org_img_default_path = self.app_setting["SoftwareSetting"]["file_path"]["org_img_dir"]
    self.org_img_file_path, selected_filter = QFileDialog.getOpenFileName(self, 'Select original image', org_img_default_path, 'Image files(*.jpg *jpeg *.png)', options=options)
        
    org_img_dir_path, org_img_file = os.path.split(self.org_img_file_path)
    org_img_bare_name, org_img_ext = os.path.splitext(org_img_file)

    self.org_img_path_label.setText(self.org_img_file_path)
        

Wenn eine Farbe durch Klicken mit der Maus in der später beschriebenen Farbleiste ausgewählt wird, wird die ausgewählte Farbe als Quadrat im Zeichenbereich zur Anzeige gezeichnet, um dem Benutzer das Verständnis zu erleichtern. Zu diesem Zeitpunkt muss zwischen dem Farbbalken und dem Objekt im ausgewählten Farbzeichnungsbereich gearbeitet werden. Zu diesem Zeitpunkt ist es erforderlich, Signal und Steckplatz über das übergeordnete Hauptfenster zu verbinden. In diesem Fall definiert die Klasse, die die Zeichnungselemente verwaltet, die im ausgewählten Farbzeichnungsbereich platziert werden sollen, ihr eigenes Signal und sendet das Signal mit den Farbinformationen des angeklickten Teils. Insbesondere sieht der Code wie folgt aus.

# Class for graphics contents of tools on main window
class GraphicsSceneForTools(QGraphicsScene):
    # Define custom signal
    img_info = Signal(QColor)

    def mousePressEvent(self, event):
        # For check program action
        pos = event.scenePos()
        x = pos.x()
        y = pos.y()
        #Wenn der Cursor oder Stift in der Bildbearbeitungssymbolleiste ausgewählt ist, werden die Farbinformationen der angeklickten Stelle angezeigt(QColor)Geben Sie ein Signal mit aus
        if self.mode == 'cursor' or self.mode == 'pen':
            self.pix_rgb = self.img_content.pixelColor(x, y)
            self.img_info.emit(self.pix_rgb)

#Definieren Sie den Steckplatz, der dem Signal der auf der Seite des Hauptfensters ausgewählten Farbinformationen entspricht
class MainWindow(QMainWindow):
    #Verwaltungsobjekt für Zeichnungselemente für Farbbalken
    self.color_bar_scene = GraphicsSceneForTools()
    #Stellen Sie eine Verbindung mit einer Funktion her, die zu einem Steckplatz wird, der das Signal empfängt, das die Farbinformationen gesendet hat
    self.color_bar_scene.img_info.connect(self.set_selected_color)

Bildanzeigemechanismus

Für die Bildanzeige sind mehrere Widgets verknüpft. Die Beziehung ist wie in der folgenden Abbildung dargestellt. Bereiten Sie QGraphicsView, ein Zeichenbereichsobjekt, in MainWindow vor, platzieren Sie QGraphicsScene, das Zeichnungsobjekte enthält und verwaltet, und fügen Sie Zeichnungen und Bilder wie Linien und Kreise zu QGraphicsScene hinzu. Gehen.

Qt_ImageView_Component.png

Die im Hauptzeichnungsbereich festgelegte QGraphicsScene zeigt die Pixelinformationen des angezeigten Bildes in der Statusleiste an, wenn das Cursorwerkzeug ausgewählt ist, und die Ebene über dem Bild, wenn das Stift- oder Radiergummiwerkzeug ausgewählt ist. Ich werde versuchen zu zeichnen. Um einen solchen Funktionssatz selbst hinzuzufügen, erstellen Sie eine Grafikszene, die die QGraphic-Szene wie folgt erbt. Durch Festlegen des übergeordneten Zeichenbereichs QGraphicsView und seines übergeordneten Hauptfensters in der Initialisierungsinitialisierungsfunktion können die von jedem Element dieser GraphicsScene erhaltenen Informationen an den Zeichenbereich oder das Fenster übergeben werden.

Um ehrlich zu sein, bin ich mir bei QGraphicsView und QGraphicsScene zunächst nicht sicher, aber ich fand es kompliziert und mühsam, auf die Inhalte zuzugreifen und sie zu kontrollieren! Dies scheint darauf zurückzuführen zu sein, dass es die komplizierte Anforderung des Zeichnens innerhalb des sichtbaren Bereichs (Zeichenbereich) aus verschiedenen Blickwinkeln erfüllt, auch wenn sich der zu zeichnende Zielinhalt nicht ändert. Wenn der zu zeichnende Inhalt beispielsweise größer als der Zeichenbereich ist, wird er möglicherweise angezeigt, während der Ansichtspunkt mit der Bildlaufleiste geändert wird, oder ein 3D-Objekt wird angezeigt, während der Ansichtspunkt geändert wird.

class GraphicsSceneForMainView(QGraphicsScene):

    def __init__(self, parent=None, window=None, mode='cursor'):
        QGraphicsScene.__init__(self, parent)
        # Set parent view area
        self.parent = parent
        # Set grand parent window
        self.window = window
        # Set action mode
        self.mode = mode

        # mouse move pixels
        self.points = []

        # added line items
        self.line_items = []
        self.lines = []

        # added line's pen attribute
        self.pens = []
        
    def set_mode(self, mode):
        self.mode = mode

    def set_img_contents(self, img_contents):
        # image data of Graphics Scene's contents
        self.img_contents = img_contents

    def clear_contents(self):
        self.points.clear()
        self.line_items.clear()
        self.lines.clear()
        self.pens.clear()
        self.img_contents = None

    def mousePressEvent(self, event):
        # For check program action
        pos = event.scenePos()
        x = pos.x()
        y = pos.y()

        if self.mode == 'cursor':
            # Get items on cursor
            message = '(x, y)=({x}, {y}) '.format(x=int(x), y=int(y))

            for img in self.img_contents:
                # Get pixel value
                pix_val = img.pixel(x, y)
                pix_rgb = QColor(pix_val).getRgb()
                message += '(R, G, B) = {RGB} '.format(RGB=pix_rgb[:3])

            # show scene status on parent's widgets status bar
            self.window.statusBar().showMessage(message)

Link zur QGraphicsView-Dokumentation Link zur QGraphicsScene-Dokumentation

Bildobjekt

Verwenden Sie QGraphicsScene.addItem (QPixmap) im Format QPixmap, um ein Bild in QGraphicsScene zu platzieren. Im QPixmap-Format können die Informationen der einzelnen Pixel jedoch nicht erfasst oder neu geschrieben werden. Behalten Sie sie daher im QImage-Format bei und konvertieren Sie sie zum Zeichnen in QPixmap. Um ein QImage aus einer Bilddatei zu erstellen, verwandeln Sie es in eine QPixmap und fügen Sie es der QGraphicsScene hinzu. Der Code sieht folgendermaßen aus:

#self bezieht sich auf MainWindow
self.scene = GraphicsSceneForMainView(self.graphics_view, self)
self.org_qimg = QImage(self.org_img_file_path)
self.org_pixmap = QPixmap.fromImage(self.org_qimg)
scene.addItem(self.org_pixmap)

Verwenden Sie den folgenden Code, um ein QImage von 8 Bit (256 Abstufungen) RGBA (A ist Transparenz) am Himmel zu erstellen.

self.layer_qimg = QImage(self.org_img_width, self.org_img_height, QImage.Format_RGBA8888)

Link zur QImage-Dokumentation Link zur QPixmap-Dokumentation

Farbbalkeneinstellungen

Dieser Artikel wird als Referenz verwendet, und die Farbleiste zur Auswahl der Stiftfarbe wird einer Wärmezuordnung zugeordnet (glatt von Blau bei niedriger Temperatur bis Rot bei hoher Temperatur). Ich habe es geschafft mit (ändern). Das Objekt, mit dem die Farbleiste festgelegt wird, ist teilweise in der Erläuterung von "Mechanismus zum Empfangen von Aktionen für Teile" beschrieben. Ich habe jedoch eine Klasse namens GraphicsSceneForTools erstellt, die QGraphicsScene geerbt und verwendet hat. Auf diese Weise wird durch Klicken mit der Maus ein Signal entsprechend der von diesem Objekt gedrückten Position und im MainWindow (genauer gesagt MainWindow-> QGraphicsView-> GraphicsSceneForTools) des übergeordneten Objekts ausgegeben, in dem sich das Objekt befindet. Durch Vorbereiten einer Slot-Funktion, die von Signal empfangen werden soll, wird der ausgewählte Farbanzeigebereich mit der vom Benutzer in der Farbleiste ausgewählten Farbe gefüllt und auf leicht verständliche Weise angezeigt. In der neu vorbereiteten Klasse GraphicsSceneForTools (QGraphicsScene) wird ein Signal mit QColor (Farbinformationen) als img_info = Signal (QColor) vorbereitet und beim Klicken der Maus in def mousePressEvent (self, event) festgelegt. Ich versuche, ein Signalsignal mit der Farbe (self.pix_rgb) der angeklickten Koordinatenposition des Zeichnungselements (in diesem Fall Farbbalken) als self.img_info.emit (self.pix_rgb) auszugeben. Auf der MainWindow-Seite wird set_selected_color () als Slot-Funktion auf der Empfangsseite vorbereitet, wenn das GraphicsSceneForTools-Objekt das entsprechende Signal als self.color_bar_scene.img_info.connect (self.set_selected_color) ausgibt. Insbesondere lautet der Code wie folgt.

class MainWindow(QMainWindow):
    # Set color bar
    self.color_bar_width = 64
    self.color_bar_height = 256
    self.color_bar_view = QGraphicsView()
    self.color_bar_view.setFixedSize(self.color_bar_width+3, self.color_bar_height+3)
    self.color_bar_scene = GraphicsSceneForTools()

    #Stellen Sie die Farbleiste ein.
    #Die Farbänderungsdaten, die der Farbleiste zugrunde liegen, sind selbst.colormap_Es ist in Daten.
    #Informationen zum Erstellen finden Sie im Quellcode oder im Referenzartikel.
    self.color_bar_img = QImage(self.color_bar_width, self.color_bar_height, QImage.Format_RGB888)

    for i in range(self.color_bar_height):
        # Set drawing pen for colormap
        ii = round(i * (1000/256))
        color = QColor(self.colormap_data[ii][0], self.colormap_data[ii][1], self.colormap_data[ii][2])
        pen = QPen(color, 1, Qt.SolidLine, \
                Qt.SquareCap, Qt.RoundJoin)
        self.color_bar_scene.addLine(0, self.color_bar_height - i-1, self.color_bar_width, self.color_bar_height - i-1, pen=pen)
        for j in range(self.color_bar_width):
           self.color_bar_img.setPixelColor(j, self.color_bar_height-i-1, color)

    self.color_bar_scene.set_img_content(self.color_bar_img)

    self.color_bar_view.setScene(self.color_bar_scene)

    # Connect signal to slot of color_bar_scene
    self.color_bar_scene.img_info.connect(self.set_selected_color)

    # Slot of color bar clicked for selection color
    def set_selected_color(self, color):
        # Delete existng image item
        self.select_color_scene.removeItem(self.select_color_rect)
        self.draw_color = color
        brush = QBrush(self.draw_color)
        self.select_color_rect = self.select_color_scene.addRect(QRect(0, 0, self.select_color_view_size, self.select_color_view_size), \
            brush=brush)
        self.select_color_view.setScene(self.select_color_scene)

# Class for graphics contents of tools on main window
class GraphicsSceneForTools(QGraphicsScene):
    # Define custom signal
    img_info = Signal(QColor)

    def __init__(self, parent=None, window=None):
        QGraphicsScene.__init__(self, parent)
        # Set parent view area
        self.parent = parent
        # Set grand parent window
        self.window = window
        self.mode = 'cursor'

    def set_mode(self, mode):
        self.mode = mode

    def set_img_content(self, img_content):
        # image data of Graphics Scene's contents
        self.img_content = img_content
    
    def mousePressEvent(self, event):
        # For check program action
        pos = event.scenePos()
        x = pos.x()
        y = pos.y()

        if self.mode == 'cursor' or self.mode == 'pen':
            self.pix_rgb = self.img_content.pixelColor(x, y)
            self.img_info.emit(self.pix_rgb)

Reflektieren Sie den gezeichneten Inhalt und speichern Sie ihn als Datei

Mit den oben genannten Inhalten können Sie einen Stift oder ein Radiergummi zum Zeichnen auswählen. Das Originalbild wird angezeigt und das Ergebnis meiner Zeichnung wird auf einer anderen Ebene darüber gezeichnet. Um den von Ihnen gezeichneten Inhalt zu speichern, müssen Sie den gezeichneten Inhalt exportieren, indem Sie die Maus als Bild ziehen. Der durch Ziehen mit der Maus des Benutzers gezeichnete Inhalt wird als Sammlung von Linien gespeichert, die Loci sind. Linien haben Start- und Endpunkte sowie Stiftattribute (Farbe, Größe). Daher werden die Koordinaten, die das Bild weitergeben, basierend auf dem Startpunkt und dem Endpunkt in der Reihenfolge aus der Gruppe von Linien berechnet und im Bild für den Export wiedergegeben.

#Eine Klasse, die Elemente verwaltet, die im Zeichenbereich platziert werden sollen
class GraphicsSceneForMainView(QGraphicsScene):
    #Wenn ein Stift oder Radiergummi durch Ziehen der Maus ausgewählt und gezeichnet wird
    def mouseMoveEvent(self, event):
        # For check program action
        pos = event.scenePos()
        x = pos.x()
        y = pos.y()
    
        if self.mode == 'pen' or self.mode == 'eraser':
            if x >= 0 and x < self.width() and y >= 0 and y < self.height():
                if len(self.points) != 0:
                    draw_color = self.window.draw_color
                    # Set transparenc value
                    draw_color.setAlpha(self.window.layer_alpha)
                    draw_size = self.window.draw_tool_size
                    pen = QPen(draw_color, draw_size, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
                    self.lines_items.append(self.addLine(QLineF(self.points[-1].x(), self.points[-1].y(), x, y), pen=pen))
                    #Die Position der gezeichneten Linie und die Attribute des Stifts zu diesem Zeitpunkt zum späteren Speichern als Bild(Farbe, Größe)sparen
                    self.lines.append(self.lines_items[-1].line())
                    self.pens.append(pen)

                self.points.append(pos)


# Main Window components
class MainWindow(QMainWindow):
    #Verarbeitung, um die Zeichnung des Benutzers auf dem Bild wiederzugeben
    #Der durch Ziehen der Maus gezeichnete Inhalt ist eine Sammlung von Linieninformationen mit einem Startpunkt und einem Endpunkt.
    def make_layer_image(self):
        for i, line in enumerate(self.scene.lines):
            pen = self.scene.pens[i]

            pen_size = int(pen.width())
            pen_color = pen.color()

            # start pixel of line
            x1 = int(line.x1())
            y1 = int(line.y1())

            # end pixel of line
            x2 = int(line.x2())
            y2 = int(line.y2())

            dx = int(line.dx())
            dy = int(line.dy())

            # When only 1pixl line
            if dx <= 1 and dy <= 1:
                draw_pix_x1_s = max(x1 - int(pen_size/2), 0)
                draw_pix_x1_e = min(x1 + int(pen_size/2), self.org_img_width-1)
                draw_pix_y1_s = max(y1 - int(pen_size/2), 0)
                draw_pix_y1_e = min(y1 + int(pen_size/2), self.org_img_height-1)

                # for Pen's size
                for y in range(draw_pix_y1_s, draw_pix_y1_e):
                    for x in range(draw_pix_x1_s, draw_pix_x1_e):
                        self.layer_qimg.setPixelColor(x, y, pen_color)

                draw_pix_x2_s = max(x2 - int(pen_size/2), 0)
                draw_pix_x2_e = min(x2 + int(pen_size/2), self.org_img_width-1)
                draw_pix_y2_s = max(y2 - int(pen_size/2), 0)
                draw_pix_y2_e = min(y2 + int(pen_size/2), self.org_img_height-1)

                # for Pen's size
                for y in range(draw_pix_y2_s, draw_pix_y2_e):
                    for x in range(draw_pix_x2_s, draw_pix_x2_e):
                        self.layer_qimg.setPixelColor(x, y, pen_color)

            else:
                # For avoid devide by 0
                if dx == 0:
                    for y in range(y1, y2+1):
                        draw_pix_y_s = y - int(pen_size/2)
                        draw_pix_y_e = y + int(pen_size/2)
                        # for Pen's size
                        for yy in range(draw_pix_y_s, draw_pix_y_e):
                            self.layer_qimg.setPixelColor(x1, yy, pen_color)

                else:
                    grad = dy/dx

                    # Choose coordinates with small slope not to skip pixels
                    if grad >= 1.0:
                        for x in range(dx):
                            y = y1 + int(grad * x + 0.5)
                            draw_pix_x_s = max(x1 + x - int(pen_size/2), 0)
                            draw_pix_x_e = min(x1 + x + int(pen_size/2), self.org_img_width-1)
                            draw_pix_y_s = max(y - int(pen_size/2), 0)
                            draw_pix_y_e = min(y + int(pen_size/2), self.org_img_height-1)
                            # for Pen's size
                            for yy in range(draw_pix_y_s, draw_pix_y_e+1):
                                for xx in range(draw_pix_x_s, draw_pix_x_e+1):
                                    self.layer_qimg.setPixelColor(xx, yy, pen_color)

                    else:
                        for y in range(dy):
                            x = x1 + int(1/grad * y + 0.5)
                            draw_pix_y_s = max(y1 + y - int(pen_size/2), 0)
                            draw_pix_y_e = min(y1 + y + int(pen_size/2), self.org_img_height-1)
                            draw_pix_x_s = max(x - int(pen_size/2), 0)
                            draw_pix_x_e = min(x + int(pen_size/2), self.org_img_width-1)
                            # for Pen's size
                            for yy in range(draw_pix_y_s, draw_pix_y_e+1):
                                for xx in range(draw_pix_x_s, draw_pix_x_e+1):
                                    self.layer_qimg.setPixelColor(xx, yy, pen_color)

Fügen Sie dem Menü "Datei" "Ebenenbild speichern" hinzu. Wenn Sie es auswählen, wird das vom Benutzer gezeichnete Bild gespeichert. Im Einzelnen lautet der Code wie folgt: Führen Sie den Vorgang zum Erstellen eines QImage-Bilds aus, das die Zeichnung mit make_layer_image () widerspiegelt, öffnen Sie den Dateidialog zum Speichern und speichern Sie mit dem eingegebenen Bilddateinamen. Machen.

# Main Window components
class MainWindow(QMainWindow):
    def __init__(self):
        # Set "Save layer image" menu
        self.layer_img_save_button = QAction(self.style().standardIcon(getattr(QStyle, 'SP_FileDialogEnd')), 'Save Layer Image', self)
        self.layer_img_save_button.setShortcut('Ctrl+S')
        self.layer_img_save_button.triggered.connect(self.save_layer_image)
        self.file_menu.addAction(self.layer_img_save_button)


    # Slot function of save layer image button clicked
    def save_layer_image(self):

        self.make_layer_image()

        layer_img_default_path = self.app_setting["SoftwareSetting"]["file_path"]["layer_img_dir"]
        options = QFileDialog.Options()
        file_name, selected_filete = QFileDialog.getSaveFileName(self, 'Save layer image', layer_img_default_path, \
            'image files(*.png, *jpg)', options=options)
        
        self.layer_qimg.save(file_name)
        ret = QMessageBox(self, 'Success', 'layer image is saved successfully', QMessageBox.Ok)

Platzierung von Widgets (Teilen) in der GUI

Qt wird außerdem mit einem Tool namens Qt Designer geliefert, das Teile wie Schaltflächen auf dem Bildschirm der Anwendung anordnet, die Sie auf dem GUI-Bildschirm erstellen möchten. Bevor Sie sich daran gewöhnen, können Sie sich leicht vorstellen, welche Art von Teilen (Widget) Sie haben. Daher ist es möglicherweise einfacher zu verstehen, wenn Sie versuchen, damit ein Erscheinungsbild zu erstellen.

Quellcode

Der Quellcode der erstellten Anwendung wird an der folgenden Stelle veröffentlicht. App-Quellcodepage

Recommended Posts

Erläuterung zum Erstellen einer Anwendung zum Anzeigen von Bildern und Zeichnen mit Python
Verknüpfen Sie Python Enum mit einer Funktion, um es aufrufbar zu machen
Erläuterung zum Erstellen einer Anwendung zum Anzeigen von Bildern und Zeichnen mit Python
Verfahren zum Erstellen einer Anwendung mit Django mit Pycharm ~ Vorbereitung ~
Ein Ei mit Python erstellen
[Persönliche Entwicklung] Eine Geschichte über das Erstellen einer App für Künstler mit SPA mit Django REST Framework und Vue-Cli [DRF + Vue.js]
[Für Anfänger] Zusammenfassung der Standardeingabe in Python (mit Erklärung)
Drehen Sie ein Array von Zeichenfolgen mit einer for-Anweisung (Python3).
Koexistenz von Python2 und 3 mit CircleCI (1.0)
Leicht verständliche Erklärung der Python-Webanwendung (Django) auch für Anfänger (5) [Einführung in den DB-Betrieb mit Django-Shell]
Verstärken Sie Bilder für maschinelles Lernen mit Python
Hinweise beim Erstellen einer Umgebung mit Python
Bilder mit Pupil, Python und OpenCV aufnehmen
[Python] Bilder mit OpenCV lesen (für Anfänger)
Zeichnen mit Matrix-Reinventor von Python Image Processing-
Importieren und Exportieren von GeoTiff-Bildern mit Python
Holen Sie sich Bilder von OpenStreetMap und Geographical Institute Map mit Python + py-staticmaps
Leicht verständliche Erklärung der Python-Webanwendung (Django) auch für Anfänger (2) [Projekterstellung]
Holen Sie sich Bilder von OpenStreetMap und Geographical Institute Map mit Python + staticmap
Ich habe die Geschwindigkeit der Listeneinschlussnotation für und während mit Python2.7 gemessen.
Leicht verständliche Erklärung der Python-Webanwendung (Django) auch für Anfänger (1) [Umgebungskonstruktion]
Kausales Denken und kausale Suche von Python (für Anfänger)
Erstellen einer Anaconda-Umgebung für Python mit pyenv
Vorgehensweise zum Erstellen eines mit Python erstellten LineBot
Python: Tipps zum Anzeigen eines Arrays (einer Liste) mit einem Index (wie man herausfindet, welche Nummer ein Element eines Arrays ist)
[Python] Sammeln Sie Bilder mit Icrawler für maschinelles Lernen [1000 Blatt]
TRIE-Baumimplementierung mit Python und LOUDS
[Hikari-Python] Kapitel 09-02 Klassen (Erstellen und Instanziieren von Klassen)
Wavelet-Konvertierung von Bildern mit PyWavelets und OpenCV
Fortsetzung der Multi-Plattform-Entwicklung mit Electron und Python
Erläuterung der Bearbeitungsentfernung und Implementierung in Python
Beispiel für das Lesen und Schreiben von CSV mit Python
Lassen Sie uns eine App erstellen, die ähnliche Bilder mit Python und Flask Part1 durchsuchen kann
Erstellen Sie einen API-Server, um den Betrieb der Front-Implementierung mit Python3 und Flask zu überprüfen
Extrahieren Sie Bilder und Tabellen mit Python aus PDF, um die Berichtslast zu verringern
Umfang der Erstellung und Veröffentlichung von Django-Malice, einer Django-Anwendung zur Verursachung von HTTP 40X-Fehlern
Leicht verständliche Erklärung der Python-Webanwendung (Django) auch für Anfänger (6) [Vervollständigung des MTV-Entwurfsmusters]
Ablauf beim Erstellen eines eigenen Pakets mit setup.py mit Python
Mit Python + Tweepy können Sie Bilder und Videos der Medienzeitleiste abrufen
Machen Sie die Python CUI-Anwendung zu einer App für Mac
Zeigen Sie eingebettete Bilder von MP3 und Flac mit Mutagen an
Liste der Python-Bibliotheken für Datenwissenschaftler und Dateningenieure
Python netCDF4 Lesegeschwindigkeit und Verschachtelung von for-Anweisungen
Python - Erläuterung und Zusammenfassung der Verwendung der 24 wichtigsten Pakete
Versuchen Sie, die Bildkonvertierung mit OpenCV mit Python zu projizieren
Laden Sie mp4 einfach teilweise mit Python und youtube-dl herunter!
Zusammenfassung der Tools zum Betreiben der Windows-Benutzeroberfläche mit Python
[# 2] Mach Minecraft mit Python. ~ Modellzeichnung und Player-Implementierung ~
Analysieren und visualisieren Sie JSON (Webanwendung ⑤ mit Python + Flask)
Erstellen einer Umgebung für die Verarbeitung natürlicher Sprache mit Python
Erstellen Sie einen Stapel von Bildern und blasen Sie sie mit ImageDataGenerator auf
Erstellen der ρ-Methode zum Entschlüsseln der elliptischen Kurve mit Python
Erstellen von BINGO "Web Tools" mit Python (Inhaltsverzeichnis)
Python: Ruft eine Liste der Methoden für ein Objekt ab
Informationen zum Erstellen und Ändern von benutzerdefinierten Designs für Python IDLE
Laden / Anzeigen und Beschleunigen von GIF mit Python [OpenCV]
Erhalten Sie ein abstraktes Verständnis der Python-Module und -Pakete
Vergleich von CoffeeScript mit JavaScript-, Python- und Ruby-Grammatik
Versionsverwaltung von Node, Ruby und Python mit anyenv
Ich habe versucht, das Bild mit Python + OpenCV "morphologisch zu konvertieren"
Zeichnen mit Python Tinker