Created
December 23, 2016 17:11
-
-
Save pashango2/c548c28525c630f124da835648062f5d to your computer and use it in GitHub Desktop.
汎用検索オブジェクト
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! usr/bin/python | |
# -*- coding: utf-8 -*- | |
from __future__ import unicode_literals, print_function, absolute_import | |
""" | |
# 汎用検索オブジェクト | |
QAbstractItemViewに対して付加可能な検索オブジェクト。 | |
ツリー型モデルとテーブル型の両対応をしている。 | |
# 使い方 | |
``` | |
import sys | |
app = QApplication(sys.argv) | |
widget = QWidget() | |
layout = QVBoxLayout(widget) | |
line_edit = QLineEdit(widget) | |
table_view = QTableView(widget) | |
layout.addWidget(line_edit) | |
layout.addWidget(table_view) | |
table_model = QStandardItemModel(3, 3) | |
table_model.setItem(0, 0, QStandardItem("りんご")) | |
table_model.setItem(0, 1, QStandardItem("\\100")) | |
table_model.setItem(1, 0, QStandardItem("バナナ")) | |
table_model.setItem(1, 1, QStandardItem("\\100")) | |
table_model.setItem(2, 0, QStandardItem("メロン")) | |
table_model.setItem(2, 1, QStandardItem("\\100")) | |
table_view.setModel(table_model) | |
finder_obj = FinderObject(table_model, table_view, widget) | |
line_edit.textChanged.connect(finder_obj.find) | |
line_edit.returnPressed.connect(finder_obj.findNext) | |
finder_obj.indexFound.connect(table_view.setCurrentIndex) | |
next_act = finder_obj.createFindNextAction("次へ", widget) | |
prev_act = finder_obj.createFindPreviousAction("前へ", widget) | |
widget.addActions([next_act, prev_act]) | |
widget.show() | |
app.exec_() | |
``` | |
""" | |
from PySide.QtCore import * | |
from PySide.QtGui import * | |
class FinderObject(QObject): | |
indexFound = Signal(QModelIndex) | |
def __init__(self, model, view, parent=None): | |
""" | |
:type view: QAbstractItemView | |
:type parent: QObject or None | |
:type model: QAbstractItemModel | |
""" | |
super(FinderObject, self).__init__(parent) | |
self.model = model | |
self.view = view | |
self._cmp_func = self._default_cmp | |
self._find_str = "" | |
self._current_index = QModelIndex() | |
self.find_role = Qt.DisplayRole | |
def _default_cmp(self, find_str, index): | |
""" 標準の比較関数 | |
:type find_str: str or unicode | |
:type index: QModelIndex | |
""" | |
data = index.data(self.find_role) | |
return data and find_str.lower() in data.lower() | |
def next_index(self, index=QModelIndex()): | |
""" 次のQModelIndexを求める | |
:rtype: QModelIndex | |
:type index: QModelIndex | |
""" | |
if index.isValid(): | |
_index = index.child(0, 0) | |
if not _index.isValid(): | |
_index = index.sibling(index.row(), index.column() + 1) | |
if not _index.isValid(): | |
_index = index.sibling(index.row() + 1, 0) | |
if not _index.isValid(): | |
_index = index.parent() | |
_index = _index.sibling(_index.row() + 1, 0) | |
if not _index.isValid(): | |
_index = self.model.index(0, 0) | |
return _index | |
else: | |
return self.model.index(0, 0) | |
def _last_index(self, index=QModelIndex()): | |
""" 最後の葉のQModelIndexを求める | |
:type index: QModelIndex | |
""" | |
while self.model.rowCount(index) > 1: | |
index = self.model.index(self.model.rowCount(index) - 1, 0, index) | |
index = index.sibling(index.row(), self.model.columnCount(index.parent()) - 1) | |
return index | |
def prev_index(self, index=QModelIndex()): | |
""" 前のQModelIndexを求める | |
:rtype: QModelIndex | |
:type index: QModelIndex | |
""" | |
if index.isValid(): | |
_index = index.sibling(index.row(), index.column() - 1) | |
if not _index.isValid(): | |
_index = index.sibling(index.row() - 1, 0) | |
if _index.isValid(): | |
_index = self._last_index(_index) | |
if _index.isValid(): | |
_index = _index.sibling(_index.row(), self.model.columnCount(_index.parent()) - 1) | |
if not _index.isValid(): | |
_index = index.parent() | |
if not _index.isValid(): | |
_index = self._last_index() | |
return _index | |
else: | |
return self._last_index() | |
@Slot(str) | |
def find(self, find_str): | |
""" 検索 | |
:type find_str: str or unicode | |
""" | |
self._find_str = find_str | |
current_index = self.view.currentIndex() | |
if not current_index.isValid() or not self._cmp_func(find_str, current_index): | |
self._find() | |
def _find(self, forward=True): | |
""" 検索(内部関数) | |
:type forward: bool | |
""" | |
if not self._find_str: | |
return | |
index = self.view.currentIndex() | |
index = stop_index = self.next_index(index) if forward else self.prev_index(index) | |
while True: | |
if self._cmp_func(self._find_str, index): | |
self.indexFound.emit(index) | |
break | |
index = self.next_index(index) if forward else self.prev_index(index) | |
if index == stop_index: | |
break | |
@Slot() | |
def findNext(self): | |
""" 次を探索 """ | |
self._find() | |
@Slot() | |
def findPrevious(self): | |
""" 前を探索 """ | |
self._find(forward=False) | |
def createFindNextAction(self, text, parent=None): | |
""" | |
:type parent: QWidget | |
:type text: str | |
""" | |
act = QAction(text, parent, triggered=self.findNext) | |
act.setShortcut(QKeySequence.FindNext) | |
return act | |
def createFindPreviousAction(self, text, parent=None): | |
""" | |
:type parent: QWidget | |
:type text: str | |
""" | |
act = QAction(text, parent, triggered=self.findPrevious) | |
act.setShortcut(QKeySequence.FindPrevious) | |
return act |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment