PySide

QTableWidget についてまとめてみる

久しぶりに QTableWidget を使う機会があったんですが、色々と苦戦したのででまとめておきます。

基本的な QTableWidget の作り方

とりあえず下記のコードが使えれば基本的なテーブルウィジェットは作れます。

# テーブルウィジェットの設置
# --------------------------------------------------------------------------------------------------------------
self.table_widget = QtWidgets.QTableWidget()
root_area.addWidget(self.table_widget)

# 行数 の設定
self.table_widget.setRowCount(15)

# 列数 の設定
self.table_widget.setColumnCount(6)

# 行のヘッダー 設定
row_item = QtWidgets.QTableWidgetItem('行のヘッダー名')
self.table_widget.setVerticalHeaderItem(0, row_item)

# 列のヘッダー名 の設定
col_item = QtWidgets.QTableWidgetItem('列のヘッダー名')
self.table_widget.setHorizontalHeaderItem(0, col_item)

# 値の設置
value_item = QtWidgets.QTableWidgetItem('値')
self.table_widget.setItem(1, 2, value_item)
# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function, unicode_literals)

import sys

from PySide2 import QtWidgets, QtCore


# noinspection PyAttributeOutsideInit
class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        """
        ウィンドウ設定
        """
        super(MainWindow, self).__init__()

        self.resize(QtCore.QSize(700, 500))
        self.setWindowTitle('QTableWidget')
        self.init_ui()

    def init_ui(self):
        """
        UI の初期化
        """
        wrapper = QtWidgets.QWidget()
        self.setCentralWidget(wrapper)

        root_area = QtWidgets.QVBoxLayout()
        wrapper.setLayout(root_area)

        # テーブルウィジェットの設置
        # --------------------------------------------------------------------------------------------------------------
        self.table_widget = QtWidgets.QTableWidget()
        root_area.addWidget(self.table_widget)

        # 行数 の設定
        self.table_widget.setRowCount(15)

        # 列数 の設定
        self.table_widget.setColumnCount(6)

        # 行のヘッダー 設定
        row_item = QtWidgets.QTableWidgetItem('行のヘッダー名')
        self.table_widget.setVerticalHeaderItem(0, row_item)

        # 列のヘッダー名 の設定
        col_item = QtWidgets.QTableWidgetItem('列のヘッダー名')
        self.table_widget.setHorizontalHeaderItem(0, col_item)

        # 値の設置
        value_item = QtWidgets.QTableWidgetItem('値')
        self.table_widget.setItem(1, 2, value_item)


def launch():
    """
    ウィンドウの起動
    """
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())


# 起動
if __name__ == '__main__':
    launch()

テーブルウィジェットの作成

self.table_widget = QtWidgets.QTableWidget()
root_area.addWidget(self.table_widget)

テーブルウィジェットを作ってレイアウトにいれるだけです。

行と列の設定

このテーブルウィジェットに行と列を設定します。

# 行数 の設定
self.table_widget.setRowCount(15)

# 列数 の設定
self.table_widget.setColumnCount(6)

ヘッダーを設定する

# 行のヘッダー 設定
row_item = QtWidgets.QTableWidgetItem('行のヘッダー名')
self.table_widget.setVerticalHeaderItem(0, row_item)

# 列のヘッダー名 の設定
col_item = QtWidgets.QTableWidgetItem('列のヘッダー名')
self.table_widget.setHorizontalHeaderItem(0, col_item)

第一引数の数値を変えることで各ヘッダーの列数 / 行数を指定できます。

値を入れる

# 値の設置
value_item = QtWidgets.QTableWidgetItem('値')
self.table_widget.setItem(1, 2, value_item)
.setItem(行数, 列数, QTableWidgetItem)

自動で表示する QTableWidget をつくる

上記のコードだと使いづらいので、テーブルウィジェットを継承してカスタマイズしていきます。
データを渡すだけで自動で表を表示してくれるテーブルウィジェットをつくります。

クラスの作成

# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function, unicode_literals)

import sys

from PySide2 import QtWidgets, QtCore


# noinspection PyAttributeOutsideInit
class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        """
        ウィンドウ設定
        """
        super(MainWindow, self).__init__()

        self.resize(QtCore.QSize(700, 500))
        self.setWindowTitle('QTableWidget')
        self.init_ui()

    def init_ui(self):
        """
        UI の初期化
        """
        wrapper = QtWidgets.QWidget()
        self.setCentralWidget(wrapper)

        root_area = QtWidgets.QVBoxLayout()
        wrapper.setLayout(root_area)

        # テーブルウィジェットの設置
        self.table_widget = MyTableWidget(root_area)


'''

QTableWidget を継承して改造する
------------------------------------------------------------------------------------------------------------------------
'''


class MyTableWidget(QtWidgets.QTableWidget):

    def __init__(self, put_area=None):
        """
        QTableWidget をカスタムしたやつ

        :param put_area: 設置するレイアウト
        """
        super(MyTableWidget, self).__init__()

        self.put_area = put_area

        self.init_ui()

    def init_ui(self):
        """
        UI の初期化
        """

        if self.put_area is not None:
            self.put_area.addWidget(self)

    # 値の入力
    # ------------------------------------------------------------------------------------------------------------------
    def set_value(self, input_value=None):
        """
        値の自動セット

        :param input_value: 入力する値
        """
        self.clear()

        if input_value is None:
            return

        #
        # 渡された値で分岐
        #
        if type(input_value) == list:
            self.set_list(input_value)

    #
    # リスト型の場合の入力
    def set_list(self, list_value):
        pass


def launch():
    """
    ウィンドウの起動
    """
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())


# 起動
if __name__ == '__main__':
    launch()

このクラスを色々と弄っていきます。

値の自動入力

渡された値を自動で入力する仕組みにしていきます。
対応させるのは、

  • 2次元リスト
  • 値がリストの辞書
  • csv ファイル

の 3種類です。

これらを渡されたとき、下記の事を自動で行えるメソッドを作ります。

  • 行数 / 列数の自動設定
  • ヘッダーの自動設定
  • 値の自動設定

テーブルウィジェットを設置後、set_value メソッドに値を渡すことでこれらを自動で行えるようにしていきます。

# テーブルウィジェットの設置
self.table_widget = MyTableWidget(root_area)
self.table_widget.set_value(value)

2次元リストの入力

value = [
    ['grape', 'apple', 'orange', 'strawberry'],
    ['dog', 'cat', 'monkey', 'lion', 'bear'],
    ['spoon', 'fork', 'knife', 'dish'],
    'book'
]

上記のような2次元 または 1次元のリストを入力します。
ヘッダーを指定しない場合です。

    #
    # リスト型の場合の入力
    def set_list(self, list_value):
        """
        2次元までのリストを TableWidget へ表示

        :param list_value: テーブルに入れる値。2次元までのリストに対応
        :type list_value: list
        """

        # ここではリスト型しか処理しない
        if not type(list_value) == list:
            return

        max_column_count = 1

        # 行数の設定 リストの最大値がそのまま行数になる
        self.setRowCount(len(list_value))

        for row_count, row_value in enumerate(list_value):

            self.setColumnCount(max_column_count)

            # リストでない場合はそのまま 0列目に値を入力
            if not type(row_value) == list:
                item = QtWidgets.QTableWidgetItem(row_value)
                self.setItem(row_count, 0, item)

            # リストの場合は
            else:
                for column_count, column_value in enumerate(row_value):

                    # 列数の設定
                    #
                    # ループする度に列数の最大値を取得し、
                    # 更新があればそのタイミングでウィジェットに変更を加える

                    column_count = column_count + 1

                    if max_column_count < column_count:
                        max_column_count = column_count
                        self.setColumnCount(max_column_count)

                    # 値の入力
                    # column_count は列数の計算で +1 しているので戻してから利用する

                    item = QtWidgets.QTableWidgetItem(column_value)
                    self.setItem(row_count, column_count - 1, item)

リストの値の数の差にも対応させていますし、1次元の book にも対応できています。

辞書型 の入力

value = {
    'fruit': [
        'grape', 'apple', 'orange', 'strawberry'
    ],
    'animal': [
        'dog', 'cat', 'monkey', 'lion', 'bear'
    ],
    'tableware': [
        'spoon', 'fork', 'knife', 'dish'
    ],
    'desktop': 'book'
}

上記の辞書型の値を入力できるようにします。
辞書型の場合はキーをヘッダーへ登録するようにします。

処理の流れとしては、

  1. キーをヘッダーに登録
  2. 値をリストに追加して2次元のリスト
  3. 先ほどの set_list に渡す

という処理をします。

#
# 辞書型の場合の入力
def set_dict(self, dict_value):
    """
    辞書型の値を TableWidget へ表示

    :param dict_value: 入力する値
    :type dict_value: dict
    """
    
    # ここでは辞書型しか処理しない
    if not type(dict_value) == dict:
        return

    # 行数の設定 リストの最大値がそのまま行数になる
    self.setRowCount(len(dict_value))

    list_value = []

    for row_count, key in enumerate(dict_value):

        # 行のヘッダー 設定
        row_item = QtWidgets.QTableWidgetItem(key)
        self.setVerticalHeaderItem(row_count, row_item)

        # 値をリストに入れる
        list_value.append(dict_value[key])

    # リストをテーブルウィジェットに入力
    self.set_list(list_value)

csv ファイルの入力

サンプルとして下記のページの csv ファイルを読み込んでテーブルウィジェットへ入力できるようにします。

上記のサイトにある、

こちらの csv ファイルをサンプルにコードを書いていきます。

value = '202010-202106_2.csv'

渡す値は csv ファイルのパスです。

csv ファイルの編集

上記のサイトの csv はそのまま読めるようになっていないので、
余分なところを削除します。

この csv ファイルの場合は上から 3行が不要な項目です。
これがあると python で読み込めません。
削除して上書き保存し、このファイルのパスを set_value メソッドに渡します。

csv ファイルの入力コード

※ 下記のコードは 組み込みでない pandas と chardet のパッケージを使用しています。
そのため、DCC ツールで利用するには pip のインストールから必要です。

csv ファイルを pandas の DataFrame 型で読み込むのが下記のコードです。

# csv ファイルの読み込み
def read_csv_file(csv_file_path):
    """
    csv ファイル を DataFrame 型で読み込む

    :param csv_file_path: csv ファイルのパス
    :type csv_file_path: str
    :return: データフレーム型の csv ファイルの中身
    :rtype: pandas.core.frame.DataFrame
    """

    # 文字コードの取得
    with open(csv_file_path, 'rb') as f:
        binary_file = f.read()

    _encode = chardet.detect(binary_file)
    encode = _encode['encoding']

    # csv をデータフレームで読み込み
    df = pd.read_csv(csv_file_path, encoding=encode)

    return df

実際の処理が下記のコードです。

# csvファイルの入力
# ------------------------------------------------------------------------------------------------------------------
def set_csv_file(self, csv_file_path):
    """
    csv ファイルの中身をテーブルウィジェットへ入力

    :param csv_file_path: csv ファイルのパス
    :type csv_file_path: str
    """

    # ここでは存在する .csv ファイルのパスしか扱わない
    if not os.path.isfile(csv_file_path):
        return

    if not os.path.splitext(csv_file_path)[1].lower() == '.csv':
        return

    # csv ファイルの読み込み
    df = read_csv_file(csv_file_path)

    #
    #   値の入力
    #

    # データフレームを辞書型に変換
    # このコードでは行ベースで記述している。
    # データフレームは列ベースで書かれているため、転地したものを 辞書型に変換する
    dict_df = df.T.to_dict()

    dict_value = {}

    # csv は2次元の辞書型になっているため、{ key : list }の形にする。
    # すべての値をリストにし、それをキーの値に設定する。
    for row_key in dict_df:

        row_list = []

        for column_key in dict_df[row_key]:
            df_value = (dict_df[row_key][column_key])
            row_list.append(df_value)

        dict_value[row_key] = row_list

    # この文脈で扱える形になったため、set_dict へ繋げる
    self.set_dict(dict_value)

    #
    #   カラムのヘッダー設定
    #

    # .setColumnCount() でヘッダーがリセットされるため、値を入力した後でヘッダーを設定する
    column_base_dict_df = df.to_dict()

    for column_count, key in enumerate(column_base_dict_df.keys()):
        col_item = QtWidgets.QTableWidgetItem(str(key))
        self.setHorizontalHeaderItem(column_count, col_item)
  1. csv を DataFrame で読み込み
  2. csv を辞書型に変換
  3. { key: { key: value } } の形になっているので、{ key : list } の形に変換
  4. set_dict メソッドに渡して値を入力
  5. ヘッダーの登録

の順で処理を行っています。

テーブルウィジェットに元データと同じ表記にできています。

Excel のデータも読み込めるようにする

ついでなのでエクセルにも対応させておきます。
pandas はエクセルにも対応しています。

エクセルの読み方は下記です。

# Excel フィルの読み込み
def read_excel_file(excel_file_path):
    """
    Excel ファイル を DataFrame 型で読み込む

    :param excel_file_path: Excel ファイルのパス
    :type excel_file_path: str
    :return: データフレーム型の Excel ファイルの中身
    :rtype: pandas.core.frame.DataFrame
    """

    # Excel ファイルの読み込み
    input_book = pd.ExcelFile(excel_file_path)

    # シートの取得
    input_sheet_name = input_book.sheet_names

    # シートを指定してデータフレームに変換
    df = input_book.parse(input_sheet_name[0])

    return df

ここでは強制的に一番最初のシートを読むようにしています。
シートを GUI で変更したい場合は別途 ラインエディットなどを用意する必要があります。(ここではやりません。)

これに合わせて条件分岐の構文も変更しています。

# csv / Excel ファイルの入力
# ------------------------------------------------------------------------------------------------------------------
def set_csv_excel_file(self, csv_excel_file_path):
    """
    csv ファイルの中身をテーブルウィジェットへ入力

    :param csv_excel_file_path: csv / Excel ファイルのパス
    :type csv_excel_file_path: str
    """

    # ここでは存在する .csv / '.xlsx' /  .xls ファイルのパスしか扱わない
    if not os.path.isfile(csv_excel_file_path):
        return

    # csv ファイルの読み込み
    if os.path.splitext(csv_excel_file_path)[1].lower() == '.csv':
        df = read_csv_file(csv_excel_file_path)

    # Excel ファイルの読み込み
    elif os.path.splitext(csv_excel_file_path)[1].lower() == '.xlsx' or \
            os.path.splitext(csv_excel_file_path)[1].lower() == '.xls':
        df = read_excel_file(csv_excel_file_path)

    else:
        return

特に問題はなさそうです。
エクセルはデータフレームまで変換できればその後の処理は csv のときと同じです。

値を取得する

値を取得できるメソッドをつくっていきます。

実際に使用する際は他のウィジェットと組み合わせることになりますが、ここではセルを選択することで各情報を一括で取得できるようにしていきます。

編集不可にする

デフォルトだとセルをダブルクリックした際に編集モードになってしまいます。
今回は面倒なので編集不可にしてしまいます。

setReadOnly メソッドでいけると思っていたんですが、
QTableWidget はこれではだめそうです。
下記の文で編集不可にできました。

# 編集不可にする
self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)

QTableWidget のシグナル

使い勝手がよそうなシグナルだけまとめておきます。

セルのクリック

self.cellClicked.connect(lambda: print('cell clicked'))

こちらはセルのクリックの時にシグナルを出します。
ヘッダーの選択ではシグナルがでません。

セルのダブルクリック

self.cellDoubleClicked.connect(lambda: print('DoubleClicked'))

項目の変更

self.itemChanged.connect(lambda: print('item changed'))

こちらは項目を増やしたり、セルの内容を書き換えた際にシグナルを出します。

セルの項目の選択変更

self.currentCellChanged.connect(lambda: print('current cell changed'))

このシグナルは初期化の際にも発生します。
ヘッダーの選択時にもシグナルを出します。

今回はこのシグナルで色んな情報を取得していくことにします。

クラスの初期化の時に編集不可とシグナルの設定を行っておきます。

class MyTableWidget(QtWidgets.QTableWidget):

    def __init__(self, put_area=None):
        """
        QTableWidget をカスタムしたやつ

        :param put_area: 設置するレイアウト
        """
        super(MyTableWidget, self).__init__()

        self.put_area = put_area

        # 編集不可にする
        self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)

        # セルの選択状況変更時のシグナル
        self.currentCellChanged.connect(lambda: self.current_cell_changed())

        self.init_ui()
# いろんな情報を取得する
# ==================================================================================================================
def current_cell_changed(self):
    print('\n\n')

接続先のメソッドから各情報を出力するようにしていきます。

セルの情報を取得する(単一選択)

    # いろんな情報を取得する
    # ==================================================================================================================
    def current_cell_changed(self):

        # 最後に選択しているセルのみの情報を取得できる
        print('cell_text', self.get_current_cell_text())
        print('cell_row', self.get_current_cell_row())
        print('cell_column', self.get_current_cell_column())
        print('header_row', self.get_current_vertical_header_text())
        print('header_column', self.get_current_horizontal_header_text())
        print('')

    # 文字列の取得
    def get_current_cell_text(self):
        """
        セルに入っている文字列を取得する。
        複数選択時は最初のセルの文字列のみ取得する。

        :return: 選択中のセルの文字列
        :rtype: str
        """
        item = self.currentItem()
        return item.text()

    # 行数の取得
    def get_current_cell_row(self):
        """
        セルに入っている行数を取得する。
        複数選択時は最初のセルの行数のみ取得する。

        :return: 選択中のセルの行数
        :rtype: int
        """

        row = self.currentRow()
        return row

    # 列数の取得
    def get_current_cell_column(self):
        """
        セルに入っている列数を取得する。
        複数選択時は最初のセルの列数のみ取得する。

        :return: 選択中のセルの列数
        :rtype: int
        """

        column = self.currentColumn()
        return column

    # 行のヘッダーテキスト
    def get_current_vertical_header_text(self):
        """
        列のヘッダーテキストの取得

        :return: 列のヘッダーテキスト
        :rtype: str
        """
        row = self.get_current_cell_row()
        v_header_text = self.verticalHeaderItem(row).text()
        return v_header_text

    # 列のヘッダーテキスト
    def get_current_horizontal_header_text(self):
        """
        列のヘッダーテキストの取得

        :return: 列のヘッダーテキスト
        :rtype: str
        """
        column = self.get_current_cell_column()
        h_header_text = self.horizontalHeaderItem(column).text()
        return h_header_text

これらのメソッドは複数選択に対応していません。
複数選択している場合は最初のセルの情報のみ取得してきます。

全体の列 / 行の個数の取得

全体の行や列の個数を取得するには下記のコードを利用します。

# 行の個数
def get_row_count(self):
    """
    全体の行の個数の取得

    :return: 行の個数
    :rtype: int
    """
    row_count = self.rowCount()
    return row_count

# 列の個数
def get_column_count(self):
    """
    列の個数の取得

    :return: 列の個数
    :rtype: int
    """
    column_count = self.columnCount()
    return column_count

選択中のすべてのセルの情報を取得する

選択中の QTableWidgetItem の取得

select_items = self.selectedItems()

selectedItems メソッドは
選択中のセルの QTableWidgetItem クラスをリストで返します。

[<PySide2.QtWidgets.QTableWidgetItem object at 0x000001F3ACBD9E88>, <PySide2.QtWidgets.QTableWidgetItem object at 0x000001F3ACBD9F08>]

これを for 文でループさせ、各 QTableWidgetItem からセルの情報を取り出します。

各 QTableWidgetItem の情報を取り出す

# 選択中のセルの情報を取得する
def get_select_item_info(self):
    """
    選択中のセルの情報を [{key : value}] の形で取得する。\n
    辞書のキー は\n
    文字列 : 'text' \n
    行数 : 'row' \n
    列数 : 'column'

    :return: [ { key : value} ]
    :rtype: list
    """
    select_items = self.selectedItems()

    # 選択中のセルがない場合は処理を抜ける
    if len(select_items) == 0:
        return None

    # 各項目の値を辞書型にし、リストにいれて返す
    return_list = []

    for item in select_items:

        value_dict = {
            'text': item.text(),
            'row': item.row(),
            'column': item.column()
        }

        return_list.append(value_dict)

    return return_list

見た目を変更する

ここから見た目を変更していきます。

最終的にはこんな見た目になりました。

QTableWidget の QSS

QTableWidget

'QTableWidget{}'

QTableWidget 全体に対しての QSS を設定します。セレクタはそのまま QTableWidget です。
特殊なプロパティが二つ用意されています。

alternate-background-color: #464646;
gridline-color: #646464; 
alternate-background-color

alternate-background-color は背景色を交互に変更する設定をした際の背景色を設定します。
交互に変更する設定は QTableWidget クラスに .setAlternatingRowColors(True) を設定します。

# 行ごとに交互に色を変更する
self.setAlternatingRowColors(True)

.setAlternatingRowColors(True)alternate-background-color はセットで使用するケースが多いと思います。

gridline-color

そのままセルを分けているグリッドラインの色を指定するプロパティです。
QTableWidget セレクタに対して設定します。

セルのセレクタである QTableWidget:item セレクタに対してボーダーを指定した場合、
セルの内側にさらにボーダーが追加されることになります。

QTableCornerButton::section

テーブルウィジェットの左上にある全てのセルを選択するボタンです。

ここのスタイルを変更するには QTableCornerButton::section セレクタで設定します。

セルに関するセレクタ

セルに関するセレクタです。

'''
QTableWidget:item {
    background-color:transparent;
}

QTableWidget:item::selected {
    background-color: #3a3a3a;
    color: #fff;
}

QTableWidget:item::hover {
    color: #fff;
}
'''

特に特殊なものはありません。

ヘッダーに関するセレクタ

'''
QHeaderView {
    background-color:transparent;
}

QHeaderView::section {
    color: #cccccc;
    font-weight:bold;
    border:0px solid #555;
    border-width:0px 1px 1px 0px;
}

QHeaderView::section:checked {
    background-color: #0059A4;
}

QHeaderView::section:hover {
}
'''

ヘッダーも特殊なものはありません。

QScrollBar の QSS

少し本題とは逸れる気がしますが、ついでにこちらもまとめておきます。

この辺とか参考になると思います。

各セレクタと設定しそうなプロパティ

'''

/* スクロールバー全体 */
QScrollBar {
}

/* ハンドル */
QScrollBar::handle {
}

/* 横のハンドル */
QScrollBar::handle:horizontal {
    background-image: url(icon_handle_horizontal.png);
    background-repeat: no-repeat;
    background-position: center;
    min-width: 50px;
}

/* 縦のハンドル */
QScrollBar::handle:vertical {
    background-image: url(icon_handle_vertical.png);
    background-repeat: no-repeat;
    background-position: center;
    min-height: 50px;
}

/* スクロールバーのハンドル以外の部分の戻る部分 */
QScrollBar::sub-page {
}

/*スクロールバーのハンドル以外の部分の進む部分 */
QScrollBar::add-page {
}

/* 横のスクロールバー全体 */
QScrollBar:horizontal {
    height: 18px
}

/* 横のスクロールバーの戻るボタン */
QScrollBar::sub-line:horizontal {
    subcontrol-position:left;
    subcontrol-origin:margin;
    width: 18px;
    image: url(icon_left.png);
}

/* 横のスクロールバーの進むボタン */
QScrollBar::add-line:horizontal {
    subcontrol-position:right;
    subcontrol-origin:margin;
    width: 18px;
    image: url(icon_right.png);
}

/* 縦のスクロールバー全体 */
QScrollBar:vertical {
    width: 18px;
}

QScrollBar::sub-line:vertical {
    subcontrol-position:top;
    subcontrol-origin:margin;
    height: 18px;
    image: url(icon_top.png)
}

QScrollBar::add-line:vertical {
    subcontrol-position:bottom;
    subcontrol-origin:margin;
    height: 18px;
    image: url(icon_bottom.png);
}

'''

実際に書いたコード

実際に記述する際には

  1. グローバル変数で共通の値を入れた変数を作る
  2. プロパティを作成し、インスタンス変数に入れる
  3. プロパティを各セレクタにセットする

という段階を踏んでいます。

これは特にこうしなければならない、というわけではなく、
今のところ個人的にこの形が最も保守がしやすい書き方だからです。

1 のグローバル変数の値を変更するだけで一括でスタイルを変更することができます。

共通の値

# フォントに関する設定
FONT_FAMILY_JA = '游ゴシック'
MAIN_FONT_COLOR = '#cccccc'
MAIN_FONT_SIZE = 14

# 倍軽食
MAIN_BG_COLOR = '#3a3a3a'
BLUE_01 = '#0059A4'
TOUCH_COLOR = '#525252'
TOUCH_COLOR_02 = '#5c5c5c'
BORDER_COLOR = '#646464'

プロパティの作成

def generate_property(self):
"""
プロパティ の生成
"""
# テーブルウィジェット の css
# --------------------------------------------------------------------------------------------------------------

# QTableWidget 全体の css
self.table_widget_css = '''
    color:{};
    font-weight:bold;
    background:transparent;
    border:0px solid red;
    gridline-color:{};
    alternate-background-color:#464646;
'''.format(
    self.font_color,
    self.border_color,
)

# 角のコーナー部分
self.table_corner_button_section_css = '''
    background-color:#464646;
'''

# ヘッダーの項目外の部分
self.header_view_css = '''
    background-color:transparent;
'''

# ヘッダーの項目
self.header_view_section_css = '''
    color:{};
    font-weight:bold;
    background:transparent;
    border:0px solid #555;
    border-width:0px 1px 1px 0px;
'''.format(
    self.font_color,
)

# 選択中のヘッダー
self.header_view_section_checked_css = '''
    background-color:{};
'''.format(
    self.highlight_color
)

# マウスオーバー時のヘッダー
self.header_view_section_hover_css = '''
'''

# セル
self.item_css = '''
    background-color:transparent;
    border:0px solid red;
'''

# 選択時のセル
self.item_selected_css = '''
    background-color:{};
    color:#fff;
'''.format(
    self.highlight_color
)

# マウスオーバー時のセル
self.item_hover_css = '''
    color:#fff;
'''

# スクロールエリア の css
# --------------------------------------------------------------------------------------------------------------

# スクロールバー全体
self.scroll_bar_css = '''
    background-color:transparent;
    border:0px solid red;
'''

# ハンドル
self.scroll_bar_handle_css = '''
    background-color:{};
    border: 1px solid #2c2c2c;
'''.format(
    self.touch_color
)

self.scroll_bar_handle_horizontal_css = '''
    background-image: url(icon_handle_horizontal.png);
    background-repeat: no-repeat;
    background-position: center;
    min-width: 50px;
'''

self.scroll_bar_handle_vertical_css = '''
    background-image: url(icon_handle_vertical.png);
    background-repeat: no-repeat;
    background-position: center;
    min-height: 50px;
'''

# ハンドルの外
self.scroll_bar_page_css = '''
    background-color:#2c2c2c;
    border: 0px solid #8e8e8e;
'''

margin = 0
border_width = 0

scroller_width = 18

#
#   横のスクロールバー
#

# 横のスクロールバー
self.scroll_bar_horizontal_css = '''
    margin: 0px {}px;
    height:{}px;
    padding-top:{}px;
    border-top: 0px solid {};
'''.format(
    scroller_width,
    scroller_width,
    margin,
    border_width,
    self.border_color,
)

# 左のボタン
self.scroll_bar_sub_line_horizontal = '''
    subcontrol-position:left;
    subcontrol-origin:margin;
    width:{}px;
    background-color:{};
    border: 1px solid #2c2c2c;
    image: url(icon_left.png);
'''.format(
    scroller_width,
    self.touch_color,
)

# 右のボタン
self.scroll_bar_add_line_horizontal = '''
    subcontrol-position:right;
    subcontrol-origin:margin;
    width:{}px;
    background-color:{};
    border:1px solid #2c2c2c;
    image: url(icon_right.png);
'''.format(
    scroller_width,
    self.touch_color,
)

#
#   縦のスクロールバー
#

# 縦のスクロールバー
self.scroll_bar_vertical_css = '''
    margin: {}px 0px;
    width:{}px;
'''.format(
    scroller_width,
    scroller_width,
)

# 上のボタン
self.scroll_bar_sub_line_vertical = '''
    subcontrol-position:top;
    subcontrol-origin:margin;
    height:{}px;
    background-color:{};
    border: 1px solid #2c2c2c;
    image: url(icon_top.png);
'''.format(
    scroller_width,
    self.touch_color,
)

# 下のボタン
self.scroll_bar_add_line_vertical = '''
    subcontrol-position:bottom;
    subcontrol-origin:margin;
    height:{}px;
    background-color:{};
    border:1px solid #2c2c2c;
    image: url(icon_bottom.png);
'''.format(
    scroller_width,
    self.touch_color,
)

セレクタにセット

self.setStyleSheet(

    # テーブルウィジェットの QSS
    'QTableWidget{}'.format('{' + self.table_widget_css + '}') +
    'QTableCornerButton::section{}'.format('{' + self.table_corner_button_section_css + '}') +
    'QHeaderView{}'.format('{' + self.header_view_css + '}') +
    'QHeaderView::section{}'.format('{' + self.header_view_section_css + '}') +
    'QHeaderView::section:checked{}'.format('{' + self.header_view_section_checked_css + '}') +
    'QHeaderView::section:hover{}'.format('{' + self.header_view_section_hover_css + '}') +
    'QTableWidget:item{}'.format('{' + self.item_css + '}') +
    'QTableWidget:item::selected{}'.format('{' + self.item_selected_css + '}') +
    'QTableWidget:item::hover{}'.format('{' + self.item_hover_css + '}') +

    # スクロールバーの QSS
    'QScrollBar{}'.format('{' + self.scroll_bar_css + '}') +
    'QScrollBar::handle{}'.format('{' + self.scroll_bar_handle_css + '}') +
    'QScrollBar::handle:horizontal{}'.format('{' + self.scroll_bar_handle_horizontal_css + '}') +
    'QScrollBar::handle:vertical{}'.format('{' + self.scroll_bar_handle_vertical_css + '}') +
    'QScrollBar::sub-page{}'.format('{' + self.scroll_bar_page_css + '}') +
    'QScrollBar::add-page{}'.format('{' + self.scroll_bar_page_css + '}') +
    'QScrollBar:horizontal{}'.format('{' + self.scroll_bar_horizontal_css + '}') +
    'QScrollBar::sub-line:horizontal{}'.format('{' + self.scroll_bar_sub_line_horizontal + '}') +
    'QScrollBar::add-line:horizontal{}'.format('{' + self.scroll_bar_add_line_horizontal + '}') +
    'QScrollBar:vertical{}'.format('{' + self.scroll_bar_vertical_css + '}') +
    'QScrollBar::sub-line:vertical{}'.format('{' + self.scroll_bar_sub_line_vertical + '}') +
    'QScrollBar::add-line:vertical{}'.format('{' + self.scroll_bar_add_line_vertical + '}')
)

コード全文

# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function, unicode_literals)

import os
import sys
import pandas as pd
import chardet
from PySide2 import QtWidgets, QtCore, QtGui
from PySide2.QtCore import Qt

value = '202010-202106_2.xlsx'

# QSS 用変数
# ----------------------------------------------------------------------------------------------------------------------

# フォントに関する設定
FONT_FAMILY_JA = '游ゴシック'
MAIN_FONT_COLOR = '#cccccc'
MAIN_FONT_SIZE = 14

# 倍軽食
MAIN_BG_COLOR = '#3a3a3a'
BLUE_01 = '#0059A4'
TOUCH_COLOR = '#525252'
TOUCH_COLOR_02 = '#5c5c5c'
BORDER_COLOR = '#646464'


#
# csv ファイルの読み込み
def read_csv_file(csv_file_path):
    """
    csv ファイル を DataFrame 型で読み込む

    :param csv_file_path: csv ファイルのパス
    :type csv_file_path: str
    :return: データフレーム型の csv ファイルの中身
    :rtype: pandas.core.frame.DataFrame
    """

    # 文字コードの取得
    with open(csv_file_path, 'rb') as f:
        binary_file = f.read()

    _encode = chardet.detect(binary_file)
    encode = _encode['encoding']

    # csv をデータフレームで読み込み
    df = pd.read_csv(csv_file_path, encoding=encode)

    return df


#
# Excel フィルの読み込み
def read_excel_file(excel_file_path):
    """
    Excel ファイル を DataFrame 型で読み込む

    :param excel_file_path: Excel ファイルのパス
    :type excel_file_path: str
    :return: データフレーム型の Excel ファイルの中身
    :rtype: pandas.core.frame.DataFrame
    """

    # Excel ファイルの読み込み
    input_book = pd.ExcelFile(excel_file_path)

    # シートの取得
    input_sheet_name = input_book.sheet_names

    # シートを指定してデータフレームに変換
    df = input_book.parse(input_sheet_name[0])

    return df


# noinspection PyAttributeOutsideInit
class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        """
        ウィンドウ設定
        """
        super(MainWindow, self).__init__()

        self.resize(QtCore.QSize(700, 500))
        self.setWindowTitle('QTableWidget')
        self.init_ui()

    def init_ui(self):
        """
        UI の初期化
        """
        self.setStyleSheet('background-color:{};'.format(MAIN_BG_COLOR))
        wrapper = QtWidgets.QWidget()
        self.setCentralWidget(wrapper)

        root_area = QtWidgets.QVBoxLayout()
        wrapper.setLayout(root_area)

        # テーブルウィジェットの設置
        self.table_widget = MyTableWidget()

        # ボタン01
        self.btn_01 = MyPushButton('選択中のセルの情報取得')
        self.btn_01.setFixedWidth(200)
        self.btn_01.clicked.connect(lambda: print(self.table_widget.get_select_item_info()))
        root_area.addWidget(self.btn_01)

        # テーブルウィジェットの設置
        root_area.addWidget(self.table_widget)
        self.table_widget.set_value(value)


'''

QTableWidget を継承して改造する
------------------------------------------------------------------------------------------------------------------------
'''


class MyTableWidget(QtWidgets.QTableWidget):

    def __init__(
            self, put_area=None,
            font_family=FONT_FAMILY_JA, font_color=MAIN_FONT_COLOR, bg_color=MAIN_BG_COLOR,
            touch_color=TOUCH_COLOR_02, highlight_color=BLUE_01, border_color=BORDER_COLOR
    ):
        """
        QTableWidget をカスタムしたやつ

        :param put_area: 設置するレイアウト
        """
        super(MyTableWidget, self).__init__()

        self.put_area = put_area

        self.font_family = font_family
        self.font_color = font_color
        self.highlight_color = highlight_color

        self.touch_color = touch_color

        self.bg_color = bg_color
        self.border_color = border_color

        #
        # css 用のインスタンス変数
        # self.generate_css() で内容を生成する
        self.table_widget_css = ''
        self.table_corner_button_section_css = ''
        self.header_view_css = ''
        self.header_view_section_css = ''
        self.header_view_section_checked_css = ''
        self.header_view_section_hover_css = ''
        self.item_css = ''
        self.item_selected_css = ''
        self.item_hover_css = ''

        # スクロールバー用
        self.scroll_bar_css = ''
        self.scroll_bar_handle_css = ''
        self.scroll_bar_handle_horizontal_css = ''
        self.scroll_bar_handle_vertical_css = ''
        self.scroll_bar_horizontal_css = ''
        self.scroll_bar_sub_line_horizontal = ''
        self.scroll_bar_add_line_horizontal = ''
        self.scroll_bar_vertical_css = ''
        self.scroll_bar_sub_line_vertical = ''
        self.scroll_bar_add_line_vertical = ''

        self.scroll_bar_page_css = ''

        self.init_ui()

    #
    # QSS の生成
    # ==================================================================================================================
        def generate_property(self):
        """
        プロパティ の生成
        """
        # テーブルウィジェット の css
        # --------------------------------------------------------------------------------------------------------------

        # QTableWidget 全体の css
        self.table_widget_css = '''
            color:{};
            font-weight:bold;
            background:transparent;
            border:0px solid red;
            gridline-color:{};
            alternate-background-color:#464646;
        '''.format(
            self.font_color,
            self.border_color,
        )

        # 角のコーナー部分
        self.table_corner_button_section_css = '''
            background-color:#464646;
        '''

        # ヘッダーの項目外の部分
        self.header_view_css = '''
            background-color:transparent;
        '''

        # ヘッダーの項目
        self.header_view_section_css = '''
            color:{};
            font-weight:bold;
            background:transparent;
            border:0px solid #555;
            border-width:0px 1px 1px 0px;
        '''.format(
            self.font_color,
        )

        # 選択中のヘッダー
        self.header_view_section_checked_css = '''
            background-color:{};
        '''.format(
            self.highlight_color
        )

        # マウスオーバー時のヘッダー
        self.header_view_section_hover_css = '''
        '''

        # セル
        self.item_css = '''
            background-color:transparent;
            border:0px solid red;
        '''

        # 選択時のセル
        self.item_selected_css = '''
            background-color:{};
            color:#fff;
        '''.format(
            self.highlight_color
        )

        # マウスオーバー時のセル
        self.item_hover_css = '''
            color:#fff;
        '''

        # スクロールエリア の css
        # --------------------------------------------------------------------------------------------------------------

        # スクロールバー全体
        self.scroll_bar_css = '''
            background-color:transparent;
            border:0px solid red;
        '''

        # ハンドル
        self.scroll_bar_handle_css = '''
            background-color:{};
            border: 1px solid #2c2c2c;
        '''.format(
            self.touch_color
        )

        self.scroll_bar_handle_horizontal_css = '''
            background-image: url(icon_handle_horizontal.png);
            background-repeat: no-repeat;
            background-position: center;
            min-width: 50px;
        '''

        self.scroll_bar_handle_vertical_css = '''
            background-image: url(icon_handle_vertical.png);
            background-repeat: no-repeat;
            background-position: center;
            min-height: 50px;
        '''

        # ハンドルの外
        self.scroll_bar_page_css = '''
            background-color:#2c2c2c;
            border: 0px solid #8e8e8e;
        '''

        margin = 0
        border_width = 0

        scroller_width = 18

        #
        #   横のスクロールバー
        #

        # 横のスクロールバー
        self.scroll_bar_horizontal_css = '''
            margin: 0px {}px;
            height:{}px;
            padding-top:{}px;
            border-top: 0px solid {};
        '''.format(
            scroller_width,
            scroller_width,
            margin,
            border_width,
            self.border_color,
        )

        # 左のボタン
        self.scroll_bar_sub_line_horizontal = '''
            subcontrol-position:left;
            subcontrol-origin:margin;
            width:{}px;
            background-color:{};
            border: 1px solid #2c2c2c;
            image: url(icon_left.png);
        '''.format(
            scroller_width,
            self.touch_color,
        )

        # 右のボタン
        self.scroll_bar_add_line_horizontal = '''
            subcontrol-position:right;
            subcontrol-origin:margin;
            width:{}px;
            background-color:{};
            border:1px solid #2c2c2c;
            image: url(icon_right.png);
        '''.format(
            scroller_width,
            self.touch_color,
        )

        #
        #   縦のスクロールバー
        #

        # 縦のスクロールバー
        self.scroll_bar_vertical_css = '''
            margin: {}px 0px;
            width:{}px;
        '''.format(
            scroller_width,
            scroller_width,
        )

        # 上のボタン
        self.scroll_bar_sub_line_vertical = '''
            subcontrol-position:top;
            subcontrol-origin:margin;
            height:{}px;
            background-color:{};
            border: 1px solid #2c2c2c;
            image: url(icon_top.png);
        '''.format(
            scroller_width,
            self.touch_color,
        )

        # 下のボタン
        self.scroll_bar_add_line_vertical = '''
            subcontrol-position:bottom;
            subcontrol-origin:margin;
            height:{}px;
            background-color:{};
            border:1px solid #2c2c2c;
            image: url(icon_bottom.png);
        '''.format(
            scroller_width,
            self.touch_color,
        )

    def init_ui(self):
        """
        UI の初期化
        """

        if self.put_area is not None:
            self.put_area.addWidget(self)

        # 編集不可にする
        self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)

        # フォントの設定
        self.setFont(QtGui.QFont(self.font_family))

        # css を生成
        self.generate_property()

        # 行ごとに交互に色を変更する
        self.setAlternatingRowColors(True)

        self.setStyleSheet(

            # テーブルウィジェットの QSS
            'QTableWidget{}'.format('{' + self.table_widget_css + '}') +
            'QTableCornerButton::section{}'.format('{' + self.table_corner_button_section_css + '}') +
            'QHeaderView{}'.format('{' + self.header_view_css + '}') +
            'QHeaderView::section{}'.format('{' + self.header_view_section_css + '}') +
            'QHeaderView::section:checked{}'.format('{' + self.header_view_section_checked_css + '}') +
            'QHeaderView::section:hover{}'.format('{' + self.header_view_section_hover_css + '}') +
            'QTableWidget:item{}'.format('{' + self.item_css + '}') +
            'QTableWidget:item::selected{}'.format('{' + self.item_selected_css + '}') +
            'QTableWidget:item::hover{}'.format('{' + self.item_hover_css + '}') +

            # スクロールバーの QSS
            'QScrollBar{}'.format('{' + self.scroll_bar_css + '}') +
            'QScrollBar::handle{}'.format('{' + self.scroll_bar_handle_css + '}') +
            'QScrollBar::handle:horizontal{}'.format('{' + self.scroll_bar_handle_horizontal_css + '}') +
            'QScrollBar::handle:vertical{}'.format('{' + self.scroll_bar_handle_vertical_css + '}') +
            'QScrollBar::sub-page{}'.format('{' + self.scroll_bar_page_css + '}') +
            'QScrollBar::add-page{}'.format('{' + self.scroll_bar_page_css + '}') +
            'QScrollBar:horizontal{}'.format('{' + self.scroll_bar_horizontal_css + '}') +
            'QScrollBar::sub-line:horizontal{}'.format('{' + self.scroll_bar_sub_line_horizontal + '}') +
            'QScrollBar::add-line:horizontal{}'.format('{' + self.scroll_bar_add_line_horizontal + '}') +
            'QScrollBar:vertical{}'.format('{' + self.scroll_bar_vertical_css + '}') +
            'QScrollBar::sub-line:vertical{}'.format('{' + self.scroll_bar_sub_line_vertical + '}') +
            'QScrollBar::add-line:vertical{}'.format('{' + self.scroll_bar_add_line_vertical + '}')
        )

    # 値の入力
    # ==================================================================================================================
    def set_value(self, input_value=None):
        """
        値の自動セット

        :param input_value: 入力する値
        """
        self.clear()

        if input_value is None:
            return

        #
        # 渡された値で分岐
        #
        if type(input_value) == list:
            self.set_list(input_value)

        elif type(input_value) == dict:
            self.set_dict(input_value)

        elif type(input_value) == str:
            self.set_csv_excel_file(input_value)

    #
    # リスト型の場合の入力
    # ------------------------------------------------------------------------------------------------------------------
    def set_list(self, list_value):
        """
        2次元までのリストを TableWidget へ表示

        :param list_value: テーブルに入れる値。2次元までのリストに対応
        :type list_value: list
        """

        # ここではリスト型しか処理しない
        if not type(list_value) == list:
            return

        max_column_count = 1

        # 行数の設定 リストの最大値がそのまま行数になる
        self.setRowCount(len(list_value))

        for row_count, row_value in enumerate(list_value):

            self.setColumnCount(max_column_count)

            # リストでない場合はそのまま 0列目に値を入力
            if not type(row_value) == list:
                item = QtWidgets.QTableWidgetItem(row_value)
                self.setItem(row_count, 0, item)

            # リストの場合は
            else:
                for column_count, column_value in enumerate(row_value):

                    #   列数の設定
                    #
                    # ループする度に列数の最大値を取得し、
                    # 更新があればそのタイミングでウィジェットに変更を加える

                    column_count = column_count + 1

                    if max_column_count < column_count:
                        max_column_count = column_count
                        self.setColumnCount(max_column_count)

                    #   値の入力
                    #
                    # ・ column_count は列数の計算で +1 しているので戻してから利用する
                    # ・ 整数も浮動小数になるため、末尾が .0 のものは削除する
                    cell_value = str(column_value)
                    if cell_value.endswith('.0'):
                        cell_value = cell_value[:-2]

                    item = QtWidgets.QTableWidgetItem(cell_value)
                    self.setItem(row_count, column_count - 1, item)

    #
    # 辞書型の場合の入力
    # ------------------------------------------------------------------------------------------------------------------
    def set_dict(self, dict_value):
        """
        辞書型の値を TableWidget へ表示

        :param dict_value: 入力する値
        :type dict_value: dict
        """

        # ここでは辞書型しか処理しない
        if not type(dict_value) == dict:
            return

        # 行数の設定 リストの最大値がそのまま行数になる
        self.setRowCount(len(dict_value))

        list_value = []

        for row_count, key in enumerate(dict_value):
            # 行のヘッダー 設定
            row_item = QtWidgets.QTableWidgetItem(str(key))
            self.setVerticalHeaderItem(row_count, row_item)

            # 値をリストに入れる
            list_value.append(dict_value[key])

        # リストをテーブルウィジェットに入力
        self.set_list(list_value)

    #
    # csv / Excel ファイルの入力
    # ------------------------------------------------------------------------------------------------------------------
    def set_csv_excel_file(self, csv_excel_file_path):
        """
        csv ファイルの中身をテーブルウィジェットへ入力

        :param csv_excel_file_path: csv / Excel ファイルのパス
        :type csv_excel_file_path: str
        """

        # ここでは存在する .csv / '.xlsx' /  .xls ファイルのパスしか扱わない
        if not os.path.isfile(csv_excel_file_path):
            return

        # csv ファイルの読み込み
        if os.path.splitext(csv_excel_file_path)[1].lower() == '.csv':
            df = read_csv_file(csv_excel_file_path)

        # Excel ファイルの読み込み
        elif os.path.splitext(csv_excel_file_path)[1].lower() == '.xlsx' or \
                os.path.splitext(csv_excel_file_path)[1].lower() == '.xls':
            df = read_excel_file(csv_excel_file_path)

        else:
            return

        #
        #   値の入力
        #

        # データフレームを辞書型に変換
        # このコードでは行ベースで記述している。
        # データフレームは列ベースで書かれているため、転地したものを 辞書型に変換する
        dict_df = df.T.to_dict()

        dict_value = {}

        # csv は2次元の辞書型になっているため、{ key : list }の形にする。
        # すべての値をリストにし、それをキーの値に設定する。
        for row_key in dict_df:

            row_list = []

            for column_key in dict_df[row_key]:
                df_value = (dict_df[row_key][column_key])
                row_list.append(df_value)

            dict_value[row_key] = row_list

        # この文脈で扱える形になったため、set_dict へ繋げる
        self.set_dict(dict_value)

        #
        #   カラムのヘッダー設定
        #

        # .setColumnCount() でヘッダーがリセットされるため、値を入力した後でヘッダーを設定する
        column_base_dict_df = df.to_dict()

        for column_count, key in enumerate(column_base_dict_df.keys()):
            col_item = QtWidgets.QTableWidgetItem(str(key))
            self.setHorizontalHeaderItem(column_count, col_item)

    #
    # 値の取得
    # ==================================================================================================================

    # 文字列の取得
    def get_current_cell_text(self):
        """
        セルに入っている文字列を取得する。
        複数選択時は最初のセルの文字列のみ取得する。

        :return: 選択中のセルの文字列
        :rtype: str
        """
        item = self.currentItem()
        return item.text()

    # 行数の取得
    def get_current_cell_row(self):
        """
        セルに入っている行数を取得する。
        複数選択時は最初のセルの行数のみ取得する。

        :return: 選択中のセルの行数
        :rtype: int
        """

        row = self.currentRow()
        return row

    # 列数の取得
    def get_current_cell_column(self):
        """
        セルに入っている列数を取得する。
        複数選択時は最初のセルの列数のみ取得する。

        :return: 選択中のセルの列数
        :rtype: int
        """

        column = self.currentColumn()
        return column

    # 行のヘッダーテキスト
    def get_current_vertical_header_text(self):
        """
        列のヘッダーテキストの取得

        :return: 列のヘッダーテキスト
        :rtype: str
        """
        row = self.get_current_cell_row()
        v_header_text = self.verticalHeaderItem(row).text()
        return v_header_text

    # 列のヘッダーテキスト
    def get_current_horizontal_header_text(self):
        """
        列のヘッダーテキストの取得

        :return: 列のヘッダーテキスト
        :rtype: str
        """
        column = self.get_current_cell_column()
        h_header_text = self.horizontalHeaderItem(column).text()
        return h_header_text

    # 行の個数
    def get_row_count(self):
        """
        全体の行の個数の取得

        :return: 行の個数
        :rtype: int
        """
        row_count = self.rowCount()
        return row_count

    # 列の個数
    def get_column_count(self):
        """
        列の個数の取得

        :return: 列の個数
        :rtype: int
        """
        column_count = self.columnCount()
        return column_count

    # 選択中のセルの情報を取得する
    def get_select_item_info(self):
        """
        選択中のセルの情報を [{key : value}] の形で取得する。\n
        辞書のキー は\n
        文字列 : 'text' \n
        行数 : 'row' \n
        列数 : 'column'

        :return: [ { key : value} ]
        :rtype: list
        """
        select_items = self.selectedItems()

        # 選択中のセルがない場合は処理を抜ける
        if len(select_items) == 0:
            return None

        # 各項目の値を辞書型にし、リストにいれて返す
        return_list = []

        for item in select_items:
            value_dict = {
                'text': item.text(),
                'row': item.row(),
                'column': item.column()
            }

            return_list.append(value_dict)

        return return_list


class MyPushButton(QtWidgets.QPushButton):

    def __init__(
            self, label_text=None, put_area=None,
            font_color=MAIN_FONT_COLOR, font_family=FONT_FAMILY_JA, bg_color=TOUCH_COLOR, hover_bg_color=BLUE_01
    ):
        super(MyPushButton, self).__init__(label_text)

        self.put_area = put_area

        self.font_family = font_family
        self.font_color = font_color
        self.bg_color = bg_color
        self.hover_bg_color = hover_bg_color

        self.push_button_qss = ''
        self.push_button_hover_qss = ''

        self.init_ui()

    def generate_property(self):
        height = 28

        self.push_button_qss = '''
            color:{};
            height: {}px;
            font-size: 12px;
            font-weight: bold;
            background-color:{};
            border: 2px solid #7d7d7d;
            border-radius: {}px;
        '''.format(
            self.font_color,
            height,
            self.bg_color,
            height / 2
        )

        self.push_button_hover_qss = '''
            color:#fff;
            background-color:{};
        '''.format(
            self.hover_bg_color
        )

    def init_ui(self):
        if self.put_area is not None:
            self.put_area.addWidget(self)

        self.generate_property()

        # フォントの設定
        self.setFont(QtGui.QFont(self.font_family))

        self.setStyleSheet(
            'QPushButton{}'.format('{' + self.push_button_qss + '}') +
            'QPushButton:hover{}'.format('{' + self.push_button_hover_qss + '}')
        )


def launch():
    """
    ウィンドウの起動
    """
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())


# 起動
if __name__ == '__main__':
    launch()

-PySide