PySide: how to scale up images in QTableWidget? - python

I have problem with PySide QTableWidget. I need to add in first column of all rows image preview. I'm trying to add this using QIcon:
library_table.insertRow(index)
library_table.setItem(index, 1, QTableWidgetItem(file))
image = QIcon(self.sub_ad + file)
library_table.setItem(index, 0, QTableWidgetItem(image, ""))
But image is very small.
I was trying to use QSize, QPixmap etc. without any succes, size is still the same. How can I make this prev images bigger?

A simple solution is to establish a delegate where the icon is resized and set in the QTableWidget using the setItemDelegateForColumn() method:
from PySide import QtCore, QtGui
class IconDelegate(QtGui.QStyledItemDelegate):
def initStyleOption(self, option, index):
super(IconDelegate, self).initStyleOption(option, index)
option.decorationSize = option.rect.size()
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
table_widget = QtGui.QTableWidget()
self.setCentralWidget(table_widget)
table_widget.setColumnCount(2)
table_widget.verticalHeader().setDefaultSectionSize(80)
for index, file in enumerate(("clear.png", "butterfly.png")):
table_widget.insertRow(table_widget.rowCount())
item1 = QtGui.QTableWidgetItem(QtGui.QIcon(file), "")
item2 = QtGui.QTableWidgetItem(file)
table_widget.setItem(index, 0, item1)
table_widget.setItem(index, 1, item2)
delegate = IconDelegate(table_widget)
table_widget.setItemDelegateForColumn(0, delegate)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Related

Data will not save when using ComboBoxes inside QTableWidget

import sys
from PyQt6 import QtWidgets
from PyQt6.QtWidgets import QApplication, QItemDelegate, QWidget, QTableWidget, QTableWidgetItem, QPushButton, QHeaderView, QHBoxLayout, QVBoxLayout
from PyQt6.QtCore import Qt
import pandas as pd
class ComboBoxDelegate(QItemDelegate):
def __init__(self, parent=None):
super(ComboBoxDelegate, self).__init__(parent)
self.items = []
def setItems(self, items):
self.items = items
def createEditor(self, widget, option, index):
editor = QtWidgets.QComboBox(widget)
editor.addItems(self.items)
return editor
def setEditorData(self, editor, index):
value = index.model().data(index, Qt.ItemDataRole.EditRole)
if value:
editor.setCurrentText(str(value))
print("Data Changed")
def setModelData(self, editor, model, index):
model.setData(index, editor.currentIndex(), Qt.ItemDataRole.EditRole)
def updateEditorGeometry(self, editor, option, index):
editor.setGeometry(option.rect)
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.window_width, self.window_height = 700, 500
self.resize(self.window_width, self.window_height)
self.setWindowTitle('Load Excel (or CSV) data to QTableWidget')
layout = QVBoxLayout()
self.setLayout(layout)
self.table = QTableWidget()
layout.addWidget(self.table)
self.button = QPushButton('&Load Data')
self.button.clicked.connect(lambda _, xl_path=excel_file_path,: self.loadExcelData(xl_path))
layout.addWidget(self.button)
def loadExcelData(self, excel_file_dir):
df = pd.read_csv(excel_file_dir)
if df.size == 0:
return
df.fillna('', inplace=True)
self.table.setRowCount(df.shape[0])
self.table.setColumnCount(df.shape[1])
self.table.setHorizontalHeaderLabels(df.columns)
# returns pandas array object
for row in df.iterrows():
values = row[1]
for col_index, value in enumerate(values):
if isinstance(value, (float, int)):
value = '{0:0,.0f}'.format(value)
tableItem = QTableWidgetItem(str(value))
self.table.setItem(row[0], col_index, tableItem)
self.create_delegate(self.table)
self.table.setColumnWidth(2, 300)
def create_delegate(self, table):
test_del = ComboBoxDelegate()
test_list = ["Gravity Main", "Manhole", "Lateral"]
test_del.setItems(test_list)
table.setItemDelegateForColumn(0, test_del)
if __name__ == '__main__':
excel_file_path = "[Your CSV]"
app = QApplication(sys.argv)
app.setStyleSheet('''
QWidget {
font-size: 17px;
}
''')
myApp = MyApp()
myApp.show()
try:
sys.exit(app.exec())
except SystemExit:
print('Closing Window...')
Extension to previous question
Change the file directory to a random csv.
This populates the QTableWidget and does the same thing as my main program.
The QTableWidget does not save the changes.
My goal is to be able to populate multiple columns with different options based on the csv that is loaded. I had a working version but using QTableView instead of QTableWidget and I am working on transferring that progress.
The issue is caused by a code generation bug, according to the PyQt maintainer.
It should have been fixed in the following PyQt6 snapshots, so it's very likely that if you do a pip update you'll get the working version already, otherwise wait a couple of days and keep an eye on the changelog of the official site.

How to customize Qtreewidget item editor in PyQt5?

I am making a QtreeWidget with item editable,but the problem is with the Item Editor or QAbstractItemDelegate(might be called like this,not sure).I am unable to change the stylesheet,actually i dont know how to do this.And also i want the selected lines(blue in editor) should be according to my wish.like below picture
here i want that blue selected line upto ".jpg",so that anyone cant change that ".jpg". Only ,one can change upto this".jpg"
Here is my code:
import sys
from PyQt5 import QtCore, QtWidgets
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.button = QtWidgets.QPushButton('Edit')
self.button.clicked.connect(self.edittreeitem)
self.tree = QtWidgets.QTreeWidget()
self.tree.setStyleSheet('background:#333333;color:grey')
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tree)
layout.addWidget(self.button)
columns = 'ABCDE'
self.tree.setColumnCount(len(columns))
for index in range(50):
item=QtWidgets.QTreeWidgetItem(
self.tree, [f'{char}{index:02}.jpg' for char in columns])
item.setFlags(item.flags()|QtCore.Qt.ItemIsEditable)
def edittreeitem(self):
getSelected = self.tree.selectedItems()
self.tree.editItem(getSelected[0],0)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setWindowTitle('Test')
window.setGeometry(800, 100, 540, 300)
window.show()
sys.exit(app.exec_())
You can create your own delegate that only considers the base name without the extension, and then set the data using the existing extension.
class BaseNameDelegate(QtWidgets.QStyledItemDelegate):
def setEditorData(self, editor, index):
editor.setText(QtCore.QFileInfo(index.data()).completeBaseName())
def setModelData(self, editor, model, index):
name = editor.text()
if not name:
return
suffix = QtCore.QFileInfo(index.data()).suffix()
model.setData(index, '{}.{}'.format(name, suffix))
class Window(QtWidgets.QWidget):
def __init__(self):
# ...
self.tree.setItemDelegate(BaseNameDelegate(self.tree))
The only drawback of this is that the extension is not visible during editing, but that would require an implementation that is a bit more complex than that, as QLineEdit (the default editor for string values of a delegate) doesn't provide such behavior.

How to create a Drawer instance and attach it to MainWindow

I am struggling to add a side menu to my application.
I have a QMainWindow instance to which I was hoping to add a QDrawer object and achieve an effect similar to this sample.
Unfortunately, it seems that PySide2 only provides QMenu, QTooltip and QDialog widgets which inherit from the Popup class, and QDrawer is nowhere to be found. However, using a Drawer tag in a QML file works just fine. Shouldn't it be possible to also create an instance of QDrawer programmatically?
As another try, I tried to load a Drawer instance from a QML file and attach it to my QMainWindow. Unfortunately I can't quite understand what should I specify as parent, what should I wrap it in, what parameters should I use etc. - any advice would be appreciated (although I would much rather create and configure it programatically).
My goal is to create a QMainWindow with a toolbar, central widget and a QDrawer instance as a side navigation menu (such as in this sample). Can you please share some examples or explain what to do?
One possible solution is to implement a Drawer using Qt Widgets, the main feature is to animate the change of width for example using a QXAnimation, the other task is to set the anchors so that it occupies the necessary height. A simple example is the one shown in the following code:
import os
from PySide2 import QtCore, QtGui, QtWidgets
class Drawer(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedWidth(0)
self.setContentsMargins(0, 0, 0, 0)
# self.setFixedWidth(0)
self._maximum_width = 0
self._animation = QtCore.QPropertyAnimation(self, b"width")
self._animation.setStartValue(0)
self._animation.setDuration(1000)
self._animation.valueChanged.connect(self.setFixedWidth)
self.hide()
#property
def maximum_width(self):
return self._maximum_width
#maximum_width.setter
def maximum_width(self, w):
self._maximum_width = w
self._animation.setEndValue(self.maximum_width)
def open(self):
self._animation.setDirection(QtCore.QAbstractAnimation.Forward)
self._animation.start()
self.show()
def close(self):
self._animation.setDirection(QtCore.QAbstractAnimation.Backward)
self._animation.start()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowFlag(QtCore.Qt.FramelessWindowHint)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
self.tool_button = QtWidgets.QToolButton(
checkable=True, iconSize=QtCore.QSize(36, 36)
)
content_widget = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
content_widget.setText("Content")
content_widget.setStyleSheet("background-color: green")
lay = QtWidgets.QVBoxLayout(central_widget)
lay.setSpacing(0)
lay.setContentsMargins(0, 0, 0, 0)
lay.addWidget(self.tool_button)
lay.addWidget(content_widget)
self.resize(640, 480)
self.drawer = Drawer(self)
self.drawer.move(0, self.tool_button.sizeHint().height())
self.drawer.maximum_width = 200
self.drawer.raise_()
content_lay = QtWidgets.QVBoxLayout()
content_lay.setContentsMargins(0, 0, 0, 0)
label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
label.setText("Content\nDrawer")
label.setStyleSheet("background-color: red")
content_lay.addWidget(label)
self.drawer.setLayout(content_lay)
self.tool_button.toggled.connect(self.onToggled)
self.onToggled(self.tool_button.isChecked())
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.onCustomContextMenuRequested)
#QtCore.Slot()
def onCustomContextMenuRequested(self):
menu = QtWidgets.QMenu()
quit_action = menu.addAction(self.tr("Close"))
action = menu.exec_(QtGui.QCursor.pos())
if action == quit_action:
self.close()
#QtCore.Slot(bool)
def onToggled(self, checked):
if checked:
self.tool_button.setIcon(
self.style().standardIcon(QtWidgets.QStyle.SP_MediaStop)
)
self.drawer.open()
else:
self.tool_button.setIcon(
self.style().standardIcon(QtWidgets.QStyle.SP_MediaPlay)
)
self.drawer.close()
def resizeEvent(self, event):
self.drawer.setFixedHeight(self.height() - self.drawer.pos().y())
super().resizeEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

How to convert QLabel to QTableWidgetItem to put into QTableWidget

I want to add an icon to my QTableWidget. However, the icon being added is pretty small, so I try to find a way to resize the icon
I have tried using setSizeHint(), but it didn't work. So I thought of creating a pixmap and set the pixmap in QLabel, but I couldn't figure out to convert the QLabel into QTabelWidgetItem.
this is the code in two different approaches
##this is when I try to use setSizeHint()
class test_UI(Ui_MainWindow,QtWidgets.QMainWindow)
def set_icon(self):
icon_item=QtWidgets.QTableWidgetItem()
icon_item.setSizeHint(QtCore.QSize(100,100))
icon_item.setIcon(QtGui.QIcon("Kevin_test.png"))
self.tableWidget.setItem(0,1,icon_item)
##this is when I try to use pixmap to put it inside the table
class test_UI(Ui.MainWindow,QtWidgets.QMainWindow)
def set_icon(self):
icon_item=QtWidgets.QTableWidgetItem(self.label)
icon_item.setFlags(QtCore.Qt.ItemIsEditable)
self.tableWidget.setItem(0,1,icon_item)
def build_icon(self):
self.icon = QtGui.QIcon("Kevin_test.png")
self.label=QtWidgets.QLabel('pic',self)
self.label.setFixedSize(300,300)
pixmap1=self.icon.pixmap(100,100,QtGui.QIcon.Active,QtGui.QIcon.On)
self.label.setPixmap(pixmap1)
For the first approach, I expect the size of the icon to change but it did not.
For the second approach, my program crash because there is no overload call to make QTableWidgetItem with a QLabel.
There are at least the following methods:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Delegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
option.decorationSize = index.data(QtCore.Qt.SizeHintRole)
def main(args):
app = QtWidgets.QApplication(args)
# sol1
widget_1 = QtWidgets.QTableWidget(1, 1)
it1 = QtWidgets.QTableWidgetItem()
widget_1.setItem(0, 0, it1)
it1.setIcon(QtGui.QIcon("so-logo.png"))
it1.setSizeHint(QtCore.QSize(100, 100))
widget_1.setIconSize(QtCore.QSize(100, 100))
# sol2
widget_2 = QtWidgets.QTableWidget(1, 1)
it2 = QtWidgets.QTableWidgetItem()
widget_2.setItem(0, 0, it2)
label = QtWidgets.QLabel()
pixmap = QtGui.QPixmap("so-logo.png")
""" scaled
pixmap = pixmap.scaled(
QtCore.QSize(400, 400),
QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation,
)"""
size = pixmap.size()
label.setPixmap(pixmap)
it2.setSizeHint(size)
label.setFixedSize(size)
widget_2.setCellWidget(0, 0, label)
# sol3
widget_3 = QtWidgets.QTableWidget(1, 1)
it3 = QtWidgets.QTableWidgetItem()
widget_3.setItem(0, 0, it3)
it3.setIcon(QtGui.QIcon("so-logo.png"))
it3.setSizeHint(QtCore.QSize(100, 100))
delegate = Delegate(widget_3)
widget_3.setItemDelegate(delegate)
w = QtWidgets.QWidget()
lay = QtWidgets.QVBoxLayout(w)
lay.addWidget(widget_1)
lay.addWidget(widget_2)
lay.addWidget(widget_3)
w.show()
ret = app.exec_()
return ret
if __name__ == "__main__":
sys.exit(main(sys.argv))
Explanation:
By default the icon size is taken based on the iconSize property.
The QLabel can be added using the setCellWidget() method.
You can use a delegate to set the icon size.

Dynamically Resize QListView Item's Icon

How can I make it so the icon of a QListView's item resizes when i change the slider? It appears to resize the item but not it's icon.
I tried calling both of these, neither of them worked. I would ideally like to not call setGridSize since that causes the widget to ignore the setSpacing(5) which i intend on using.
self.uiListView.setGridSize(iconSize)
self.uiListView.setIconSize(iconSize)
import os, sys, re
from Qt import QtWidgets, QtGui, QtCore
from . import StyleUtils
values = ['MomBod','Colonel','Tater','Tot','Ginger','Donut','Sport','LaLa','Itchy','Bruiser','Cotton','Cumulus','Toodles','Salt','Ghoulie','Cat','Dirty','Harry','Buckeye','Flyby','Swiss','Miss','Buddy','Pecan','Sunny','Jet','Thor','Gingersnap','Cuddle','Pig','Turkey','Foxy','Mini','Me','Dolly','Stud','Music','Man','Barbie','Munchkin','Bubba','Hammer','Twizzler','Bebe']
class ViewerWidget(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.resize(500,500)
self.uiIconSize = QtWidgets.QSlider(QtCore.Qt.Horizontal)
self.uiIconSize.setRange(32,256)
self.uiIconSize.setValue(128)
self.uiIconSize.setMinimumWidth(100)
self.viewerModel = QtGui.QStandardItemModel()
self.viewerProxyModel = QtCore.QSortFilterProxyModel()
self.viewerProxyModel.setSourceModel(self.viewerModel)
self.uiListView = QtWidgets.QListView()
self.uiListView.setSpacing(5)
self.uiListView.setMovement(QtWidgets.QListView.Static)
self.uiListView.setViewMode(QtWidgets.QListView.IconMode)
self.uiListView.setLayoutMode(QtWidgets.QListView.Batched)
self.uiListView.setBatchSize(100)
self.uiListView.setFlow(QtWidgets.QListView.LeftToRight)
self.uiListView.setWrapping(True)
self.uiListView.setResizeMode(QtWidgets.QListView.Adjust)
self.uiListView.setDragEnabled(False)
self.uiListView.setUniformItemSizes(True)
self.uiListView.setIconSize(self.getIconSize())
self.uiListView.setSelectionMode(QtWidgets.QListView.ExtendedSelection)
self.uiListView.setModel(self.viewerProxyModel)
# main layout
self.layout = QtWidgets.QVBoxLayout()
self.layout.setContentsMargins(0,0,0,0)
self.layout.setSpacing(0)
self.layout.addWidget(self.uiListView)
self.layout.addWidget(self.uiIconSize)
self.setLayout(self.layout)
# Signals
self.uiIconSize.valueChanged.connect(self.setItemSize)
# Init
self.populateModel()
def getIconSize(self):
return QtCore.QSize(self.uiIconSize.value(), self.uiIconSize.value())
def setItemSize(self):
iconSize = self.getIconSize()
# self.uiListView.setGridSize(iconSize)
self.uiListView.setIconSize(iconSize)
def populateModel(self):
model = self.viewerModel
model.clear()
icon = QtGui.QIcon('C:/Users/jmartini/Desktop/image.png')
for x in values:
newItem = QtGui.QStandardItem(x)
newItem.setData(icon, role=QtCore.Qt.DecorationRole)
model.appendRow(newItem)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = ViewerWidget()
ex.show()
sys.exit(app.exec_())
I discovered this is a result of my icon's native size being 64x64. Qt will not resize the icon to be larger than it's original size. It will only resize the icon to be of a smaller size.
self.uiListView.setIconSize(QtCore.QSize(64,64))

Categories