I am using PyQt5 and using PyCharm. How can I align all cells under one column to center? The code below seems to be working but for only one cell which is the header. What should I change or add?
item3 = QtWidgets.QTableWidgetItem('Item Name')
item3.setTextAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignVCenter)
self.tableWidget.setHorizontalHeaderItem(2, item3)
A simple way to establish the alignment of a column is through the delegates:
import sys
from PyQt5 import QtCore, QtWidgets
class AlignDelegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super(AlignDelegate, self).initStyleOption(option, index)
option.displayAlignment = QtCore.Qt.AlignCenter
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.tableWidget = QtWidgets.QTableWidget(15, 6)
self.setCentralWidget(self.tableWidget)
for i in range(self.tableWidget.rowCount()):
for j in range(self.tableWidget.columnCount()):
it = QtWidgets.QTableWidgetItem("{}-{}".format(i, j))
self.tableWidget.setItem(i, j, it)
delegate = AlignDelegate(self.tableWidget)
self.tableWidget.setItemDelegateForColumn(2, delegate)
# for all columns:
# self.tableWidget.setItemDelegate(delegate)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
Related
I have a Tab Widget with 2 Tabs. How can I get the index number of a Tab when I click on it?
self.tab = QTabWidget()
self.tab.addTab(self.widget1, "Tab1")
self.tab.addTab(self.widget2, "Tab2")
data_entry_tab.tabBarClicked.connect(self.OnTabClicked)
def OnTabClicked(self):
tab_bar = self.sender()
# I want to use idx to do some calculation
idx = ?
You can use the tabBarClicked signal:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.tabwidget = QtWidgets.QTabWidget()
self.tabwidget.addTab(QtWidgets.QWidget(), "Tab1")
self.tabwidget.addTab(QtWidgets.QWidget(), "Tab2")
self.tabwidget.addTab(QtWidgets.QWidget(), "Tab3")
self.setCentralWidget(self.tabwidget)
self.tabwidget.tabBarClicked.connect(self.handle_tabbar_clicked)
def handle_tabbar_clicked(self, index):
print(index)
print("x2:", index * 2)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
whatever you have your Qtabwidget set up as, like lets say. tabs = QTabWidget(), for instance. then you would use tabs.currentIndex() to find the index of the tab that is currently open. so then you can be like current_index = tabs.currentIndex(), and use the index for whatever it is you were needing it for.
I have a Qlistview with some items. I want to set selection at first item at startup of window. selectionModel().selectedRows() returns the selectet item. But
QAbstractItemModel().setCurrentIndex(0) does't select the item. How could that be done like setSelection(INDEX).
self.listView = QtWidgets.QListView()
self.entry = QtGui.QStandardItemModel()
self.listView.setModel(self.entry)
----------
self.listView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.listView.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
self.listView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
----------
self.listView.QAbstractItemModel().setCurrentIndex(0) #<------ Not really working
selection = self.listView.selectionModel().selectedRows()
print(selection)
If you want to select an item then you must use the select() method of selectionModel():
from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.listView = QtWidgets.QListView(
editTriggers=QtWidgets.QAbstractItemView.NoEditTriggers,
selectionMode=QtWidgets.QAbstractItemView.SingleSelection,
selectionBehavior=QtWidgets.QAbstractItemView.SelectRows,
)
self.entry = QtGui.QStandardItemModel()
self.listView.setModel(self.entry)
for letter in list("abcdefghijklmnopqrstuvwxyz"):
it = QtGui.QStandardItem(letter)
self.entry.appendRow(it)
ix = self.entry.index(0, 0)
sm = self.listView.selectionModel()
sm.select(ix, QtCore.QItemSelectionModel.Select)
self.setCentralWidget(self.listView)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
I have embedded a QPushbutton in a Qwidget in a QListView:
QPushbutton >> QWidget >> QListView
list_widget = QWidget()
list_widget.layout(QHBoxLayout())
btn = QPushButton()
btn.pressed.connect(clicked)
list_widget.layout().addWidget(QPushButton())
list_view.setIndexWidget(self.list_model.index(row, 0), list_widget)
def clicked():
row = list_view.selectedIndexes()
The problem is now list_view.selectedIndexes() does not return the row of the pressed button, when pressed.
This seems to work only when the QPushbutton is embedded in the QListView directly: QPushbutton >> QListView.
Does anyone have an idea how to delegate the focus of the pushbutton to the QListView?
When you click on the button it is not transmitted to the QListView because the button consumes it and does not transmit it to other widgets so if you want to obtain the row it must be obtained indirectly, a possible solution is to use the geometry for it you must obtain the sender , in this case the button, and then for its topleft to global positions, then convert it to a local position with respect to the viewport of QListView, using that position with the method indexAt() you get the QModelIndex.
from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.list_model = QtGui.QStandardItemModel(200, 1)
self.list_view = QtWidgets.QListView()
self.list_view.setModel(self.list_model)
self.setCentralWidget(self.list_view)
for row in range(self.list_model.rowCount()):
list_widget = QtWidgets.QWidget()
hlay = QtWidgets.QHBoxLayout(list_widget)
btn = QtWidgets.QPushButton(str(row))
btn.pressed.connect(self.clicked)
hlay.addWidget(btn)
hlay.setContentsMargins(0, 0, 0, 0)
self.list_view.setIndexWidget(self.list_model.index(row, 0), list_widget)
#QtCore.pyqtSlot()
def clicked(self):
btn = self.sender()
gp = btn.mapToGlobal(QtCore.QPoint())
lp = self.list_view.viewport().mapFromGlobal(gp)
ix = self.list_view.indexAt(lp)
print("row", ix.row())
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Another much simpler way is to pass the row as an argument using functools.partial():
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.list_model = QtGui.QStandardItemModel(200, 1)
self.list_view = QtWidgets.QListView()
self.list_view.setModel(self.list_model)
self.setCentralWidget(self.list_view)
for row in range(self.list_model.rowCount()):
list_widget = QtWidgets.QWidget()
hlay = QtWidgets.QHBoxLayout(list_widget)
btn = QtWidgets.QPushButton(str(row))
btn.pressed.connect(partial(self.clicked, row))
hlay.addWidget(btn)
hlay.setContentsMargins(0, 0, 0, 0)
self.list_view.setIndexWidget(self.list_model.index(row, 0), list_widget)
#QtCore.pyqtSlot(int)
def clicked(self, row):
print(row)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Or using a lambda method:
from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.list_model = QtGui.QStandardItemModel(200, 1)
self.list_view = QtWidgets.QListView()
self.list_view.setModel(self.list_model)
self.setCentralWidget(self.list_view)
for row in range(self.list_model.rowCount()):
list_widget = QtWidgets.QWidget()
hlay = QtWidgets.QHBoxLayout(list_widget)
btn = QtWidgets.QPushButton(str(row))
btn.pressed.connect(lambda *args, row=row: self.clicked(row))
hlay.addWidget(btn)
hlay.setContentsMargins(0, 0, 0, 0)
self.list_view.setIndexWidget(self.list_model.index(row, 0), list_widget)
#QtCore.pyqtSlot(int)
def clicked(self, row):
print(row)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
In my case I prefer to use partials since you do not need to write a lot of logic and it's thread-safe.
I have a two-dimensional QTreeWidget, how can I get an Item by clicking on it? I use PyQt5. I have this part of the code, but it gets only the first item of the selected row (or any other by changing the baseNode.text(#))
...
self.treeWidget.itemSelectionChanged.connect(lambda: loadAllMessages())
def loadAllMessages():
getSelected = self.treeWidget.selectedItems()
if getSelected:
baseNode = getSelected[0]
getChildNode = baseNode.text(0)
print(getChildNode)
...
You just have to use the itemClicked signal sent by the QTreeWidgetItem and the clicked column:
Example:
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
lay = QtWidgets.QVBoxLayout(self)
tree = QtWidgets.QTreeWidget()
tree.setColumnCount(2)
lay.addWidget(tree)
for i in range(4):
parent_it = QtWidgets.QTreeWidgetItem(["{}-{}".format(i, l) for l in range(2)])
tree.addTopLevelItem(parent_it)
for j in range(5):
it = QtWidgets.QTreeWidgetItem(["{}-{}-{}".format(i, j, l) for l in range(2)])
parent_it.addChild(it)
tree.expandAll()
tree.itemClicked.connect(self.onItemClicked)
#QtCore.pyqtSlot(QtWidgets.QTreeWidgetItem, int)
def onItemClicked(self, it, col):
print(it, col, it.text(col))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Here's my code. I'm trying to make it such that as you change the dropdown box, it will dynamically show more or less QLineEdits for input. This is just the latest iteration of testing
import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit,
QInputDialog, QApplication, QComboBox, QFrame)
import numpy as np
class GUI(QWidget):
def __init__(self):
super().__init__()
self.initgui()
def initgui(self):
#
# Set up GUI
#
self.setGeometry(100, 100, 400, 400)
self.move(300, 300)
combobox = QComboBox(self)
for i in range(1, 10, 1):
combobox.addItem(str(i + 1))
combobox.activated[str].connect(self.comboboxchanged)
self.setWindowTitle("Testing Easy Setup")
self.show()
def comboboxchanged(self, text):
frame = QWidget(self)
frame.hide()
for num in range(0, int(text), 1):
QLineEdit(frame).move(60, num * 19)
frame.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = GUI()
sys.exit(app.exec_())
The problem is that when you pass a parent to a widget it is placed in the 0, 0 position with respect to the parent, in your case QFrame is on top of QComboBox since both are in the 0, 0 position. The proper thing is to use layouts. On the other hand you have to eliminate the widgets before adding new ones for it, we create a function that eliminates those items.
import sys
from PyQt5.QtWidgets import *
def clearLayout(lay):
while lay.count() > 0:
item = lay.takeAt(0)
widget = item.widget()
if widget:
widget.deleteLater()
del item
class GUI(QWidget):
def __init__(self):
super().__init__()
self.initgui()
def initgui(self):
lay = QHBoxLayout(self)
vlay1 = QVBoxLayout()
combobox = QComboBox(self)
combobox.addItems([str(i) for i in range(2, 11)])
vlay1.addWidget(combobox)
vlay1.addItem(QSpacerItem(20, 245, QSizePolicy.Minimum, QSizePolicy.Expanding))
self.vlay2 = QVBoxLayout()
lay.addLayout(vlay1)
lay.addLayout(self.vlay2)
self.comboboxchanged(combobox.currentText())
combobox.activated[str].connect(self.comboboxchanged)
self.setWindowTitle("Testing Easy Setup")
self.show()
def comboboxchanged(self, text):
clearLayout(self.vlay2)
for num in range(0, int(text)):
self.vlay2.addWidget(QLineEdit(self))
self.vlay2.addItem(QSpacerItem(20, 245, QSizePolicy.Minimum, QSizePolicy.Expanding))
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = GUI()
sys.exit(app.exec_())