質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

1回答

955閲覧

QAbstractItemModel キーイベントの書き方 Python

goki_gottan

総合スコア168

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2022/08/09 09:05

以下コードのQAbstractItemModelの構造ですと、キーイベントやクローズイベントをどこに入れても動作しません。
正しくキーイベントやクローズイベントを動作させるためにはどこに挿入したら良いのでしょうか。

import pandas as pd from PyQt5 import QtWidgets, QtCore import sys,glob,os,threading from PyQt5.QtWidgets import QApplication,QDialog from PyQt5.QtCore import Qt import pyperclip from PyQt5.QtWidgets import QMainWindow, QWidget, QAction, QTableWidget,QTableWidgetItem,QVBoxLayout,QCheckBox,QHBoxLayout,QPushButton,QLabel,QLineEdit,QGridLayout,QProgressBar from PyQt5.QtGui import QPixmap,QFont import sqlite3 from PyQt5.QtWidgets import QMessageBox,QListWidget #テーブル名 z1=〇#データベース conn = sqlite3.connect(z1) c = conn.cursor() sql = "SELECT * FROM " + table_ +";" df=pd.read_sql(sql,conn) class PandasModel(QtCore.QAbstractItemModel): def __init__(self, parent=None, data_frame=None): super(PandasModel, self).__init__(parent) self.df = data_frame def closeEvent(self,event): global conn,app # conn.close() self.close() QtWidgets.QApplication.quit() def columnCount(self, parent=QtCore.QModelIndex()): return self.df.shape[1] def data(self, index, role=QtCore.Qt.DisplayRole): if not index.isValid(): return QtCore.QVariant() if role == QtCore.Qt.EditRole or role == QtCore.Qt.DisplayRole: return self.df.iat[index.row(), index.column()] return QtCore.QVariant() def flags(self, index): return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole): if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole: return self.df.columns[section] if orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole: return self.df.index[section] def index(self, row, column, parent=QtCore.QModelIndex()): if not self.hasIndex(row, column, parent): return QtCore.QModelIndex() return self.createIndex(row, column, QtCore.QModelIndex()) def insertColumns(self, column, count, parent=QtCore.QModelIndex()): self.beginInsertColumns(parent, column, column + count - 1) columns = [ str(self.columnCount()+i+1) for i in range(count) ] left = self.df.iloc[:, 0:column] mid = pd.DataFrame(index=self.df.index, columns=columns) right = self.df.iloc[:, column+count-1:self.columnCount()] self.df = pd.concat( [left, mid, right], axis=1 ) self.endInsertColumns() def insertRows(self, row, count, parent=QtCore.QModelIndex()): self.beginInsertRows(parent, row, row + count - 1) indexes = [ str(self.rowCount()+i) for i in range(count) ] left = self.df[0:row] mid = pd.DataFrame(index=indexes, columns=self.df.columns) right = self.df[row+count-1:self.rowCount()] self.df = pd.concat([left, mid, right]) self.endInsertRows() def removeColumns(self, column, count, parent=QtCore.QModelIndex()): self.beginRemoveColumns(parent, column, column + count - 1) left = self.df.iloc[:, 0:column] right = self.df.iloc[:, column+count:self.columnCount()] self.df = pd.concat( [left, right], axis=1 ) self.endRemoveColumns() def removeRows(self, row, count, parent=QtCore.QModelIndex()): self.beginRemoveRows(parent, row, row + count - 1) left = self.df.iloc[0:row] right = self.df.iloc[row+count:self.rowCount()] self.df = pd.concat( [left, right], axis=0 ) self.endRemoveRows() def rowCount(self, parent=QtCore.QModelIndex()): return self.df.shape[0] def setData(self, index, value, role=QtCore.Qt.EditRole): if role == QtCore.Qt.EditRole: self.df.iat[index.row(), index.column()] = value return True return False def closeEvent(self,event): global conn,app print("t4") # conn.close() self.close() QtWidgets.QApplication.quit() class Delegate(QtWidgets.QStyledItemDelegate): def __init__(self, parent=None, setModelDataEvent=None): super(Delegate, self).__init__(parent) self.setModelDataEvent = setModelDataEvent def createEditor(self, parent, option, index): index.model().data(index, QtCore.Qt.DisplayRole) return QtWidgets.QLineEdit(parent) def setEditorData(self, editor, index): value = index.model().data(index, QtCore.Qt.DisplayRole) editor.setText(str(value)) def setModelData(self, editor, model, index): model.setData(index, editor.text()) if not self.setModelDataEvent is None: self.setModelDataEvent() def closeEvent(self,event): global conn,app print("t3") # conn.close() self.close() QtWidgets.QApplication.quit() def main(): def insert_row(): if len(tableView.selectedIndexes()) == 0: model.insertRows(model.rowCount(), 1) else: rows = list( set([ index.row() for index in tableView.selectedIndexes() ]) ) for row in rows[::-1]: model.insertRows(row, 1) def delete_row(): rows = list( set([ index.row() for index in tableView.selectedIndexes() ]) ) for row in rows[::-1]: model.removeRows(row, 1) def insert_column(): if len(tableView.selectedIndexes()) == 0: model.insertColumns(model.columnCount(), 1) else: columns = list( set([ index.column() for index in tableView.selectedIndexes() ]) ) for column in columns[::-1]: model.insertColumns(column, 1) def delete_column(): columns = list( set([ index.column() for index in tableView.selectedIndexes() ]) ) for column in columns[::-1]: model.removeColumns(column, 1) def exec_context_menu(point): menu = QtWidgets.QMenu(tableView) menu.addAction('Insert row', insert_row) menu.addAction('Delete row', delete_row) menu.addAction('Insert column', insert_column) menu.addAction('Delete column', delete_column) menu.exec( tableView.focusWidget().mapToGlobal(point) ) def closeEvent(self,event): global conn,app print("t1") # conn.close() self.close() QtWidgets.QApplication.quit() def keyPressEvent(self, event): # print(event.key()) current_index = self.view.currentIndex() row = current_index.row() column = current_index.column() key = event.key() modifiers = event.modifiers() print(row) app = QtWidgets.QApplication(sys.argv) window = QtWidgets.QMainWindow() window.resize(600, 600) centralwidget = QtWidgets.QWidget(window) verticalLayout = QtWidgets.QVBoxLayout(centralwidget) tableView = QtWidgets.QTableView(centralwidget) model = PandasModel(tableView, df) tableView.setModel(model) tableView.setItemDelegate(Delegate()) tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) tableView.customContextMenuRequested.connect(exec_context_menu) verticalLayout.addWidget(tableView) window.setCentralWidget(centralwidget) window.show() app.exec() if __name__ == '__main__': main()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

Model-View では、ユーザー入力イベントを受けるのは Model ではなく View の役割です。

View のサブクラスを作成するのが順当な実装方法ですが、
選択肢としては他に、「ショートカットキー」や、イベントと関数を結びつける「シグナル・スロット」、
アプリケーション全体のイベントを所得する「イベントフィルター」といった方法もあります。(用途次第)


問題点
質問に掲載のコードの問題点は、実装が main関数内のローカルな関数となっているので、
そもそもイベントメソッドのオーバーライドになってません。

これらの xxxEvent 型のメソッドをオーバーライドしたい場合は、
必ずウィジェット系クラスのサブクラスを作成します。
(Modelは内部のデータ部分で、GUIの実態を持ちません。表示部分はViewが担います)

どの実装方法が適しているかは、以下の順に検討してみてください

  • A 簡単なショートカット・キー用途なら QShortcut の利用を検討
  • B 関数として実装して、イベントと結びつけたい場合はシグナル・スロット
  • C より柔軟なキー入力制御が必要な場合は、QTableView をサブクラス化して

 keyPressEvent 等のキー入力関連のメソッドをオーバーライド

  • D アプリケーション全体のキー入力をまとめて扱いたい場合は

 イベントフィルター (検索用ヒント installEventFilter)

大抵の場合は、C と B を組み合わせた方法を取ります。
手順は手短に、サブクラスを作成し、xxxEvent 系メソッドをオーバーライド。
xxxEvent 系メソッドないで独自シグナルを発呼。シグナルをスロットやユーザー定義関数へ接続。

投稿2022/08/14 04:41

teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問