tkinter がうまくいかないので、PyQt6でWidget（ウィジェット）に挑戦（その１）

# 環境
>・　macOS Ventura 13.2
・　python3.10.4


# 何もわからない中、ChatGPTに質問を繰り返しPyQt6を勉強してみた。
>参考図書も探してみたが見つからない。
ネットを検索して、下記の参考にしたページが見つかって、まずは勉強したが、pyqt5も知らない（Widgetの基本も知らない）ので、難しいことだらけ。
　そこで、ChatGPTに質問を繰り返して作って見ることにした。
回答が間違っていてErrorが出ることもあったが、Errorの内容を示すと、素直に謝って修正後のprogramを示してくれたので、参考になった。

https://tech.nkhn37.net/python-gui-libraries/

# 取り敢えず出来上がったProgramを見て下さい。
>その前に、やっておくことがあります。
PyQt6のインストールです。
インストールは簡単です。pipでインストールしました。
**% python3 -m pip install pyqt6**


インストール後、これを実行すると
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/bd54f868-e066-af13-59ec-9efdc3d94377.png" alt="スクリーンショット" width="400">
と表示され、
起算日と日数を入力すると
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/49dc4eec-ec24-f066-eb6a-736d01cbaf04.png" alt="スクリーンショット" width="400">
となります。ぜひ試して見て下さい。


# ポイント
作成したいWidgetのイメージを書いてみると良いと思います。
```python
    def initUI(self):
        # Widgetのタイトルの設定
        self.setWindowTitle("起算日＋日数から年月日を計算")
```
そうすれば、def initUI(self):以下に記述するWidgetの配置がスムーズにできると思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/dbb0e578-2818-0f11-df41-b285aedbf0a8.png" alt="スクリーンショット" width="400">

そしてその順番に記述する。
操作することはdef xxx(self):で作って、connectでつなげていく。
最後に、def mainText(self):で処理することをpythonでCodeを書く。
ほとんど定型なので、基本形を作ればコピペでできる。
（苦労したのは、def xxx(self):で計算した年月日や日数をクラスのインスタンス変数に保存するところ）


```python
# PyQt6の操作
#----------------------------------------------------
import pandas as pd
from datetime import datetime, timedelta
#----------------------------------------------------
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QMainWindow, QLineEdit#, QRadioButton, QRadioButton, QComboBox

import PyQt6.QtCore as QtCore # QDateオブジェクトから年月日のみを取得する
from PyQt6.QtGui import QFont   # Fontを作成

# ******************************************************
# （ユーザー定義関数）
def add_days_to_date(start_date, days):
    # 入力された日付をdatetimeオブジェクトに変換
    start_date = datetime.strptime(start_date, '%Y-%m-%d')

    # 指定された日数を日付に加算
    end_date = start_date + timedelta(days=days)

    # 結果を年月日の形式に変換
    end_date = end_date.strftime('%Y-%m-%d')

    return end_date

# ******************************************************
# ******************************************************
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        # -------------------
        self.initUI()
        # -------------------
        # クラスのインスタンス変数として定義する
        # (起算日)
        self.st_date = ""
        # (日数)
        self.number_days = None

# ******************************************************
    def initUI(self):
        # Widgetのタイトルの設定
        self.setWindowTitle("起算日＋日数から年月日を計算")
        #----------------------------------
        # 縦のレイアウトを作成
        layout = QVBoxLayout()# 必須
        self.setLayout(layout)# 必須
        #----------------------------------
        # FontSizeを設定
        font = QFont("Helvetica", 15, QFont.Weight.Normal)# 必要で必要に応じて
        # *************************************************
        '''Widgetを設計（想定）してLabelやButtonを表示指定順に記述'''
        # 説明するラベル(Labelの作成とlayout設定)
        self.lbl_01 = QLabel("起算日＋日数から年月日を計算をします。",self)# 必須
        # label Fontの設定
        self.lbl_01.setFont(font)# 必要で必要に応じて
        # styleSheetを使用して色を設定
        self.lbl_01.setStyleSheet("color:brown")# 必要で必要に応じて
        # layoutの設定
        layout.addWidget(self.lbl_01)# 必須

        #----------------------------------------------------
        # 起算日を入力を表示(Labelの作成とlayout設定)
        self.lbl_02 = QLabel("起算日を入力:",self)
        # label Fontの設定
        self.lbl_02.setFont(font)
        # styleSheetを使用して色を設定
        self.lbl_02.setStyleSheet("color:blue")
        # layoutの設定
        layout.addWidget(self.lbl_02)

        #----------------------------------------------------
        # LineEditで起算日入力欄を作成
        self.s_date = QLineEdit(self,placeholderText="入力例：20230531")# 必須
        # connectで「def format_date1(self,text):」オブジェクトを呼び出し
        self.s_date.textChanged.connect(self.format_date1)
        layout.addWidget(self.s_date)# 必須
        # 横幅を指定
        self.s_date.setFixedWidth(188)# 必要で必要に応じて
        
        #----------------------------------------------------
        # 日数を入力を表示（Labelの作成とlayout設定）
        self.lbl_03 = QLabel("日数を入力:",self)
        # label Fontの設定
        self.lbl_03.setFont(font)
        # styleSheetを使用して色を設定
        self.lbl_03.setStyleSheet("color:blue")
        # layoutの設定
        layout.addWidget(self.lbl_03)
        #----------------------------------------------------
        # LineEditで日数入力欄を作成
        self.numberdays = QLineEdit(self,placeholderText="入力例：31")
        # connectで「def format_date2(self,text):」オブジェクトを呼び出し
        self.numberdays.textChanged.connect(self.format_date2)
        layout.addWidget(self.numberdays)
        # 横幅を指定
        self.numberdays.setFixedWidth(80)

        #----------------------------------------------------
        # 計算を開始するボタンの作成
        self.btn01 = QPushButton("Enter",self,checkable=True)
        self.btn01.clicked.connect(self.mainText)
        layout.addWidget(self.btn01)

        #----------------------------------------------------
        # 結果を表示する（Labelの作成とlayout設定）
        self.lbl_04 = QLabel("計算結果:",self)
        # label Fontの設定（不要の場合はコメンアウト）
        self.lbl_04.setFont(font)
        # styleSheetを使用して色を設定（不要の場合はコメンアウト）
        self.lbl_04.setStyleSheet("color:red")
        # layoutの設定
        layout.addWidget(self.lbl_04)

        
        #----------------------------------------------------
        # Widgetを終了するボタン
        self.btn_fin= QPushButton("Finish",self,checkable=True)
        self.btn_fin.clicked.connect(QApplication.quit)
        layout.addWidget(self.btn_fin)
        
# ******************************************************
    def format_date1(self,text):
        #入力された日付テキストを取得して、８桁の数字であることを確認
        if len(text) != 8 or not text.isdigit():
            return
        #----------------------------------
        # QDateオブジェクトを作成して年月日をセット
        year = int(text[0:4])
        month = int(text[4:6])
        day = int(text[6:8])
        date = QtCore.QDate(year,month,day)
        #----------------------------------
        # 日付を文字列に変換して、スラッシュを挿入
        formatted_date = date.toString("yyyy-MM-dd")
        #----------------------------------
        # QLineEditにフォーマットされた日付をセット
        self.s_date.setText(formatted_date)
        #----------------------------------
        # クラスのインスタンス変数に保存する（どこでも使えるように）
        julian_day = date.toJulianDay()
        self.st_date = pd.to_datetime(formatted_date).date()
        # print(f"st_date={self.st_date}")#コンソールに表示
# ******************************************************
    def format_date2(self,text):
        # クラスのインスタンス変数に保存する（どこでも使えるように）
        temp_days = self.numberdays.text()
        self.number_days = int(temp_days)
        # print(f"number_days={self.number_days}")# コンソールに表示
        
# ******************************************************
    def mainText(self):
        '''色々な処理をするpython3 Codeを記入'''
        # テスト用の入力値
        start_date = str(self.st_date)
        days_to_add = self.number_days

        # ユーザー定義関数を呼び出して結果を表示
        result_date = add_days_to_date(start_date, days_to_add)
        
        self.lbl_04.setText(f"------------------------------------------------------------\n計算の結果は「 {result_date} 」となります。")

        # print(f"rslt_date={result_date}")# コンソールに表示

# ******************************************************
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    #-----GraphWindowへ飛び処理が終了したら戻ってくる------------
    window.show()
    sys.exit(app.exec())    # PyQt6アプリケーションのメインループを開始し、アプリケーションが終了するときに呼び出される関数

```
# 関係リンク
><font color="green">**"ChatGPT for Mac" をインストールして使ってみた。**</font>
https://qiita.com/ti104110/items/40563e13d9f389bd62bd
***
><font color="green">**tkinter がうまくいかないので、PyQt6でWidget（ウィジェット）に挑戦（その２）RadioButtonで選択してWebを開く**</font>
https://qiita.com/ti104110/items/7785758f98ef978c2d97
***
><font color="green">**tkinter がうまくいかないので、PyQt6でWidget（ウィジェット）に挑戦（その３）QGridLayout()オブジェクトを使って、labelとQLineEditを横並びに表示**</font>
https://qiita.com/ti104110/items/a35263176ff5ddaafac7
***

><font color="green">**tkinter がうまくいかないので、PyQt6でWidget（ウィジェット）に挑戦（その４）自作programをRadiButtonでリスト化**</font>
https://qiita.com/ti104110/items/dc07bcb2d0fa7a9ff269
***
>**tkinter がうまくいかないので、PyQt6でウィジェットに挑戦（その５）「Googleの急上昇ワード」の表示に"QTextBrowser"でURLにリンク設定を追加**
https://qiita.com/ti104110/items/d9868846ff7ac9556edf

# あとがき
>これらは、参考図書がないため、ほとんどchatGPTに「pyqt6でlabelの作り方を具体的に教えて？」などと聞きながら作りました。
ググったり、本を読むより早くわかりやすく進みました。
たまには、言われた通り記述してもErrorが出ることがあり、その都度Error内容を伝えると、「申し訳ありません。xxxxが説明不足でした。・・・・」とすぐ訂正Codeが来るので、結構楽しく出来ました。