[Python]329 PyQt6 ボタン動作の実装

[M1 Mac, Big Sur 11.6.5, Python 3.10.0]

前回のコードにボタン動作を追加しPyQt6アプリを完成させました。icnsファイル作成箇所はクラスファイルとして別にしました。このアプリではドラッグ&ドロップでファイルパスを取得することもできます。

appファイルにすると260MBの巨大サイズになりました。さくっと作れますがやはりファイルの大きさが問題です。

アプリはとりあえず自サイトにアップしました。ここからC++の本家Qtに移植の予定です。

PyQt6はこれまで見てきたウィジェットツールキットの中では最も扱いやすかったです。並べると、PyQt6 > Swing >>> Tkinter >>FLTK といったところでしょうか。上位2つは企業開発であり、商品としてそれなりに洗練されているということでしょう。

FLTKは外観・文法・ウィジェットの名称など、クセが強すぎて開発意欲が低いままです。ラジオボタンがFl_Round_Button、ラベルがFl_Boxなどなどネーミングがピンとこなくて困っています。

2022/03/25追記
pngからjpgに変換しなくても解像度を上げられましたので後日コードをアップします。

https://www.tampiweb.site/?page_id=453
import sys
from PyQt6.QtWidgets import QLabel,QWidget,QApplication,QTextEdit,QLineEdit,QPushButton,QButtonGroup,QRadioButton
from PyQt6.QtCore import Qt
from pathlib import Path
from PIL import Image
import makeIcns

class ImageInspector(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("IMAGE INSPECTOR")
        self.setGeometry(100,100,360,220)
        self.setStyleSheet('background-color: #708090')
        self.setAcceptDrops(True)
        
        file = QLabel('File',self)
        file.setGeometry(15,15,26,16)
        file.setAlignment(Qt.AlignmentFlag.AlignCenter)
        
        self.input= QLineEdit('',self)
        self.input.setGeometry(50,10,220,25)
        self.input.setAcceptDrops(True)
        
        execution = QPushButton('実行',self)
        execution.setGeometry(290,10,50,30)
        execution.released.connect(self.execute)
        
        clear = QPushButton('クリア',self)
        clear.setGeometry(290,50,50,30)
        clear.released.connect(self.clear)
        
        self.rbtns = QButtonGroup()
        self.inspect = QRadioButton("Inspect",self)
        self.inspect.setGeometry(50,40,90,20)
        self.inspect.setChecked(True)
        self.rbtns.addButton(self.inspect)
        
        self.resize_img = QRadioButton("Resize",self)
        self.resize_img.setGeometry(50,65,90,20)
        self.rbtns.addButton(self.resize_img)
        
        width_label = QLabel('W',self)
        width_label.setGeometry(135,70,15,10)
        width_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        width_label.setStyleSheet('font-size:10px')
        
        self.width = QLineEdit('',self)
        self.width.setGeometry(155,65,45,20)
        
        height_label = QLabel('H',self)
        height_label.setGeometry(205,70,15,10)
        height_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        height_label.setStyleSheet('font-size:10px')
        
        self.height = QLineEdit('',self)
        self.height.setGeometry(220,65,45,20)
        
        self.icns = QRadioButton("icns作成",self)
        self.icns.setGeometry(50,90,90,20)
        self.icns.setToolTip('PNG file[2048*2048,72px] required')  
        self.rbtns.addButton(self.icns)
        
        self.output = QTextEdit('',self)
        self.output.setGeometry(50,115,240,100)
        self.output.setAcceptDrops(False)
        
    def dragEnterEvent(self, e):
        if(e.mimeData().hasUrls()):
            e.accept()

    def dropEvent(self, e):
        urls = e.mimeData().urls()
        path = Path(urls[0].toLocalFile())
        print(f"Drop_path {path}")
        self.input.setText(str(path))
        
    def execute(self):
        image_path = self.input.text()
        print(f"Exe_path {image_path}")
        img = Image.open(image_path)
        
        if self.inspect.isChecked():
            self.output.append("Size " + str(img.size) + "\n"+ "dpi " + str(img.info.get('dpi')))
        elif self.resize_img.isChecked():
            width = int(self.width.text())
            height = int(self.height.text())
            resize_img= img.resize((width,height))
            resize_img_path = ".".join(self.input.text().split(".")[:-1]) + "_resized." + (self.input.text()).split(".")[-1]
            print(f"Resize_path {resize_img_path}")
            resize_img.save(resize_img_path)
        else: # icns作成
            makeIcns.MakeIcns.make(None,image_path,self)
        
    def clear(self):
        self.input.clear()
from PIL import Image
import subprocess, os
from PyQt6.QtWidgets import QDialog,QPushButton,QLabel
from PyQt6.QtCore import Qt

class MakeIcns():
    def make(self, filepath0, window):
        img = Image.open(filepath0)
        print(str(img.size))
        if str(img.size)=="(2048, 2048)": # 2048*2048
            filepath0_jpg = ".".join(filepath0.split(".")[:-1]) + ".jpg" # 1024*1024 dpi=144
            filepath = ".".join(filepath0.split(".")[:-1]) + "1.png" # 1024*1024 dpi=144
            filepath2 = ".".join(filepath0.split(".")[:-1]) + "2.png" # 512*512 dpi=72
            filedir = "/".join(filepath0.split("/")[:-1]) + "/" + (filepath0.split("/")[-1]).split(".")[-2] + ".iconset/"
            
            print(f"filepath0_jpg {filepath0_jpg}")
            print(f"filepath {filepath}")
            print(f"filepath2 {filepath2}")
            print(f"filedir {filedir}")
            
            os.mkdir(filedir)

            img1 = Image.open(filepath0).convert("RGB")
            # 512*512 dpi=72
            img1_resize = img1.resize((512,512))
            img1_resize.save(filepath2)

            # dpi=144にするため一旦jpgへ変換
            img1_resize2 = img1.resize((1024,1024))
            img1_resize2.save(filepath0_jpg,dpi=(144,144))
            # jpgをpngへ変換
            img3 = Image.open(filepath0_jpg).convert("RGBA")
            img3.save(filepath,dpi=(144,144))

            pixels = [32, 64, 256, 512, 1024]
            pixels2 = [16, 32, 128, 256, 512]
            filepaths = ['icon_16x16@2x.png','icon_32x32@2x.png','icon_128x128@2x.png','icon_256x256@2x.png','icon_512x512@2x.png']
            filepaths2 = ['icon_16x16.png','icon_32x32.png','icon_128x128.png','icon_256x256.png','icon_512x512.png']

            # dpi=144の各種pngファイル作成
            for pixel,file in zip(pixels,filepaths):
                img = Image.open(filepath)
                img_resize = img.resize((pixel,pixel))
                img_resize.save(filedir + file)
                img.close()

            # dpi=72の各種pngファイル作成    
            for pixel,file in zip(pixels2,filepaths2):
                img = Image.open(filepath2)
                img_resize = img.resize((pixel,pixel))
                img_resize.save(filedir + file)
                img.close()

            # icnsファイル作成
            dir = "/".join(filepath0.split("/")[:-1])
            iconset = (filepath0.split("/")[-1]).split(".")[-2] + ".iconset"
            cmd = f'iconutil -c icns {iconset}'
            subprocess.run(cmd, cwd=dir,shell=True)
            
            os.remove(filepath0_jpg)
            os.remove(filepath)
            os.remove(filepath2)
        else:
            MakeIcns.showDialog(self,window)
            
    def showDialog(self,window):
        dlg = QDialog(window)
        dlg.setFixedSize(250,100)
        label = QLabel('This file is invalid.\nPNG file[2048*2048,72dpi] required',dlg)
        label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        label.move(15,20)
        label.setStyleSheet('font-size:14px')
        btn = QPushButton("OK",dlg)
        btn.move(90,60)
        def action():
            dlg.close()
        btn.released.connect(action)
        dlg.setWindowTitle("Attention")
        dlg.exec()