Can a checkable Qstandard item be centered within a QStandardItemModel column? - python

I have a table class with a column of check boxes. I'd like to center these within the column but using item.setTextAlignment(Qt.AlignCenter) doesn't work.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import (QDate, QDateTime, QRegExp, QSortFilterProxyModel, Qt,
QTime, QModelIndex, QSize, pyqtSignal, QObject)
from PyQt5.QtGui import QStandardItemModel, QIcon, QStandardItem
class Table(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.initUI()
self.show()
def initUI(self):
mainLayout = QVBoxLayout()
self.proxyModel = QSortFilterProxyModel()
self.proxyModel.setDynamicSortFilter(True)
self.sourceModel = QStandardItemModel(0, 2, self)
self.sourceModel.setHeaderData(0, Qt.Horizontal, '')
self.sourceModel.setHeaderData(1, Qt.Horizontal, 'Value')
self.proxyModel.setSourceModel(self.sourceModel)
self.proxyGroupBox = QGroupBox('data')
self.proxyView = QTreeView()
self.proxyView.setRootIsDecorated(False)
self.proxyView.setAlternatingRowColors(True)
self.proxyView.setModel(self.proxyModel)
self.proxyView.setEditTriggers(QAbstractItemView.NoEditTriggers)
proxyLayout = QGridLayout()
proxyLayout.addWidget(self.proxyView, 0, 0, 1, 3)
self.proxyGroupBox.setLayout(proxyLayout)
mainLayout.addWidget(self.proxyGroupBox)
self.setLayout(mainLayout)
for i in range(5):
self.proxyView.resizeColumnToContents(0)
item = QStandardItem(True)
item.setCheckable(True)
item.setCheckState(False)
#item.setTextAlignment(Qt.AlignCenter)
self.sourceModel.setItem(i, 0, item)
self.sourceModel.setData(self.sourceModel.index(i, 1), i+1)
def setSourceModel(self, model):
self.proxyModel.setSourceModel(model)
if __name__=='__main__':
import sys
app = QApplication(sys.argv)
window = Table()
sys.exit(app.exec_())
Is there anyway to center each item of the first column?

If you want to change the alignment of the checkbox then you must use a QProxyStyle:
class CheckBoxProxyStyle(QProxyStyle):
def subElementRect(self, element, option, widget):
rect = super().subElementRect(element, option, widget)
if element == QStyle.SE_ItemViewItemCheckIndicator:
rect.moveCenter(option.rect.center())
return rect
self.proxyView = QTreeView()
self.proxyView.setStyle(CheckBoxProxyStyle(self.proxyView.style()))

Related

PySide2 AutoComplete: Customize the Result

I am using QCompleter to implement auto-completion on a QLineEdit widget:
from PySide2 import QtGui
from PySide2.QtCore import Qt
from PySide2.QtGui import QStandardItem
from PySide2.QtWidgets import QCompleter, QWidget, QLineEdit, QFormLayout, QApplication
class SuggestionPlaceModel(QtGui.QStandardItemModel):
def __init__(self, parent=None):
super(SuggestionPlaceModel, self).__init__(parent)
def search(self, text):
self.clear()
data = [{'text': f"{text} {i}"} for i in range(10)]
for i, row in enumerate(data):
item = QStandardItem(row['text'])
self.appendRow(item)
class Completer(QCompleter):
def splitPath(self, path):
self.model().search(path)
return super(Completer, self).splitPath(path)
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self._model = SuggestionPlaceModel(self)
completer = Completer(self)
completer.setCaseSensitivity(Qt.CaseInsensitive)
completer.setModel(self._model)
lineedit = QLineEdit()
lineedit.setCompleter(completer)
lay = QFormLayout(self)
lay.addRow("Location: ", lineedit)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Here is a result:
QUESTION: How can I customize the SuggestionPlaceModel class so that the search result can include icons, horizontal separaters, different fonts, different font sizes, etc like this?
A possible solution is to use a custom delegate where the icon is set, in the case of html you can use a QLabel that supports rich text.
import random
from PySide2 import QtCore, QtGui, QtWidgets
class Delegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super(Delegate, self).initStyleOption(option, index)
option.text = ""
def paint(self, painter, option, index):
if isinstance(option.widget, QtWidgets.QAbstractItemView):
option.widget.openPersistentEditor(index)
super(Delegate, self).paint(painter, option, index)
def createEditor(self, parent, option, index):
editor = QtWidgets.QLabel(index.data(), parent)
editor.setContentsMargins(0, 0, 0, 0)
editor.setText(index.data(QtCore.Qt.UserRole))
return editor
class SuggestionPlaceModel(QtGui.QStandardItemModel):
def search(self, text):
self.clear()
for i in range(10):
html = f"{text}-{i} <b>Stack</b> <i>Overflow</i>"
plain = QtGui.QTextDocumentFragment.fromHtml(html).toPlainText()
pixmap = QtGui.QPixmap(128, 128)
pixmap.fill(QtGui.QColor(*random.sample(range(255), 4)))
item = QtGui.QStandardItem(plain)
item.setData(html, QtCore.Qt.UserRole)
item.setIcon(QtGui.QIcon(pixmap))
self.appendRow(item)
class Completer(QtWidgets.QCompleter):
def splitPath(self, path):
self.model().search(path)
return super(Completer, self).splitPath(path)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self._model = SuggestionPlaceModel(self)
completer = Completer(self)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
completer.setModel(self._model)
delegate = Delegate(completer.popup())
completer.popup().setItemDelegate(delegate)
lineedit = QtWidgets.QLineEdit()
lineedit.setCompleter(completer)
lay = QtWidgets.QFormLayout(self)
lay.addRow("Location: ", lineedit)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

PyQt5 "Ghost" of QIcon appears in QLineEdit of a QComboBox

I have a QComboBox and I want each item to have its own QIcon, but the QIcon should only be visible in the dropdown. I took an answer from a previous question and it works pretty well:
As you can see, the Icon only appears in the dropdown. The problem arises when I set the QComboBox to be editable and this happens:
Here a "ghost" of the QIcon is still there which in turn displaces the text.
My question is: What causes this and how can I remove this "ghost" so that the text appears normally?
My code:
from PyQt5.QtWidgets import (
QApplication,
QComboBox,
QHBoxLayout,
QStyle,
QStyleOptionComboBox,
QStylePainter,
QWidget,
)
from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtCore import QSize
class EditCombo(QComboBox):
def __init__(self, parent=None):
super(EditCombo, self).__init__(parent)
self.editable_index = 99
self.currentIndexChanged.connect(self.set_editable)
def setEditableAfterIndex(self, index):
self.editable_index = index
def set_editable(self, index: int) -> None:
if index >= self.editable_index:
self.setEditable(True)
else:
self.setEditable(False)
self.update()
def paintEvent(self, event):
painter = QStylePainter(self)
painter.setPen(self.palette().color(QPalette.Text))
opt = QStyleOptionComboBox()
self.initStyleOption(opt)
opt.currentIcon = QIcon()
opt.iconSize = QSize()
painter.drawComplexControl(QStyle.CC_ComboBox, opt)
painter.drawControl(QStyle.CE_ComboBoxLabel, opt)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout()
edit_ico = QIcon("edit.png")
empty_ico = QIcon("empty.png") # For margin
combo = EditCombo(self)
combo.setEditableAfterIndex(2)
combo.addItem(empty_ico, "Foo 1")
combo.addItem(edit_ico, "Foo 2")
combo.addItem(edit_ico, "Bar 1")
combo.addItem(edit_ico, "Bar 2")
hbox.addWidget(combo)
self.setLayout(hbox)
self.show()
def main():
import sys
app = QApplication(sys.argv)
ex = Example()
ex.setFixedWidth(300)
sys.exit(app.exec_())
if __name__ == "__main__":
main()
QComboBox also uses the icon to set the position of the QLineEdit that is used when the QComboBox is editable so you see that displacement, if you don't want to observe that then you have to recalculate the geometry. The following code does it through a QProxyStyle:
class ProxyStyle(QProxyStyle):
def subControlRect(self, control, option, subControl, widget=None):
r = super().subControlRect(control, option, subControl, widget)
if control == QStyle.CC_ComboBox and subControl == QStyle.SC_ComboBoxEditField:
if widget.isEditable():
widget.lineEdit().setGeometry(r)
return r
class EditCombo(QComboBox):
def __init__(self, parent=None):
super(EditCombo, self).__init__(parent)
self._style = ProxyStyle(self.style())
self.setStyle(self._style)
self.editable_index = 99
self.currentIndexChanged.connect(self.set_editable)
# ...

How can I generate the buttons and connect them to different functions? [duplicate]

This question already has answers here:
How do I assert the identity of a PyQt5 signal?
(2 answers)
Closed 2 years ago.
I've created a search engine in PyQt5, using the code below:
import sys
from PyQt5.QtWidgets import (
QWidget, QLineEdit, QLabel, QScrollArea, QMainWindow,
QApplication, QHBoxLayout, QVBoxLayout, QSpacerItem, QSizePolicy, QCompleter, QPushButton
)
from PyQt5 import QtCore
from PyQt5.QtCore import Qt
tlist = ['thing1', 'thing2', 'thing3', 'thing4']
class Label(QWidget):
def __init__(self, name):
super(Label, self).__init__()
self.name = name
self.lbl = QLabel(self.name)
self.lbl.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.btn = QPushButton("Preview")
self.btn.setMaximumSize(QtCore.QSize(100,100))
self.btn.clicked.connect(self.printsignal)
self.hbox = QHBoxLayout()
self.hbox.addWidget(self.lbl)
self.hbox.addWidget(self.btn)
self.setLayout(self.hbox)
def show(self):
for labels in [self, self.lbl]:
labels.setVisible(True)
def hide(self):
for labels in [self, self.lbl]:
labels.setVisible(False)
def printsignal(self):
print("clicked")
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__()
self.controls = QWidget()
self.controlsLayout = QVBoxLayout()
self.widgets = []
for name in tlist:
item = Label(name)
self.controlsLayout.addWidget(item)
self.widgets.append(item)
spacer = QSpacerItem(1, 1, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.controlsLayout.addItem(spacer)
self.controls.setLayout(self.controlsLayout)
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.controls)
self.searchbar = QLineEdit()
self.searchbar.textChanged.connect(self.update_display)
self.completer = QCompleter(tlist)
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.searchbar.setCompleter(self.completer)
container = QWidget()
containerLayout = QVBoxLayout()
containerLayout.addWidget(self.searchbar)
containerLayout.addWidget(self.scroll)
container.setLayout(containerLayout)
self.setCentralWidget(container)
self.setGeometry(600, 100, 800, 600)
self.setWindowTitle('Search Engine')
def update_display(self, text):
for widget in self.widgets:
if text.lower() in widget.name.lower():
widget.show()
else:
widget.hide()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
The problem I have is, all the buttons share the same function and I don't know how to make them have different signals, as they are generated automatically. Basically, if I run the code it will show up like
this:
and when I press any of the buttons, it will print "clicked" (as in printsignal function). What I want is a different function for each button. Is there a way to do that?
Normally you can use self.sender().text() to get text from QButton which generated signal.
But because you create own widget Label with QButton and QLabel and you want text from label so you can get directly self.name
def printsignal(self):
print("clicked", self.name)
eventually self.lbl.text()
def printsignal(self):
print("clicked", self.lbl.text())
Working code.
I removed show(), hide() because you don't need it
import sys
from PyQt5.QtWidgets import (
QWidget, QLineEdit, QLabel, QScrollArea, QMainWindow,
QApplication, QHBoxLayout, QVBoxLayout, QSpacerItem, QSizePolicy, QCompleter, QPushButton
)
from PyQt5 import QtCore
from PyQt5.QtCore import Qt
tlist = ['thing1', 'thing2', 'thing3', 'thing4']
class Label(QWidget):
def __init__(self, name):
super().__init__()
self.name = name
self.lbl = QLabel(self.name)
self.lbl.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.btn = QPushButton("Preview")
self.btn.setMaximumSize(QtCore.QSize(100,100))
self.btn.clicked.connect(self.printsignal)
self.hbox = QHBoxLayout()
self.hbox.addWidget(self.lbl)
self.hbox.addWidget(self.btn)
self.setLayout(self.hbox)
def printsignal(self):
print("clicked", self.name)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__()
self.controls = QWidget()
self.controlsLayout = QVBoxLayout()
self.widgets = []
for name in tlist:
item = Label(name)
self.controlsLayout.addWidget(item)
self.widgets.append(item)
spacer = QSpacerItem(1, 1, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.controlsLayout.addItem(spacer)
self.controls.setLayout(self.controlsLayout)
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.controls)
self.searchbar = QLineEdit()
self.searchbar.textChanged.connect(self.update_display)
self.completer = QCompleter(tlist)
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.searchbar.setCompleter(self.completer)
container = QWidget()
containerLayout = QVBoxLayout()
containerLayout.addWidget(self.searchbar)
containerLayout.addWidget(self.scroll)
container.setLayout(containerLayout)
self.setCentralWidget(container)
self.setGeometry(600, 100, 800, 600)
self.setWindowTitle('Search Engine')
def update_display(self, text):
for widget in self.widgets:
if text.lower() in widget.name.lower():
widget.show()
else:
widget.hide()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

swipe to check/uncheck in QListWidget

I would like to set a QListWidget in PyQt5 to check or uncheck the check boxes when I swipe.
Here is my interface:
And my code:
import sys
from PyQt5.QtCore import QDate, QSize, Qt
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class VerifyDialog(QDialog):
def __init__(self, parent=None):
super(VerifyDialog, self).__init__(parent)
self.listWidget = QListWidget()
for i in range(100):
item = QListWidgetItem("Item %i" % i)
# could be Qt.Unchecked; setting it makes the check appear
item.setCheckState(Qt.Checked)
self.listWidget.addItem(item)
runButton = QPushButton("Run")
runButton.clicked.connect(self.exec)
cancelButton = QPushButton("Cancel")
cancelButton.clicked.connect(self.close)
horizontalLayout = QHBoxLayout()
horizontalLayout.addWidget(self.listWidget, 1)
buttonsLayout = QHBoxLayout()
buttonsLayout.addStretch(1)
buttonsLayout.addWidget(runButton)
buttonsLayout.addWidget(cancelButton)
mainLayout = QVBoxLayout()
mainLayout.addLayout(horizontalLayout)
mainLayout.addSpacing(12)
mainLayout.addLayout(buttonsLayout)
self.setLayout(mainLayout)
self.setWindowTitle("Config Dialog")
self.show()
if __name__=="__main__":
app = QApplication(sys.argv)
dialog = VerifyDialog()
sys.exit(app.exec_())
I want to click on Item 4 and have it uncheck (it's easier than clicking the box), and then I want to drag down and have lots of other items uncheck.
You must use the itemEntered signal that sends you the object under the mouse.
self.listWidget.itemEntered.connect(lambda item: item.setCheckState(Qt.Checked if item.checkState()==Qt.Unchecked else Qt.Unchecked))
Complete code:
import sys
from PyQt5.QtCore import QDate, QSize, Qt
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class VerifyDialog(QDialog):
def __init__(self, parent=None):
super(VerifyDialog, self).__init__(parent)
self.listWidget = QListWidget()
self.listWidget.itemEntered.connect(lambda item: item.setCheckState(Qt.Checked if item.checkState()==Qt.Unchecked else Qt.Unchecked))
for i in range(100):
item = QListWidgetItem("Item %i" % i)
# could be Qt.Unchecked; setting it makes the check appear
item.setCheckState(Qt.Checked)
self.listWidget.addItem(item)
runButton = QPushButton("Run")
runButton.clicked.connect(self.exec)
cancelButton = QPushButton("Cancel")
cancelButton.clicked.connect(self.close)
horizontalLayout = QHBoxLayout()
horizontalLayout.addWidget(self.listWidget, 1)
buttonsLayout = QHBoxLayout()
buttonsLayout.addStretch(1)
buttonsLayout.addWidget(runButton)
buttonsLayout.addWidget(cancelButton)
mainLayout = QVBoxLayout()
mainLayout.addLayout(horizontalLayout)
mainLayout.addSpacing(12)
mainLayout.addLayout(buttonsLayout)
self.setLayout(mainLayout)
self.setWindowTitle("Config Dialog")
self.show()
if __name__=="__main__":
app = QApplication(sys.argv)
dialog = VerifyDialog()
sys.exit(app.exec_())

How to align widgets contained on several HBoxLayouts?

Let's consider this little snippet:
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItem
from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QTreeView
from PyQt5.QtWidgets import QWidget
class PropertiesWidget(QTreeView):
def __init__(self, columns, *args, **kwargs):
super(PropertiesWidget, self).__init__(*args, **kwargs)
self.model = QStandardItemModel(self)
self.setModel(self.model)
self.model.setColumnCount(columns)
self.model.setHeaderData(0, Qt.Horizontal, "Property")
self.model.setHeaderData(1, Qt.Horizontal, "Value")
self.setFocusPolicy(Qt.NoFocus)
self.last_item = 0
self.last_item = QStandardItem()
self.parameters = {}
def begin_group(self, name, key):
root = QStandardItem(name)
root.setEditable(False)
if not key:
root.setData(key)
self.model.appendRow([root])
self.last_item = root
def end_group(self):
if (self.last_item and self.last_item.parent()):
self.last_item = self.last_item.parent()
def append_row(self, text, widget):
if not self.last_item:
return
if text in self.parameters:
raise Exception("Not allowed duplicate keys {0}".format(text))
item = self.last_item
child = QStandardItem(text)
child2 = QStandardItem()
child.setEditable(False)
item.appendRow([child, child2])
if widget:
self.setIndexWidget(child2.index(), widget)
self.expand(child.index().parent())
def add_vec2(self, key, value):
x = QLineEdit(value, self)
y = QLineEdit(value, self)
lbl = QLabel('')
lbl.setMinimumWidth(0)
lbl2 = QLabel('')
lbl2.setMinimumWidth(0)
layout = QHBoxLayout(self)
layout.addWidget(x, stretch=1)
layout.addWidget(y, stretch=1)
layout.addWidget(lbl, stretch=1)
layout.addWidget(lbl2, stretch=1)
layout.setContentsMargins(0, 0, 0, 0)
widget = QWidget(self)
widget.setLayout(layout)
setattr(widget, "operator_key", key)
self.append_row(key, widget)
def add_vec3(self, key, value):
x = QLineEdit(value, self)
y = QLineEdit(value, self)
z = QLineEdit(value, self)
lbl = QLabel('')
lbl.setMinimumWidth(0)
layout = QHBoxLayout(self)
layout.addWidget(x, stretch=1)
layout.addWidget(y, stretch=1)
layout.addWidget(z, stretch=1)
layout.addWidget(lbl, stretch=1)
layout.setContentsMargins(0, 0, 0, 0)
widget = QWidget(self)
widget.setLayout(layout)
setattr(widget, "operator_key", key)
self.append_row(key, widget)
def add_vec4(self, key, value):
x = QLineEdit(value, self)
y = QLineEdit(value, self)
z = QLineEdit(value, self)
w = QLineEdit(value, self)
layout = QHBoxLayout(self)
layout.addWidget(x, stretch=1)
layout.addWidget(y, stretch=1)
layout.addWidget(z, stretch=1)
layout.addWidget(w, stretch=1)
layout.setContentsMargins(0, 0, 0, 0)
widget = QWidget(self)
widget.setLayout(layout)
setattr(widget, "operator_key", key)
self.append_row(key, widget)
def main():
app = QtWidgets.QApplication(sys.argv)
ex = PropertiesWidget(2)
ex.begin_group("foo", "foo")
ex.add_vec2("vec2", "vec2_value")
ex.add_vec3("vec3", "vec3_value")
ex.add_vec4("vec4", "vec4_value")
ex.end_group()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
If i run it and i extend the widget we'll see all the lineedits are aligned properly on each row:
But if i shrink it the widgets will be misaligned with different sizes, like this:
How can i guarantee no matter how you've resized the widget all the lineedits will have the same size and they will be aligned each other? I've already tried using setMinimumWidth(100) but that won't do it.
#Avaris from #pyqt (freenode) channel gave me the solution I was looking for, the main trick was using properly the QSizePolicy on the QLineEdits and empty QLabels, something like this setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Expanding) will do the trick. For a full working example, here's a little snippet:
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItem
from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QTreeView
from PyQt5.QtWidgets import QWidget
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QSizePolicy
class VecParameter(QWidget):
value_changed = pyqtSignal(object)
def __init__(self, value, num_components, max_columns=4, parent=None, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.components = []
if num_components > max_columns:
num_components = max_columns
layout = QHBoxLayout(self)
for i in range(num_components):
c = QLineEdit(str(value[i]), self)
c.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Expanding)
self.components.append(c)
layout.addWidget(c, stretch=1)
for i in range(num_components, max_columns):
lbl = QLabel('')
lbl.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Expanding)
layout.addWidget(lbl, stretch=1)
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
class PropertiesWidget(QTreeView):
def __init__(self, columns, *args, **kwargs):
super(PropertiesWidget, self).__init__(*args, **kwargs)
self.model = QStandardItemModel(self)
self.setModel(self.model)
self.model.setColumnCount(columns)
self.model.setHeaderData(0, Qt.Horizontal, "Property")
self.model.setHeaderData(1, Qt.Horizontal, "Value")
self.setFocusPolicy(Qt.NoFocus)
self.last_item = 0
self.last_item = QStandardItem()
self.parameters = {}
def begin_group(self, name, key):
root = QStandardItem(name)
root.setEditable(False)
if not key:
root.setData(key)
self.model.appendRow([root])
self.last_item = root
def end_group(self):
if (self.last_item and self.last_item.parent()):
self.last_item = self.last_item.parent()
def append_row(self, text, widget):
if not self.last_item:
return
if text in self.parameters:
raise Exception("Not allowed duplicate keys {0}".format(text))
item = self.last_item
child = QStandardItem(text)
child2 = QStandardItem()
child.setEditable(False)
item.appendRow([child, child2])
if widget:
self.setIndexWidget(child2.index(), widget)
self.expand(child.index().parent())
def add_vec1(self, key, value=[0]):
widget = VecParameter(value, 1, parent=self)
self.append_row(key, widget)
def add_vec2(self, key, value=[0, 0]):
widget = VecParameter(value, 2, parent=self)
self.append_row(key, widget)
def add_vec3(self, key, value=[0, 0, 0]):
widget = VecParameter(value, 3, parent=self)
self.append_row(key, widget)
def add_vec4(self, key, value=[0, 0, 0, 0]):
widget = VecParameter(value, 4, parent=self)
self.append_row(key, widget)
def main():
app = QtWidgets.QApplication(sys.argv)
ex = PropertiesWidget(2)
ex.begin_group("foo", "foo")
ex.add_vec1("vec1", [1])
ex.add_vec2("vec2", [1, 2])
ex.add_vec3("vec3", [1, 2, 3])
ex.add_vec4("vec4", [1, 2, 3, 4])
ex.end_group()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Actualy your layouts does not have the same amount of items. Thats why. Every "line" you have must have the same lenght but with different amount of items. so when you are making it smaller, the space is divided with the items inside.
For a quick workaround your can try to add "invisible" items like spacers to your layouts, so the sum of the items in each line can be the same
You could use Tkinter to do this. It is much simpler and will keep everything aligned with its grid feature! (Just be sure to set the x offset for each box!)
Import tkinter
root = tk.Tk() # Some versions of python throw tantrums when you don't do this
root.geometry(...) #Like so: root.geometry("400x400")
#to make this easy I'll only do one box.
"""
The grid feature of tkinter allows you to grid-align boxes to a page.
By just simply asking if root.geometry is less than ... then realign to a new grid.
"""
Entry = tkinter.Entry(root, background = "...") #Use Entry.get() feature to gather what's been written as a value called ans if u want to do this.
#More entries down here.....
Entry.grid(row = 2, column = 2) #Edit row and column for where to grid it.
root.mainloop() # Required by tkinter in order to run.

Categories