プログラムで生活をHACKする

YRen-LaB

Python wxpython

【wxpython】CheckListCtrlMixinで画像を表示する

投稿日:


目的

以下のようなものをつくりたい。(つくった)

先の記事でListの作成まで書いた。

問題点

CheckListCtrlMixinを使用して作った表にはimageListを使用して画像を表示することができない。
この件は公式にも以下のように記載がある

You should not set a imagelist for the ListCtrl once this mixin is used.

翻訳すると

このミックスインを使用したら、ListCtrlにイメージリストを設定しないでください。

実際にやってみた

なんで設定しちゃダメか正直わからんかったので設定してみた。
以下、実装と結果


import pandas # csv操作ライブラリ
import configparser

import wx   # GUIライブラリ
import wx.lib.mixins.listctrl as listmix

import os

import menuEvent
import buttonEvent

import codecs

import glob
import numpy.random.common
import numpy.random.bounded_integers
import numpy.random.entropy
from wx import ImageFromStream, BitmapFromImage
import log

#-------------------------------------------------

#setting.ini読み込み    
config = configparser.ConfigParser()
config.read(R"..\setting.ini",encoding="utf-8")

# Header設定
header = (
            u"選択",\
            u"商品ID",\
            u"処理ステータス",\
            u"画像",\
            u"商品名",\
            u"取引状況",\
            u"出品日付",\
            u"出品時間",\
            u"在庫数"
        )

#-------------------------------------------------

class TestListCtrl(wx.ListCtrl, listmix.CheckListCtrlMixin, listmix.ListCtrlAutoWidthMixin):
    def __init__(self, panel, style):

        # wx.ListCtrl.__init__(self, *args, **kwargs)
        wx.ListCtrl.__init__(self, panel, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER,size=wx.Size(395, 467), pos=wx.Point(10, 20))
        listmix.CheckListCtrlMixin.__init__(self)
        listmix.ListCtrlAutoWidthMixin.__init__(self)

    def OnCheckItem(self, index, flag):
        print(index,flag)

class MainWindow(wx.Frame):
    def __init__(self, *args, **kwargs):

        wx.Frame.__init__(self, None ,wx.ID_ANY, 'test', size=(1000,500))
        self.panel = wx.Panel(self)

        self.list = TestListCtrl(self.panel, style=wx.LC_REPORT)

        # ListのHeader設定
        index = 0
        for head in header:
            if head == "選択":
                # チェックボックスのHeaderは中央寄せのサイズ70にする
                self.list.InsertColumn(index, head, wx.LIST_FORMAT_CENTER,70)
            else:
                self.list.InsertColumn(index, head, wx.LIST_FORMAT_LEFT,120)
            index += 1

#-------------追加--------------------------------------------------------
        self.imageList = wx.ImageList(64,64,wx.IMAGE_LIST_SMALL)        
        self.list.SetImageList(self.imageList,wx.IMAGE_LIST_SMALL)
#-------------ここまで----------------------------------------------------

        # csvからデータを読みこんで設定
        # 無し場合は空で画面表示
        master_path = config.get("path","output_csv_path")        
        if os.path.exists(master_path):
            with codecs.open(master_path,'r',encoding='cp932',errors="ignore") as csv_file:
                excel = pandas.read_csv(csv_file)
                # 1行を作成
                test = 0                
                for excel_data in excel.values:   
                    self.list.Append([
                            "",                                                     # スペース入れないと、チェックボックスのカラムに文字列が入る
                            "" if "nan" == str(excel_data[1]) else excel_data[1],   # 商品ID
                            "",                                                     # 処理ステータス
                            "",                                                     # 画像
                            excel_data[2],                                          # 商品名
                            "未出品" if "nan" == str(excel_data[19]) else excel_data[19], # 取引状況
                            "" if "nan" == str(excel_data[16]) else excel_data[16], # 出品日時
                            "" if "nan" == str(excel_data[17]) else excel_data[17], # 出品時間
                            "" if "nan" == str(excel_data[18]) else excel_data[18], # 在庫数
                    ]) 

#-------------追加----------------------------------------------------
                    if str(excel_data[15]) != "nan" and len(glob.glob(excel_data[15]+"/*")) > 0:
                        imageidx = self.imageList.Add(wx.Icon(glob.glob(excel_data[15]+"/*")[0], wx.BITMAP_TYPE_ANY)) 
                        self.list.SetItemColumnImage(test,3,imageidx)

                    test += 1                    
#-------------ここまで----------------------------------------------------
        # パネルにセット
        self.sizer = wx.BoxSizer(wx.VERTICAL) # メインのBox
        self.sizer.Add(self.list, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        self.panel.SetSizerAndFit(self.sizer)
        self.Show()

if __name__ == "__main__":
    app = wx.App(False)
    win = MainWindow(None)
    app.MainLoop()

上記実装で実行した結果が以下になる

画像を指定の場所に表示することには成功したが、チェックボックス部分にも画像が表示される。
しかもクリックすると別の画像に変わる。

ダメな理由はこれ...?

実装方法を調査してみた

この時点で製造も後半だったし、作り直すのはめんどくさい。
画像を設定する方法を調べたところ、同じ悩みを持っている方がいた。
そこではチェックボックスの画像を上書きすればよいとのこと。
参考

実装

上記のことをふまえた実装が以下


import pandas # csv操作ライブラリ
import configparser

import wx   # GUIライブラリ
import wx.lib.mixins.listctrl as listmix

import os

import menuEvent
import buttonEvent

import codecs

import glob
import numpy.random.common
import numpy.random.bounded_integers
import numpy.random.entropy
from wx import ImageFromStream, BitmapFromImage
import log

#-------------------------------------------------

#setting.ini読み込み    
config = configparser.ConfigParser()
config.read(R"..\setting.ini",encoding="utf-8")

# Header設定
header = (
            u"選択",\
            u"商品ID",\
            u"処理ステータス",\
            u"画像",\
            u"商品名",\
            u"取引状況",\
            u"出品日付",\
            u"出品時間",\
            u"在庫数"
        )

#-------------------------------------------------

class TestListCtrl(wx.ListCtrl, listmix.CheckListCtrlMixin, listmix.ListCtrlAutoWidthMixin):
    def __init__(self, panel, style):

        # wx.ListCtrl.__init__(self, *args, **kwargs)
        wx.ListCtrl.__init__(self, panel, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER,size=wx.Size(395, 467), pos=wx.Point(10, 20))
        listmix.CheckListCtrlMixin.__init__(self)
        listmix.ListCtrlAutoWidthMixin.__init__(self)

    def OnCheckItem(self, index, flag):
        print(index,flag)

class MainWindow(wx.Frame):
    def __init__(self, *args, **kwargs):

        wx.Frame.__init__(self, None ,wx.ID_ANY, 'test', size=(1000,500))
        self.panel = wx.Panel(self)

        self.list = TestListCtrl(self.panel, style=wx.LC_REPORT)

        # ListのHeader設定
        index = 0
        for head in header:
            if head == "選択":
                # チェックボックスのHeaderは中央寄せのサイズ70にする
                self.list.InsertColumn(index, head, wx.LIST_FORMAT_CENTER,70)
            else:
                self.list.InsertColumn(index, head, wx.LIST_FORMAT_LEFT,120)
            index += 1

#-------------追加----------------------------------------------------
        self.imageList = wx.ImageList(64,64,wx.IMAGE_LIST_SMALL)        
        self.list.SetImageList(self.imageList,wx.IMAGE_LIST_SMALL)

        self.list.SetImageList(self.imageList,wx.IMAGE_LIST_SMALL)
        # self.list.AssignImageList(self.imageList, wx.IMAGE_LIST_SMALL)

        self.imageList.Add(wx.Icon(R"..\icon\un_check.png", wx.BITMAP_TYPE_ANY)) 
        self.imageList.Add(wx.Icon(R"..\icon\checked.png", wx.BITMAP_TYPE_ANY)) 
#-------------ここまで----------------------------------------------------

        # csvからデータを読みこんで設定
        # 無し場合は空で画面表示
        master_path = config.get("path","output_csv_path")        
        if os.path.exists(master_path):
            with codecs.open(master_path,'r',encoding='cp932',errors="ignore") as csv_file:
                excel = pandas.read_csv(csv_file)
                # 1行を作成
                test = 0                
                for excel_data in excel.values:   
                    self.list.Append([
                            "",                                                     # スペース入れないと、チェックボックスのカラムに文字列が入る
                            "" if "nan" == str(excel_data[1]) else excel_data[1],   # 商品ID
                            "",                                                     # 処理ステータス
                            "",                                                     # 画像
                            excel_data[2],                                          # 商品名
                            "未出品" if "nan" == str(excel_data[19]) else excel_data[19], # 取引状況
                            "" if "nan" == str(excel_data[16]) else excel_data[16], # 出品日時
                            "" if "nan" == str(excel_data[17]) else excel_data[17], # 出品時間
                            "" if "nan" == str(excel_data[18]) else excel_data[18], # 在庫数
                    ]) 

#-------------追加----------------------------------------------------
                    if str(excel_data[15]) != "nan" and len(glob.glob(excel_data[15]+"/*")) > 0:
                        imageidx = self.imageList.Add(wx.Icon(glob.glob(excel_data[15]+"/*")[0], wx.BITMAP_TYPE_ANY)) 
                        self.list.SetItemColumnImage(test,3,imageidx)

                    test += 1
#-------------ここまで----------------------------------------------------

        # パネルにセット
        self.sizer = wx.BoxSizer(wx.VERTICAL) # メインのBox
        self.sizer.Add(self.list, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        self.panel.SetSizerAndFit(self.sizer)
        self.Show()

if __name__ == "__main__":
    app = wx.App(False)
    win = MainWindow(None)
    app.MainLoop()

解説

メイン部分は以前の記事で解説したので追加部分のみ記載する

        self.imageList = wx.ImageList(64,64,wx.IMAGE_LIST_SMALL)        
        self.list.SetImageList(self.imageList,wx.IMAGE_LIST_SMALL)

        self.list.SetImageList(self.imageList,wx.IMAGE_LIST_SMALL)
        # self.list.AssignImageList(self.imageList, wx.IMAGE_LIST_SMALL)

        self.imageList.Add(wx.Icon(R"..\icon\un_check.png", wx.BITMAP_TYPE_ANY)) 
        self.imageList.Add(wx.Icon(R"..\icon\checked.png", wx.BITMAP_TYPE_ANY)) 

今回の肝の部分。
通常通りimageListを初期化し画像をAddしている。
ここでチェックボックスの画像をAddすることで上書きができる。
un_check.png、checked.pngの画像は以下のような感じ。

※注意点
チェックボックスは画像サイズを16×16で表中に表示する画像は64×64にすることはできなかった。(やり方が悪かったのかもしれないが)
そのため、余白無しのチェックボックスの画像をそのままAddすると表の枠一杯にチェックボックスが表示される。
それだとでかすぎるため、64×64にリサイズした時にちょうど良いサイズになるまで余白を追加した。

 if str(excel_data[15]) != "nan" and len(glob.glob(excel_data[15]+"/*")) > 0:
     imageidx = self.imageList.Add(wx.Icon(glob.glob(excel_data[15]+"/*")[0], wx.BITMAP_TYPE_ANY)) 
     self.list.SetItemColumnImage(test,3,imageidx)

ここはcsvから画像フォルダのパスを取得し、最初の画像をCtrlListの任意の場所に設定しているだけ。

まとめ

以上、CheckListCtrlMixinを使用しつつも画像を設定するやり方でした。

このやり方が正しいかはわからない。
そもそも公式で使用しないでください。と記載があるため正しくはないか...





単純作業にお悩みではありませんか?

何百とあるワードを検索してファイルにまとめたり 数ある商品情報から条件にあるものだけ目で探してリ...

その単純作業プログラムで解決できるかもしれません。 もしよろしければ単純作業からの解放をお手伝いさせてください。

詳しくは以下のページからDM、または見積もり相談お願い致します。

お仕事依頼 ・ 見積もり依頼

adsense




-Python, wxpython

Copyright© YRen-LaB , 2021 AllRights Reserved Powered by AFFINGER4.