Skip to content

Instantly share code, notes, and snippets.

@mdmitry1
Last active February 5, 2023 18:45
Show Gist options
  • Save mdmitry1/ec4f06e2809a6a9f0a34a8048d7c171c to your computer and use it in GitHub Desktop.
Save mdmitry1/ec4f06e2809a6a9f0a34a8048d7c171c to your computer and use it in GitHub Desktop.
#!/usr/bin/python3.11
'''
https://www.pythonguis.com/tutorials/qtableview-modelviews-numpy-pandas/
'''
from sys import argv, exit
from rich import print as rprint
from pandas import read_csv
from os import name as osname, popen
from os.path import realpath, basename, splitext, split
from re import sub
from argparse import ArgumentParser
from PyQt5.QtWidgets import QMainWindow, QApplication, QTableView, QHeaderView, QStyledItemDelegate, QStyle
from PyQt5.QtCore import Qt, QAbstractTableModel
from PyQt5.QtGui import QBrush, QColor, QPen
if 'nt' == osname: import ctypes
def get_screen_resolution():
if 'nt' == osname:
user32 = ctypes.windll.user32
return user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)
else:
raw_string=popen("xdpyinfo | grep dimensions | cut -d':' -f2 | awk '{print $1}'").read()
resolution_string=raw_string.rstrip(raw_string[-1])
xstr, ystr = resolution_string.split('x')
return int(xstr), int(ystr)
class TableModel(QAbstractTableModel):
def __init__(self, data):
super(TableModel, self).__init__()
self._data = data
def data(self, index, role):
if role == Qt.DisplayRole: return str(self._data.iloc[index.row(), index.column()])
def rowCount(self, index): return self._data.shape[0]
def columnCount(self, index): return self._data.shape[1]
def headerData(self, section, orientation, role):
# section is the index of the column/row.
if role == Qt.DisplayRole: return str(self._data.columns[section]) if orientation == Qt.Horizontal \
else str(self._data.index[section]+1)
class CustomDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super().__init__(parent)
def paint(self, painter, option, index):
if option.state & QStyle.State_HasFocus: painter.fillRect(option.rect, QBrush(QColor(210, 180, 140)))
else: painter.fillRect(option.rect, QBrush(QColor(0, 140, 0)))
pen = QPen(QColor("#ffffd7"), 2)
painter.setPen(pen)
painter.drawRect(option.rect)
super().paint(painter, option, index)
class MainWindow(QMainWindow):
def __init__(self,args, script_name):
super().__init__()
self.table = QTableView()
style='font-size: 16px; \
background-color: lightgrey; \
gridline-color: DarkViolet; \
selection-background-color: blue'
if 'nt' == osname: style=sub("16px","20px",style)
self.table.setStyleSheet(style)
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.setWindowTitle(splitext(script_name)[0])
try:
self.df = read_csv(args.file,sep=args.separator) \
if args.header else read_csv(args.file,sep=args.separator,header=None)
except Exception as err:
rprint("\n[magenta] " + script_name + ":", "[red] ERROR: [/red]", "[red] " + str(err), "\n")
exit(1)
self.model = TableModel(self.df)
self.table.setModel(self.model)
self.table.setShowGrid(True)
self.table.setGridStyle(Qt.SolidLine)
self.setCentralWidget(self.table)
self.table.doubleClicked.connect(self.table_view_doubleClicked)
delegate = CustomDelegate()
self.table.setItemDelegate(delegate)
header = self.table.horizontalHeader()
table_width=0
for col in range(0, self.df.shape[1]):
table_width += header.sectionSize(col)
table_height = self.table.verticalHeader().sectionSize(0)*self.df.shape[0]
screen_w, screen_h = get_screen_resolution()
self.resize(min(screen_w-100,table_width+50),min(screen_h-100,table_height+50))
selection_model=self.table.selectionModel()
selection_model.selectionChanged.connect(self.on_selection_changed)
def on_selection_changed(self, index):
print("Selection has been changed")
def table_view_doubleClicked(self, index):
row = index.row()
column = index.column()
value=self.df.iloc[row,column]
print(f"Row: {row+1}, Column: {column+1}, value = {value}")
def main():
parser = ArgumentParser()
parser.add_argument('--file', '-f', default="/dev/stdin")
parser.add_argument('--header', '-hdr', default=None, action='store_true')
parser.add_argument('--separator', '-s', default='\s+')
args=parser.parse_args()
app=QApplication(argv)
window=MainWindow(args, basename(realpath(argv[0])))
window.show()
exit(app.exec_())
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment