PySide(Qt)でタブを使って、好きなだけタブを増やせるようなツールを作っている時に、、、
追加ボタン欲しい
(゚A゚;)ゴクリ
なんて思いませんか?
メニューからタブの追加とか、別途離れた場所に追加ボタンを作るなら簡単ですが、Tabと一体感がなくてイマイチ、、、
できれば、MayaのScript Editorとかにある感じで、Tabを追加できるボタンを作りたい!
そんな方法をご紹介したいと思います∠( ゚д゚)/
クラスの作成
まずは、QTabWidgetを継承した「TabWidget」のクラスから用意したいと思います!
class TabWidget(QtGui.QTabWidget): def __init__(self, *args, **kwargs): super(TabWidget, self).__init__(*args, **kwargs)
インスタンス作成時の引数は色々あるので「*args, **kwargs」で受け取って、そのまま基底クラスにぶん投げてしまいます。
タブの追加
次は、初期のタブと、タブ追加の「+」のタブを設定します。サンプルのコードですので、QWidgetのインスタンスをそのまま入れています。必要に応じて変更してください。
from PySide import QtGui class TabWidget(QtGui.QTabWidget): def __init__(self, *args, **kwargs): super(TabWidget, self).__init__(*args, **kwargs) self.insertTab(0, QtGui.QWidget(), 'Tab1') self.insertTab(1, QtGui.QWidget(), '+')
タブ追加の実装
from PySide import QtGui class TabWidget(QtGui.QTabWidget): def __init__(self, *args, **kwargs): super(TabWidget, self).__init__(*args, **kwargs) self.insertTab(0, QtGui.QWidget(), 'Tab1') self.insertTab(1, QtGui.QWidget(), '+') def __addTab(self, index): if index != self.count()-1: return newTabName, status = QtGui.QInputDialog.getText( self, 'Add New Tab', 'Specify new tab name', QtGui.QLineEdit.Normal, 'Tab%d' % (index+1) ) if not status: return self.insertTab(index, QtGui.QWidget(), newTabName) self.setCurrentIndex(index)
どの位置にタブを追加するか受け取れるように引数「index」を設けました。次のステップで、Signal「currentChanged」と接続することを想定しており、変更したタブのIndexを引数で渡してきます。
まず、タブの「+」は常に最後尾にありますので、タブの総数を調べて、Indexと比較します。最後尾のタブ出ない場合は、表示の切り替えなのでreturnして終了します(゚∀゚)v
次に、「QtGui.QInputDialog.getText」を使い、ユーザーに新しいタブの名前を決めてもらいます。このメソッドは、新しい名前と、キャンセルされたかどうか同時に返します。もし、変数「status」がnotの場合は、ユーザーがキャンセルした場合なので、新しいタブは作成せずにreturnして終了します(*´ω`*)b
新しい名前が決まったところで、「insertTab」を使ってタブを追加します。この時、「+」のタブは後ろにずれて上書きされるわけではありません。
タブを作成したら、ユーザーが作業しやすいように「作成したタブ」に切り替えます∠( ゚д゚)/
シグナルの設定
このままでは、「+」のタブをクリックしても反応しませんので、Signal & Slotの設定を「__init__」に追加します。
from PySide import QtGui class TabWidget(QtGui.QTabWidget): def __init__(self, *args, **kwargs): super(TabWidget, self).__init__(*args, **kwargs) self.insertTab(0, QtGui.QWidget(), 'Tab1') self.insertTab(1, QtGui.QWidget(), '+') self.currentChanged.connect(self.__addTab) def __addTab(self, index): if index != self.count()-1: return newTabName, status = QtGui.QInputDialog.getText( self, 'Add New Tab', 'Specify new tab name', QtGui.QLineEdit.Normal, 'Tab%d' % (index+1) ) if not status: self.setCurrentIndex(self.__preIndex) return self.insertTab(index, QtGui.QWidget(), newTabName) self.setCurrentIndex(index)
タブを変更したら、どのタブに変更したかにかかわらず実行されます。その為に「__addTab」の冒頭でどのタブに変更されたか調べて処理をするようにいたしました。
キャンセルの対応
この状態で実行してみると、タブ追加の際にキャンセルすると「+」のタブに切り替わったまま放置されて、ユーザーがバグったように感じてしまいます。
タブ追加をキャンセルしたら、タブの変更をなかったことにするために、事前のタブの位置を記憶させておく必要があります。
インスタンス変数「__preIndex」を追加して対応していきます。
from PySide import QtGui class TabWidget(QtGui.QTabWidget): def __init__(self, *args, **kwargs): super(TabWidget, self).__init__(*args, **kwargs) self.insertTab(0, QtGui.QWidget(), 'Tab1') self.insertTab(1, QtGui.QWidget(), '+') self.currentChanged.connect(self.__addTab) self.__preIndex = 0 def __addTab(self, index): if index != self.count()-1: self.__preIndex = index return newTabName, status = QtGui.QInputDialog.getText( self, 'Add New Tab', 'Specify new tab name', QtGui.QLineEdit.Normal, 'Tab%d' % (index+1) ) if not status: self.setCurrentIndex(self.__preIndex) return self.insertTab(index, QtGui.QWidget(), newTabName) self.setCurrentIndex(index)
「__init__」で、まずインスタンス変数を初期化します。
「__addTab」では、「+」出なかった時に、タブのIndexを記憶します。もしタブ追加がキャンセルされた場合は、「setCurrentIndex」を使い、記憶しておいたIndexのタブに変更します!
これで、MayaライクなTabWidgetの出来上がりです!
しかし、、、
QTabWidgetにある機能と、相性が悪いです。。。
いずれも、MayaのScript Editorでは「タブの削除ボタン」「ドラッグでタブの並び替え」はできない機能ですので、よしとします!(ぁ